Web2 API
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.
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. Use0
for Ordered outcomes,1
for Fisher-Yates, or2
for Fisher-Yates (GLI-19 certified). If you don't know which one to choose we recommend you to use0
.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. Use0
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.
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 addresssignature
(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 drawrules
(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".
- A list of participants with each participant separated by the delimiter
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. Use0
to ask for randomness immediately.algorithm
(optional): The random draw algorithm to use. Use0
for Ordered outcomes,1
for Fisher-Yates, or2
for Fisher-Yates (GLI-19 certified). If you don't know which one to choose we recommend you to use0
. Default is0
.
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
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.
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.
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
.
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}`);