Skip to main content

Web2 API

Info

This API enables you to use our RNG in a Web2 context, like a React backend for example. If you need to call our RNG from a smart contract, use the Web3 API instead.

Introduction

Requesting randomness on Random.win consists of deploying a random draw request onchain.

Once the request is fulfilled and the random numbers are generated, you are automatically notified, and can export these numbers offchain to use them in your app.

1. Get an Ethereum wallet

Skip this step if you already have an Ethereum wallet.

Otherwise, choose one of the available wallets or ask us to create a wallet for you. We personnaly recommend the Rabby wallet which is quite popular and super simple to use.

2. Request randomness

The main benefit of an onchain RNG is to let the users of your app verify your randomness onchain.

This is the purpose of a blockchain explorer such as Arbiscan. Anyone can go to the Arbiscan website, search for our contract address, and verify the random numbers for a particular request.

However, we recognize that this process can seem tedious if your users are not familiar with blockchain. This is why if you prefer, we can generate a user-friendly verification page on our domain verify.win (see example). We can even customize this page with your own company logo and design. Then, the only thing you'll have to do is to share this page's URL with your users.

Learn more about verification.

Choose whether you want a verification page or not, and then proceed to the corresponding step.

info

Make sure to top up your account before making any request otherwise your request will fail.

If you choose Without a verification page, Arbitrum will also charge you about $0.01 worth of ETH on your own wallet for executing the transaction, so make sure your wallet isn't empty. This small fee does not happen if you choose With a verification page because in this case we are making the transaction on your behalf.

Without a verification page

When requesting randomness without a verification page you can directly call our smart contract.

Endpoint

The deployDraw function in our smart contract.

Parameters

  • numbers: The number of random numbers to generate. Maximum is 500. A number cannot be selected more than once, meaning that you have the guarantee that all random numbers will be different.
  • range: The maximum value of a random number. Can be up to 1,000,000. The minimum value of a random number is 1.
  • algorithm: The random draw algorithm to use. Use 0 for Ordered outcomes, 1 for Fisher-Yates, or 2 for Fisher-Yates (GLI-19 certified). If you don't know which one to choose we recommend you to use 0.
  • scheduledAt: The timestamp, in seconds, when the randomness generation will be triggered. It will take 5 more seconds after that for the randomness generation to complete. This parameter enables you to post a request onchain now but generate the randomness at a later date, which can be useful in some cases. Use 0 to ask for randomness immediately.

Response

  • cid: A unique identifier for your random draw. You can communicate this cid to your users for them to verify the random draw onchain. Learn more.

Example Code

Here's how to do it with Viem in a Typescript backend. If you're using a different programming language for your backend, please adapt the code to your language.

Typescript
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts'
import { arbitrum } from 'viem/chains';
import mainContractAbi from './abi'; // See https://docs.random.win/faq#-what-is-an-abi-and-where-can-i-find-it-

const mainContractAddress = "<Our Main contract address>"; // See https://docs.random.win/contracts#main
const privateKey = "<Your Ethereum private key>"; /* This key is private,
NEVER share it with anyone, even us. If someone knows your private key,
he will have access to your funds on your Ethereum wallet AND your funds
on Random.win */
const account = privateKeyToAccount(privateKey);

const publicClient = createPublicClient({
chain: arbitrum,
transport: http()
});

const walletClient = createWalletClient({
account,
chain: arbitrum,
transport: http()
});

const numbers = 5; // We want to get 5 random numbers
const range = 100; // Ranging from 1 to 100 (included)
const algorithm = 0; // The random numbers will be displayed in ascending order
const scheduledAt = 0; // We want to trigger the randomness request now

const { request, result } = await publicClient.simulateContract({
address: mainContractAddress,
abi: mainContractAbi,
functionName: 'deployDraw',
args: [numbers, range, algorithm, scheduledAt],
account
});

/* As a good practice, you should always call `simulateContract` first
to make sure your request is properly made and will be accepted by the blockchain,
and then call `writeContract` to publish the request onchain.
If you don't call `writeContract` your request will never be published
and you won't get any randomness. */
await walletClient.writeContract(request);

const cid = result; // The result is your random draw identifier that we call cid
console.log(`Request ${cid} successfully published onchain. ✅`);

With a verification page

When requesting randomness with a verification page you need to make a POST request to our endpoint with the following parameters.

Endpoint

https://www.random.win/api/draw/deploy

Parameters

  • owner: Your Ethereum address
  • signature (autogenerated): The signature of your Ethereum address. A signature is a cryptographic proof which enables our API to be sure that you are the owner of this Ethereum address. It can be automaticaly generated by Viem, see code example below.
  • title: The title of the page that will be created for your draw
  • rules (optional): Description of the rules of the draw if any.
  • participants: What we call participants are the entities that you want to draw from. It can be either:
    • A list of participants with each participant separated by the delimiter \n, for example "John\nJack\nJoe" or "1\n2\n3\n4\n5\n6\n7\n8\n9". The maximum number of participants is 1,000,000.
    • Alternatively, you can set this parameter to the number of participants without specifying a list of participants, for example "3" instead of "John\nJack\nJoe", or "9" instead of "1\n2\n3\n4\n5\n6\n7\n8\n9".
  • numbers: The number of random numbers that will be generated, that is, the number of participants that will be randomly selected. Maximum is 500. Should be less or equal to the number of participants.
  • scheduledAt: The timestamp, in seconds, when the randomness generation will be triggered. It will take 5 more seconds after that for the randomness generation to complete. This parameter enables you to post a request onchain now but generate the randomness at a later date, which can be useful in some cases. Use 0 to ask for randomness immediately.
  • algorithm (optional): The random draw algorithm to use. Use 0 for Ordered outcomes, 1 for Fisher-Yates, or 2 for Fisher-Yates (GLI-19 certified). If you don't know which one to choose we recommend you to use 0. Default is 0.

Response

  • cid: A unique identifier for your random draw. You can communicate this cid to your users for them to verify the random draw. Learn more.

Example Code

Typescript
import { privateKeyToAccount } from 'viem/accounts'

const ethereumAddress = "<Your Ethereum address>";
const privateKey = "<Your Ethereum private key>"; /* This key is private,
NEVER share it with anyone, even us. If someone knows your private key,
he will have access to your funds on your Ethereum wallet AND your funds
on Random.win */

// Signature
const account = privateKeyToAccount(privateKey);
const signature = await account.signMessage({
message: ethereumAddress
});

// Request parameters
const params = {
owner: ethereumAddress,
signature: signature,
title: "Draw title",
participants: "John\nLara\nHugo",
numbers: 1,
scheduledAt: Math.floor(Date.now() / 1000) + 5*60, // trigger in 5 minutes
};

// Request
fetch("https://www.random.win/api/draw/deploy", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(params)
})
.then(res => res.json())
.then(data => {

// Response
const cid = data.response.cid;

if (cid) {
console.log("Successful deploy:", cid);
// Verification page accessible at https://verify.win/<cid>
}

if (data.error) {
console.error(data.error.message);
}

})
.catch(err => console.error(err));

3. Retrieve the randomness

Random numbers

You can get the random numbers for your request by calling the checkRandomNumbers function with your request cid as parameter. Here's how to do it with Viem.

Typescript
const response = await publicClient.readContract({
address: mainContractAddress,
abi: mainContractAbi,
functionName: 'checkRandomNumbers',
args: [cid]
});

const randomNumbers: number[] = response as number[]; // Convert the response to a number array type
console.log(`The random numbers for request ${cid} are: ${randomNumbers.join(", ")}`);
Show full example

Let's say you need 2 random numbers in order to select 2 winners among 5 participants for a random draw.

Our smart contract will emit an event called DrawCompleted once the randomness for your request has been generated. By listening to this event, you will be notified when your request is completed and will be able to retrieve the random numbers by calling the function checkRandomNumbers. You can also check at any time if your request is completed by calling the function isCompleted.

Here's a full working example of how to do it.

Typescript
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts'
import { arbitrum } from 'viem/chains';
import mainContractAbi from './abi'; // See https://docs.random.win/faq#-what-is-an-abi-and-where-can-i-find-it-

const mainContractAddress = "<Our Main contract address>"; // See https://docs.random.win/contracts#main
const privateKey = "<Your Ethereum private key>";
const account = privateKeyToAccount(privateKey);
const participants = ["John", "Lara", "Jack", "Joe", "Danny"]; // We want to randomly select 2 winners among these participants

// Clients to interact with the blockchain
const publicClient = createPublicClient({
chain: arbitrum,
transport: http()
});

const walletClient = createWalletClient({
account,
chain: arbitrum,
transport: http()
});

const numbers = 2; // We want to get 2 random numbers
const range = participants.length; // Ranging from 1 to 5 (included)
const algorithm = 0; // The random numbers will be displayed in ascending order
const scheduledAt = 0; // We want to trigger the randomness request now

const { request, result } = await publicClient.simulateContract({
address: mainContractAddress,
abi: mainContractAbi,
functionName: 'deployDraw',
args: [numbers, range, algorithm, scheduledAt],
account
});
await walletClient.writeContract(request);

const cid = result; // The result of the transaction is your request CID

// We then wait until the request is completed
// This shouldn't take more than 5 seconds because we set `scheduledAt = 0`
// If we had set `scheduledAt = Math.floor(Date.now() / 1000) + 20` (curent time + 20 seconds) then we would have to wait 25 seconds (20 seconds before triggering the randomness generation + 5 seconds to generate the randomness)
// See https://docs.random.win/faq#%EF%B8%8F-how-fast-is-the-randomness-generation- for more info
const unwatch = publicClient.watchContractEvent({
address: mainContractAddress,
abi: mainContractAbi,
eventName: 'DrawCompleted',
args: { cid },
onLogs: (logs: any) => {
console.log(logs);
getRandomNumbers();
}
});

// `watchContractEvent` will only watch for future events
// So if your request was just completed a few seconds ago you won't be notified
// That's why you can also call the function `isCompleted` to check if your request is already completed
const isCompleted = await publicClient.readContract({
address: mainContractAddress,
abi: mainContractAbi,
functionName: 'isCompleted',
args: [cid]
});


if (isCompleted as boolean) {

// If our request is already completed we can get the randomness now
getRandomNumbers();

}

async function getRandomNumbers(): Promise<void> {

unwatch(); // A request can only be completed once so we can stop listening for new events after it is completed

const response = await publicClient.readContract({
address: mainContractAddress,
abi: mainContractAbi,
functionName: 'checkRandomNumbers',
args: [cid]
});

const randomNumbers: number[] = response as number[]; // Convert the response to a number array type
console.log(`The random numbers for request ${cid} are: ${randomNumbers.join(", ")}`);
console.log(`The winners for this random draw are: ${randomNumbers.map(n => participants[n - 1]).join(", ")}`); // The minimum value of a random number is 1 so you need "n-1" to convert the number to an array index
// If randomNumbers = [2,4] then output will be "The winners are: Lara, Joe"
}

Raw randomness

You can get the raw randomness for your request by calling checkRawRandomness instead of checkRandomNumbers.

Typescript
const rawRandomness = await publicClient.readContract({
address: mainContractAddress,
abi: mainContractAbi,
functionName: 'checkRawRandomness',
args: [cid]
});

console.log(`The raw randomness for CID ${cid} is ${rawRandomness as string}`);

Learn more about raw randomness.