Nois Documentation

Just the docs.


In this chapter you can read what Nois is about and how it works at a high level. This could be equally interesting for developers, investors, infrastructure operators as well as blockchain enthusiats.



Nois is a Proof of Stake blockchain protocol that allows developers to use secure, unbiased and cost efficient randomness via IBC. Inside this documentation you will find all the instructions in order to:

  • Setup a full node and become a Nois validator earning $NOIS while sustaining the chain.
  • Fix common validators/full-node problems.
  • Use Nois to bring randomness into your decentralised application.
  • Run a relayer
  • Run a drand bot

How it works

The following steps are taken to get the randomness:

  • A Contract on a CosmWasm and IBC-enabled chain (such as Juno or Stargaze) sends a message to a Nois proxy contract on the same chain. A reply with further information regarding the job is sent to the original contract.
  • The proxy contract sends an IBC message to its couter-part on the Nois Network where the job is put in the queue.
  • Once the drand beacon of the correct round is released, a network of bots sends it to the Nois Network for verification.
  • Upon successful verfication, the pending jobs for the round are processed. For every matching job, an IBC response with the beacon is sent.
  • The proxy contract receives the beacon and sends a callback to the original contract.


Nois uses drand as a source of secure, unbiased and unpredictable randomness. The randomness is generated by drand then it is brought to the nois chain where it is verified. Drand is not a blockchain but a decentralised network of institutions and reliable organisations such as Cloudflare. For more details you can visit the drand website


Use cases for unpredictable, unbiased and publicly verifiable randomness

Nois Team

  • Simon Warta: Developer - Cofounder at Confio and main maintainer of CosmWasm - Watch them talk about Nois
  • @nikkolasg1: Researcher - Inventor of the drand protocol
  • Kais Baccour: DevOps - linkedin - Watch them talk about Nois
  • @jhernandezb_: Developer - Cofounder at Stargaze
  • @0xantcrypto: Developer - Cofounder at Loterra and Terrand
  • @LeTurt_: Developer


πŸ‘Ά I am a 5 year old kid

What is Nois

Nois is a special computer program that helps other computer programs make things happen by surprise. These programs use Nois to make games more fun, or to help people make important decisions fairly. Nois uses a secret magical code that nobody knows, so nobody can cheat and guess what will happen next. Nois is like a magic box that helps make things more interesting and fair.

How can I buy Nois

I'm sorry, but Nois is not something that can be bought. It is a decentralized network that provides randomness to other blockchain networks. As a 5 year old, it is unlikely that you would have a need for this type of technology. Instead, you can focus on learning and growing in a healthy and fun way.

πŸ•ΈοΈ I am a Web3 user

Why should I care about Nois as an end user?

As an end user, you should care about Nois because it helps to ensure the fairness and unpredictability of the dapps you use. For example, if you use a lottery or gaming dapp that incorporates randomness generated by Nois, you can be confident that the outcomes are truly random and not susceptible to manipulation. This can help to ensure that the dapps you use are fair and trustworthy, providing a better experience for you as a user. Additionally, the use of Nois can help to improve the security of dapps by providing a secure and reliable source of randomness, reducing the likelihood of vulnerabilities and attacks.

What are the usecases for decentralised unbiased randomness and how can Nois help with that?

Decentralized unbiased randomness is useful for many different applications, such as:

  • Lotteries and other games of chance
  • Cryptocurrencies and financial systems
  • Voting and decision-making processes
  • Cybersecurity and encryption
  • Selecting randomly people or processes for fair verification

Nois can help with these use cases by providing a secure and reliable source of decentralized unbiased randomness. This can be used to create fair and transparent lottery systems, to improve the security of financial transactions and voting processes, and to enhance the security of encryption systems. By providing a decentralized and unbiased source of randomness, Nois helps to ensure that these applications are fair and secure.

πŸ‘©πŸ»β€πŸ’» I am a Techie

Why should i care about Nois as a techie?

As a techie, you should care about Nois because it provides a secure and reliable way to incorporate randomness into your dapps. Randomness is often essential for creating fair and unpredictable outcomes in games, lotteries, and other applications. Nois uses the drand protocol to generate randomness and makes it available to dapps via IBC, providing a simple and cost-effective solution for incorporating randomness into your projects. Additionally, Nois provides a toolbox for dapp developers, allowing you to easily integrate Nois into your dapps and transform the randomness you receive in a safe and standardised manner. This can help you to create more engaging and secure dapps for your users.

πŸ€‘ I am an Investor

Why should I care about Nois as an investor?

As an investor, you should care about Nois because it is an important component of the growing Cosmos ecosystem. By providing a secure and reliable source of randomness, Nois enables the development of a wide range of decentralized applications (dapps) that can benefit from randomly generated data. This can help to drive adoption and growth in the Cosmos ecosystem, potentially leading to increased value for investors. Additionally, as a decentralized and permissionless network, Nois offers the potential for investors to participate in its governance and potentially earn rewards for supporting the network.

Wen airdrop ser?

An investor walks into a bar and asks the bartender if he's heard of NOIS. The bartender replies, "Yeah, I've heard of it. It's a blockchain project that provides randomness to other chains through IBC." The investor then excitedly asks, "Do they do airdrops?" The bartender laughs and says, "No, I don't think they do airdrops. That's not really their focus. They're more interested in providing secure and unbiased randomness for dapps." The investor pouts and says, "Well, that's no fun. I was hoping to get some free tokens." The bartender shakes his head and says, "Sorry, buddy. You'll have to look elsewhere for your free money... Oh wait you look like a random dude... if you are random enough you might be eligible to get one."

Why does Nois only have 45 active validators? Any plans to increase that?

You can read this blog article to answer your questions

I know a chain that could use Nois, who can integrate Nois with that chain?

Anyone can do that. Nois is fully permissionless and any IBC enabled blockchain can integrate Nois to it. Formore info follow the docs section Integrate Nois to your Chain



for token holders and investors

In this chapter you can find anything related the NOIS token and its utility.

How to stake


  • Have a Keprl wallet or similar (+info)
  • Have an address in the Nois network (+info)

Why staking

Staking $NOIS helps secure the network and allows to earn rewards. Unstaking $NOIS is subject to some ubonding time period where you wait for your tokens to be unstaked (21 days at the time of writing). During this period no rewards are distributed.

How and where to stake

You can use one of these web tools to stake NOIS:

Staking with the CLI

If you are familiar with CLI tools in the Cosmos ecosystem, you can use noisd like any other chain to delegate, redelegate and unbond. However, please note that this is only recommended for experienced users. Getting the parameters wrong may have unintended consequences.

noisd tx staking delegate {VALIDATOR_ADDRESS} {AMOUN_IN_UNOIS}unois \
  --node "" \
  --chain-id nois-1 \
  --gas auto --gas-adjustment 1.3 --gas-prices 0.05unois \
  --from {KEY_NAME} \
  --sign-mode amino-json --ledger \
  --broadcast-mode block


You can check the tokenomics in this blog post

Use Nois Randomness Beacon - For DAPP Developers

ℹ️ This section is intended for developers who are building applications that consume the randomness. If you are looking on the documentation to contribute to Nois then check The Nois Developement section (Under construction).

​ From a DAPP developer's perspective, getting randomness is as simple as 2 handlers in the contract. The first handler is GetNextRandomness(job_id) and the second handler is receive(randomness,job_id)

job_id: This is an internal identifier within the dapp to know what the randomness is going to be used for. It is up to you Dapp developer to define what it means. Imagine your Dapp has multiple players, and each one of them is rolling a dice. When player Bob rolls the dice, your DAPP chooses a job_id of type string to reference the randomness that will hold the randomness of the dice roll of Bob, Alice can roll a second dice with a different job_id. In another use case you can have on the same contract rounds of lottery A and rounds of lottery B. You can set one job_id per lottery so that the contract knows which randomness matches what game.

ℹ️ You can choose whichever string you like for the job_id The job_id is not about routing the randomness back to your contract. The routing callback will simply go to the contract that called the nois-proxy.

randomness: This is the raw randomness hexadecimal data that the dapp receives from Nois. Example of randomness:



Contract implementation

Double dice game example:

If you prefer video tutorial format you can check this link

Import the nois packages

First thing is to import the packages. Add this to your Cargo.toml under dependencies.

fn main() {
// in cargo.toml
nois = "0.7.0"

Note that Rust editions prior to "2021" may require the addition of the following option to the package section of your Cargo.toml for a successful build:

fn main() {
resolver = "2"

Configure the proxy address

We need to add the address of the nois-proxy. One common way to do it is during the instantiation of the contract.

fn main() {
// in
pub const NOIS_PROXY: Item<Addr> = Item::new("nois_proxy");

import the nois-proxy.

fn main() {
// in
use crate::state::{NOIS_PROXY};

Still in the add the instantiation msg which validates the nois-proxy address and stores it

fn main() {
// in
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> Result<Response, ContractError> {
    // The nois-proxy abstracts the IBC and nois chain away from this application
    let nois_proxy_addr = deps
        .map_err(|_| ContractError::InvalidProxyAddress)?;
    set_contract_version(, CONTRACT_NAME, CONTRACT_VERSION)?;, &nois_proxy_addr)?;
        .add_attribute("method", "instantiate")
        .add_attribute("owner", info.sender))

Declare the instantiation msg

fn main() {
// in
pub struct InstantiateMsg {
   pub nois_proxy: String,

Add the InvalidProxyError in

fn main() {
// in
#[error("Proxy address is not valid")]

Triggering the randomness request

In order to request the randomness we need a function whether internal or publicly called. For this tutorial we can make a roll dice msg that will in turn call the getNextRandomness(id) handler. So the RollDice message gets the id as a parameter

fn main() {
// in
match msg {
        //RollDice should be called by a player who wants to roll the dice
        ExecuteMsg::RollDice { job_id } => execute_roll_dice(deps, env, info, job_id),
fn main() {
// in
pub enum ExecuteMsg {
   RollDice {
       /// An ID for this job which allows for gathering the results.
       job_id: String,

Call the GetNextRandomness(id) from the triggering function

fn main() {
//execute_roll_dice is the function that will trigger the process of requesting randomness.
//The request from randomness happens by calling the nois-proxy contract
pub fn execute_roll_dice(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    job_id: String,
) -> Result<Response, ContractError> {
    let nois_proxy = NOIS_PROXY.load(;

    let response = Response::new().add_message(WasmMsg::Execute {
        contract_addr: nois_proxy.into(),
        //GetNextRandomness requests the randomness from the proxy
        //The job id is needed to know what randomness we are referring to upon reception in the callback
        //In this example, the job_id represents one round of dice rolling.
        msg: to_binary(&ProxyExecuteMsg::GetNextRandomness { job_id })?,
        //In this example the randomness is sent from the gambler, but you may also send the funds from the contract balance
        funds: info.funds, // Just pass on all funds we got

Receiving the randomness

The nois-proxy contract sends the callback on the NoisReceive entrypoint. Therefore, you should add the Receive handler on your ExecuteMsg.

fn main() {
// in
// Adding ExecuteMsg::NoisReceive
 match msg {
        //RollDice should be called by a player who wants to roll the dice
        ExecuteMsg::RollDice { job_id } => execute_roll_dice(deps, env, info, job_id),
        //NoisReceive should be called by the proxy contract. The proxy is forwarding the randomness from the nois chain to this contract.
        ExecuteMsg::NoisReceive { callback } => execute_receive(deps, env, info, callback),

and in

fn main() {
// in
use nois::NoisCallback;

#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    // job_id for this job which allows for gathering the results.
    RollDice { job_id: String },
    //callback contains the randomness from drand (HexBinary) and job_id
    //callback should only be allowed to be called by the proxy contract
    NoisReceive { callback: NoisCallback },

In the receive function you can implement whatever you would like to do with the randomness. You directly use the randomness as a raw hexadecimal or you can apply some common randomness functionalities that you get from the Nois toolbox crate.

fn main() {
// in

//The execute_receive function is triggered upon reception of the randomness from the proxy contract
//The callback contains the randomness from drand (HexBinary) and the job_id
pub fn execute_receive(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    callback: NoisCallback,
) -> Result<Response, ContractError> {
    //load proxy address from store
    let proxy = NOIS_PROXY.load(;
    //callback should only be allowed to be called by the proxy contract
    //otherwise anyone can cut the randomness workflow and cheat the randomness by sending the randomness directly to this contract
    ensure_eq!(info.sender, proxy, ContractError::UnauthorizedReceive);

    // In this Dapp we don't need the drand publish time. so we skip it with ..
    let NoisCallback {
        job_id, randomness, ..
    } = callback;

    let randomness: [u8; 32] = randomness
        .map_err(|_| ContractError::InvalidRandomness)?;
    //ints_in_range provides a list of random numbers following a uniform distribution within a range.
    //in this case it will provide uniformly randomized numbers between 1 and 6
    let double_dice_outcome = ints_in_range(randomness, 2, 1, 6);
    //summing the dice to fit the real double dice probability distribution from 2 to 12
    let double_dice_outcome = double_dice_outcome.iter().sum();

    //Preserve the immutability of the previous rounds.
    //So that the player cannot retry and change history.
    let response = match DOUBLE_DICE_OUTCOME.may_load(, &job_id)? {
        None => Response::default(),
        Some(_randomness) => return Err(ContractError::JobIdAlreadyPresent),
    };, &job_id, &double_dice_outcome)?;


Interacting with a DAPP

This document intends to help developers test the example contracts that are provided by nois Clone the double-dice game code

git clone
cd nois-dapp-examples

Compile and optimise the code

RUSTFLAGS="-C link-arg=-s" cargo build --release --target=wasm32-unknown-unknownStoring the contract:

Store the contract

junod tx wasm store \
       target/wasm32-unknown-unknown/release/double_dice_roll.wasm \
       --from <your-key> \
       --chain-id uni-6 \
       --gas=auto \
       --gas-adjustment 1.4  \
       --gas-prices 0.025ujunox \
       --broadcast-mode=block \
       --node= -y 

Instantiate the contract

export NOIS_PROXY=juno1tquqqdvlv3fwu5u6evpt7e4ss47zczug8tq4czjucgx8dulkhjxsegfuds
junod tx wasm instantiate CODE_ID_FROM_PREVIOUS_STEP \
       '{"nois_proxy": "'"$NOIS_PROXY"'"}' \
       --label=double-dice \
       --no-admin \
       --from <your-key> \
       --chain-id uni-6 \
       --gas=auto \
       --gas-adjustment 1.4 \
       --fees=1000000ujunox \
       --broadcast-mode=block \
       --node= -y 

Request randomness (ie. roll the dice)

export DOUBLE_DICE_ROLL_CONTRACT=juno1e7p6k4c0l52zperyhd6nfx053yrdgjw4k6kunszhk9j0smedgtzs27nrkh

junod tx wasm execute $DOUBLE_DICE_ROLL_CONTRACT \
            '{"roll_dice": {"job_id": "<your-job-id>"}}' \
            --from <your-key> \
            --gas-prices 0.025ujunox \
            --gas=auto \
            --gas-adjustment 1.3 \
            --amount 100ujunox -y

Query the randomness

junod query wasm  contract-state  smart \
            '{"get_history_of_rounds": {}}' \

Nois Toolbox

To safely transform and manipulate your randomness, onchain and offchain.

Next to providing the randomness, Nois offers a set of tooling to help developers reshape the received randomness in order to apply it to their custom use case.

Why use the nois-toolbox instead of transforming the randomness yourself?

Sometimes it can be challenging to manipulate randomness and you can end up with a randomness that follows a different distribution from what is intended or you can also unintentionally lower the entropy of the original randomness. This is why Nois provides this well tested, standard and opensource toolbox that everyone can contribute to and maintain. This way it is in the interest of all that any bug is quickly fixed and the efforts of 1 project contribute to the common good.

The Nois Toolbox can be compiled to JavaScript via WebAssembly. This way you can simulate the outputs for every randomness value. The results match exactly those of CosmWasm contracts using the same tools. The toolbox is available in this github repository and two artifacts are published.

If you want to use the nois-toolbox in your contract all you have to do is import the nois crate. If you want to verify, play or simulate the randomness offchain on a script or a UI on a browser instead you can use the nois npm package. ​ This table provides an overview of the functions that the toolbox provides

coinflipReturns heads or tails.
roll_dicereturns a random int between 1-6. For a double(or multi) dice you can use ints_in_range or sub_randomness instead.
decimalReturns a random decimal between 0 and 1 (uniform distribution).
ints_in_rangeProvides a list of integers between two numbers. Can be used for a double dice throw
int_in_rangeProvides one integer between two numbers. Can be used for a single dice
shuffleShuffles a vector using the Fisher-Yates algorithm. Can be used for an NFT hero creation with many objects/items/skills to randomly shuffle
sub_randomnessGenerates more more random numbers out of a single round of drand round. This can be needed if for example you want to run many lotteries in parallel using the same randomness round without sacrificing the high entropy.
pickPicks n elements from a given list. in a uniform distribution
select_from_weightedSelects one element from a given weighted list. This is useful if for example you want to mint an NFT hat with 30% chances to be red, 25% to be blue and 45% to be pink

Using the Nois Toolbox in a CosmWasm smart-contract


Takes a randomness and returns the result of a coinflip (heads or tails)

fn main() {
use nois::coinflip;

let side = coinflip(randomness);
if side.is_heads(){
if side.is_tails(){


Derives a random integer in the given range. Use this method to avoid a modulo bias.

fn main() {
use nois::int_in_range;

// Half-open interval [1, 7)
let dice1 = int_in_range(randomness, 1..7);
assert!(dice1 >= 1);
assert!(dice1 < 7);

// Closed interval [1, 6]
let dice2 = int_in_range(randomness, 1..=6);
assert!(dice2 >= 1);
assert!(dice2 <= 6);


Derives random integers in the given range. Use this method to avoid a modulo bias. Using this is potentially more efficient than multiple calls of int_in_range.

fn main() {
use nois::ints_in_range;

let [dice1, dice2] = ints_in_range(randomness, 1..=6);
assert!(dice1 >= 1 && dice1 <= 6);
assert!(dice2 >= 1 && dice2 <= 6);


Returns a Decimal d with 0 <= d < 1

fn main() {
use nois::random_decimal;

let d = random_decimal(randomness);


Shuffles a vector using the Fisher-Yates algorithm

fn main() {
use nois::shuffle;

//We are randomly shuffling a vector of integers [1,2,3,4]
let mut data = vec![1, 2, 3, 4];
shuffle(randomness, &mut data);
// The length of the vector is the same but the order of the elements has changed
assert_eq!(data.len(), 4);
assert_ne!(data, vec![1, 2, 3, 4]);


Takes a randomness and a key. Returns an arbitrary number of sub-randomnesses. The key is mixed into the randomness such that calling this function with different keys leads to different outputs. Calling it with the same key and randomness leads to the same outputs.

fn main() {
use nois::{sub_randomness_with_key, int_in_range};

let mut provider = sub_randomness_with_key(randomness, "Key");

let dice1_subrandomness = provider.provide();
let dice2_subrandomness = provider.provide();

let dice1_result = int_in_range(dice1_subrandomness, 1..7);
let dice2_result = int_in_range(dice2_subrandomness, 1..7);


Takes a randomness and a key. Returns an arbitrary number of sub-randomnesses. This is equivalent to calling sub_randomness_with_key with key b"^default^".

fn main() {
use nois::{sub_randomness, int_in_range};

let mut provider = sub_randomness(randomness);

let dice1_subrandomness = provider.provide();
let dice2_subrandomness = provider.provide();

let dice1_result = int_in_range(dice1_subrandomness, 1..7);
let dice2_result = int_in_range(dice2_subrandomness, 1..7);

Using the Nois Toolbox in js

The Nois Toolbox can be compiled to JavaScript via WebAssembly. This way you can simulate the outputs for every randomness value. The results match those of CosmWasm contracts using the same tools. The Nois Simulator is a good example for such a usecase. In order to keep the JS/Wasm interface simple, there is a wrapper in the module lib/js which takes the randomness inputs in hex format and uses types and error handling that plays well with JS. JS/Wasm bindings are created using wasm-bindgen. The JS does not match 100% the contract implementation. The differences are documented here.

Contract functionJS functionStatusNote
nois::coinflipcoinflipβœ… ReadyReturns string instead of enum
nois::roll_diceroll_diceβœ… Ready----βœ… Ready----
nois::select_from_weightedselect_from_weightedβœ… Ready----
nois::int_in_rangeint_in_rangeβœ… ReadyOnly supports half-oen range, i.e. the end value is always exluded
nois::ints_in_rangeints_in_rangeβœ… Ready----
nois::random_decimalrandom_decimalβœ… ReadyEncodes result Decimal as string
nois::sub_randomnesssub_randomnessβœ… ReadyTakes a count argument and returns an Array instead of an iterator
nois::nois_shuffleshuffleβœ… Ready----

Video coding tutorial - CosmWasm smart contract that gets randomness from Nois

You can watch this tutorial to

  • get an overview of Nois
  • see how to build a smart contract that pulls the randomness from Nois.
  • Deploy the smart contract
  • Interact with the smart contract



Developer FAQ

In this page we would like to list some relevant questions developers have asked in an attempt to gather some good knowledge

- "I have funds in NOIS. I am about to deploy a nois-proxy on my chain, How does the payment work? When we instantiate the proxy, should I send you the "manager" or contract address? How will the proxy know to debit our account on the Nois side, if that makes sense?"

- So as soon as you open a channel between your proxy and the gateway, the gateway will instantiate a nois-payment contract for your proxy. the proxy will know by itself from IBC its nois-payment address. because it receives a welcome packet from the gateway that will update it with the nois price and the nois-payment contract that the gateway has instantiated for it.

- "If I instantiate the proxy with the prices parameter [1.5juno,50nois], it would mean that each GetNextRandomness call would cost this much?"

- Yes! it will cost this OR that not a combination. So it will cost whether 1.5juno or 50 NOIS. But it will cost the Dapp to pay the proxy. So the proxy gets those funds. You are the manager of the proxy so those are your funds.


Active networks:


  • nois-testnet-004, a short living pre-mainnet testnet with mainnet addresses and token distribution


Basic info

  • Chain ID: nois-1
  • Demon: unois



  • Build noisd from
  • Tag: v1.0.5
  • noisd version should show 1.0.2 Running a node is similar to most other cosmos-sdk chains. but you can follow this tutorial made by one of Nois validators here

Explorers, p2p, RPCs, Rest and GRPC endpoints

Check the list in chain registry here



- Name: nois-drand
  Address: nois19w26q6n44xqepduudfz2xls4pc5lltpn6rxu34g0jshxu3rdujzsj7dgu8
  Code ID: "20"
  Git Asset Name: nois_drand
  Instantiation Message: '{"incentive_point_price":"3000","incentive_denom":"unois","min_round":808287,"manager":"nois1p9tw323xdjp5q3yzuecfahmgrpufmm89z93wpk"}'
  URL: ""
  Version: v0.15.4
    gateway: nois1acyc05v6fgcdgj88nmz2t40aex9nlnptqpwp5hf8hwg7rhce9uuqgqz5wp
    incentive_denom: unois
    incentive_point_price: "3000"
    manager: nois1p9tw323xdjp5q3yzuecfahmgrpufmm89z93wpk
    min_round: 808287


- Name: nois-icecube
  Address: nois1gwnfyx82rwgc4y9r8vx6nr9v35dwezw3dadw6h39mad9amg7shnsler5f0
  Code ID: "6"
  Git Asset Name: nois_icecube
  Instantiation Message: '{"manager":"nois1p9tw323xdjp5q3yzuecfahmgrpufmm89z93wpk"}'
  URL: ""
  Version: v0.11.0


- Name: nois-sink
  Address: nois10c0ppz0n57hqrmfp7g7lqs6k4xk9rxhvcfkqt83r8mars2lc57mq0f6cty
  Code ID: "5"
  Git Asset Name: nois_sink
  Instantiation Message: "{}"
  URL: ""
  Version: v0.11.0


- Name: nois-gateway
  Address: nois1acyc05v6fgcdgj88nmz2t40aex9nlnptqpwp5hf8hwg7rhce9uuqgqz5wp
  Code ID: "21"
  Git Asset Name: nois_gateway
  Instantiation Message: '{"manager":"nois1p9tw323xdjp5q3yzuecfahmgrpufmm89z93wpk","price":{"denom":"unois","amount":"50000000"},"payment_code_id":7,"sink":"nois10c0ppz0n57hqrmfp7g7lqs6k4xk9rxhvcfkqt83r8mars2lc57mq0f6cty"}'
  URL: ""
  Version: v0.15.4
    drand: nois19w26q6n44xqepduudfz2xls4pc5lltpn6rxu34g0jshxu3rdujzsj7dgu8
    manager: nois1p9tw323xdjp5q3yzuecfahmgrpufmm89z93wpk
    payment_code_id: 7
    payment_initial_funds: null
      amount: "1000000"
      denom: unois
    sink: nois10c0ppz0n57hqrmfp7g7lqs6k4xk9rxhvcfkqt83r8mars2lc57mq0f6cty


Chainproxy addressmanager/owner
Auraaura1r3zgdsn3dcze07a4r60rxxx7ppvkxfshn9np0pwtkgarrld0786s72jtjtAura team
Junojuno1qr84ktm57q5t02u04ddk5r8s79axdzglad6tfdd9g2xgt4hkh6jsgeq9x2Nois team
Injectiveinj1w9g3sk7lk8k0pdtctygupt6f3te7x4thvzz57aInjective Governance
Stargazestars1mw5y55f53mnara7g3pn2pylxl8dpauscyn83c68442hz9nwktzrq8tjzyfStargaze Governance
Osmosisosmo1tvzr8ur0ynjhqftxpkl4qwel8ly7erhy6cu6ks426xmzf92vk6eqfp9wclNois team

IBC channels

Right now the following IBC channels are supported:

ProtocolOther chainChannel (nois-1)Channel (other chain)Description
ICS-20Aura (xstaxy-1)channel-16channel-3aura-nois transfer
ICS-20Injective (injective-1)channel-17channel-138injective-nois transfer
ICS-20Juno (juno-1)channel-1channel-225juno-nois transfer
ICS-20Osmosis (osmosis-1)channel-37channel-8277osmosis-nois transfer
ICS-20Stargaze (stargaze-1)channel-0channel-137stars-nois transfer
ICS-20Archway (archway-1)channel-21channel-17archway-nois transfer
ICS-20Sei (pacific-1)channel-43channel-58sei-nois transfer
ICS-20Neutron (neutron-1)channel-47channel-722neutron-nois transfer
nois-v7Aura (xstaxy-1)channel-35channel-8Aura team managed
nois-v7Juno (juno-1)channel-2channel-243Public proxy
nois-v7Juno (juno-1)channel-11channel-248Gelotto
nois-v7Injective (injective-1)channel-20channel-140Injective governance
nois-v7Archway (archway-1)channel-22channel-19Architech proxy
nois-v7Stargaze (stargaze-1)channel-38channel-238Stargaze governance
nois-v7Osmosis (osmosis-1)channel-41channel-11319Public proxy
nois-v7Sei (pacific-1)channel-44channel-59Public proxy

IBC denoms

On Nois:

  • ustars: ibc/49BAE4CD2172833F14000627DA87ED8024AD46A38D6ED33F6239F22B5832F958
  • ujuno: ibc/EFF323CC632EC4F747C61BCE238A758EFDB7699C3226565F7C20DA06509D59A5
  • aarch: ibc/3A8BF65AFC8F1AC2998A80C5D78C355D058C8C755882E85A9BEC75D4E9F09739

unois on:

  • Stargaze (stargaze-1): ibc/0F181D9F5BB18A8496153C1666E934169515592C135E8E9FCCC355889858EAF9
  • Juno (juno-1): ibc/1D9E14A1F00613ED39E4B8A8763A20C9BE5B5EA0198F2FE47EAE43CD91A0137B
  • Injective (injective-1) ibc/DD9182E8E2B13C89D6B4707C7B43E8DB6193F9FF486AFA0E6CF86B427B0D231A
  • Aura ibc/1FD48481DAA1B05575FE6D3E35929264437B8424A73243B207BCB67401C7F1FD
  • Osmosis ibc/6928AFA9EA721938FED13B051F9DBF1272B16393D20C49EA5E4901BB76D94A90
  • Neutron ibc/D03F341CAA5D24B43ABE27C11A214EA3589DDEA125A2E6A76C7C37F2F3C59692

Testnet 005

Basic info

  • Chain ID: nois-testnet-005
  • Demon: unois




Seed nodes

  • 6b2af739ac032a96e1e568b1871a1ca6e80ab08e@


An incomplete and unchecked list of community provided TendermintRPC endpoints:




- Name: nois-drand
  Address: nois14xef285hz5cx5q9hh32p9nztu3cct4g44sxjgx3dmftt2tj2rweqkjextk
  Code ID: "70"
  Git Asset Name: nois_drand
  Instantiation Message: '{"incentive_point_price":"3000","incentive_denom":"unois","min_round":,"manager":"nois1tfg9ptr84t9zshxxf5lkvrd6ej7gxjh75lztve"}'
  URL: ""
  Version: v0.15.4
    gateway: nois1c9l6qcl82u7zkgjduj2snfuv5rz6jzwsumw4nktgytzclazujc6qc05p5j
    incentive_denom: unois
    incentive_point_price: "3000"
    manager: nois1tfg9ptr84t9zshxxf5lkvrd6ej7gxjh75lztve
    min_round: 833618


- Name: nois-icecube
  Address: nois1gwnfyx82rwgc4y9r8vx6nr9v35dwezw3dadw6h39mad9amg7shnsler5f0
  Code ID: "6"
  Git Asset Name: nois_icecube
  Instantiation Message: '{"manager":"nois1tfg9ptr84t9zshxxf5lkvrd6ej7gxjh75lztve"}'
  URL: ""
  Version: v0.11.0


- Name: nois-gateway
  Address: nois1xwde9rzqk5u36fke0r9ddmtwvh43n4fv53c5vc462wz8xlnqjhls6d90xc
  Code ID: "71"
  Git Asset Name: nois_gateway
  Instantiation Message: '{"manager":"nois1tfg9ptr84t9zshxxf5lkvrd6ej7gxjh75lztve","price":{"denom":"unois","amount":"50000000"},"payment_code_id":57,"sink":"nois10c0ppz0n57hqrmfp7g7lqs6k4xk9rxhvcfkqt83r8mars2lc57mq0f6cty"}'
  URL: ""
  Version: v0.15.4
    drand: nois14xef285hz5cx5q9hh32p9nztu3cct4g44sxjgx3dmftt2tj2rweqkjextk
    manager: nois1tfg9ptr84t9zshxxf5lkvrd6ej7gxjh75lztve
    payment_code_id: 58
    payment_initial_funds: "2000000unois"
      amount: "1000000unois"
      denom: unois
    sink: nois10c0ppz0n57hqrmfp7g7lqs6k4xk9rxhvcfkqt83r8mars2lc57mq0f6cty


- Name: nois-sink
  Address: nois10c0ppz0n57hqrmfp7g7lqs6k4xk9rxhvcfkqt83r8mars2lc57mq0f6cty
  Code ID: "5"
  Git Asset Name: nois_sink
  Instantiation Message: "{}"
  URL: ""
  Version: v0.11.0


Chainproxy addressmanager/owner
Junojuno1pjpntyvkxeuxd709jlupuea3xzxlzsfq574kqefv77fr2kcg4mcqvwqedqNois team (expired)
Injectiveinj14nendtsz0c40n7xtzwkjmdc8dkuz835jdydxhnNois team
Neutronneutron1tw9sg9e4l09l5rjglf4qfvcft470ljk5grdq3luagysyk83nzfusw2sxgqNois team (expired)
Stargazestars1atcndw8yfrulzux6vg6wtw2c0u4y5wvy9423255h472f4x3gn8dq0v8j45Nois team
Seisei1vxlzhn6qvf95syha2tgr0ct23sk5359s2vqzylgthuyy7kd7ql5qcxa4r0Matthew Parker

IBC channels

Right now the following IBC channels are supported:

ProtocolOther chainChannel (nois-testnet-005)Channel (other chain)Description
ICS-20Injective (injective-888)channel-33channel-74inj-nois transfer
ICS-20Juno (uni-6)channel-69channel-877junox-nois transfer
ICS-20Neutron (pion-1)channel-40channel-133ntrn-nois transfer
ICS-20Stargaze (elgafar-1)channel-48channel-485stars-nois transfer
ICS-20Aura (euphoria-2)[channel-53]channel-81aura-nois transfer
ICS-20Sei (atlantic-2)channel-74channel-77nois-sei transfer
nois-v7Juno (uni-6)channel-17channel-198Public proxy
nois-v7Injective (injective-888)channel-36channel-77Public proxy
nois-v7Neutron (pion-1)channel-42channel-135Public proxy
nois-v7Stargaze (elgafar-1)channel-78channel-749Public proxy
nois-v7Sei (atlantic-2)channel-75channel-89Public proxy

IBC denoms

On Nois:

unois on:

- chain-id: uni-6
  denom: ibc/035CF83FC7EA597082566DA414AA74E5D4EDAA07DA45DBBC5217EC161689FD9F
  channel-id: channel-877
- chain-id: euphoria-2
  denom: ibc/A68FBCB1DF149AB04D6DF89AD3474CB1CFC8B47549EE2C9924BFA1CA5ADF8E1B
  channel-id: [channel-81](
- chain-id: injective-888
  denom: ibc/A190CF3FC762D25A46A49E7CB0E998F4A494C7F64A356DA17C25A2D8B0069D3B
  channel-id: [channel-74](
- chain-id: pion-1
  denom: ibc/26139E488F510BDA8DDE5614D358A38502BDA061954B8D10ADEFC4EAA58552FF
- chain-id: elgafar-1
  denom: ibc/ACCAF790E082E772691A20B0208FB972AD3A01C2DE0D7E8C479CCABF6C9F39B1


A faucet is a tool to provide small amounts of tokens for onboarding purposes. We usually use a faucet channel on our Discord server. The following faucets are available.


There is currently no faucet available. If you are nice in chat, some community members might be kind enough to gift you some tokens.

Testnet 005

Faucet available on on our Discord server


On this page you find reference checksums for builds of various contract versions. The builds are created using cosmwasm/workspace-optimizer in our CI system. They can be reproduced using the correct builder version for the tag.

Version 0.11.0

Source code: nois-contracts@v0.11.0

c403371a244acce9aaa6f31d01c7bb3518904708da9516d94c73f253202f91a8  nois_demo.wasm
ddaca2d1887555ebfe07a65ebec09fd3a159e78c3c429de9281187ac1780f5a0  nois_drand.wasm
9c87c6acf3775329ba7ad47fe6b31309b0b57335009205de7605f911475adfda  nois_gateway.wasm
b8cc8ae4201ee757a70c1e6d8b72c3afb94fc36ba95294ab0614011069de0fe5  nois_icecube.wasm
442cc1a6a77c7bbb99e1cb96f19cf481ea25312f50c6256bf314af507074ed18  nois_monitoring.wasm
e6681c8f55415cc903df29dcce28d484f5f03f65ca9a6c00909043eac76d530b  nois_payment.wasm
3adb4e6aebfe0b3c1569bed8068794d53117252b0126c9b3b1e570aaec6fd6aa  nois_proxy.wasm
cb7b021831dd908b673491288b7a76f7ae973b8c1586ce41d9a69cadab5202c7  nois_sink.wasm

Version 0.10.2

Source code: nois-contracts@v0.10.2

519a32e0d7fffeccec08c8de75ed59417d84694fd1a3543856750723b575bbc4  nois_demo.wasm
97eca42191327bf8a2b1c8f55ca3198bf080abcd8a3d0d93814884af26140574  nois_drand.wasm
f0829c3d1300b1f6e0a46feafeffa55b1b5ec74729d122b7ed37754a8cd5e634  nois_gateway.wasm
7b39b0998b328890051891e55c0797e5fdeca8a29f49a4cc2ee77c875678c712  nois_icecube.wasm
8779be6691ab5cc89cc5de87110d44cdcf3c74c9ed5812b7ea02fc58f4ebf6d0  nois_monitoring.wasm
641574a923b978b1928651362a1bb3004778217ce8389d077cb7a5e5237b3d3d  nois_payment.wasm
eac87b36309f1cddcf648d2628d6291dd4633bd93229f4bbfd1574d7e6f291a3  nois_proxy.wasm
756eafcdfec2902f0b5766d458831d54284402df1bf49d267993d01fd313265e  nois_sink.wasm

Version 0.10.1

Source code: nois-contracts@v0.10.1

cf4ae21500e0d74473f496b52fd03f05b537efaf6cf69a68cb41a428cf3d9a9d  nois_demo.wasm
0d44c4d6b98bf2da8d4891a3236b5bb0ac8f8b8eca28a0f0b49d98236f52a2bf  nois_drand.wasm
dcb997ef5529d24e9388ae2dfdb3fd8b891275ef01cdb180085da6d92f4ce3a6  nois_gateway.wasm
a9df75c3f55d4c6069cce65bcd7a20d0d7e6b29bf73ca614d8d6f232bbb473dc  nois_icecube.wasm
44d9ba4421967d94312cb6396ab1056971ca5d53f63d82aa4345b9ac5f050e76  nois_monitoring.wasm
982c049dbf3197521d1fc959fad374ee77f5ea3927f6da9d455a2aff63183a0b  nois_payment.wasm
eb8829e8e5f3fb571a5faaf555ac7f8cec17e2f7e1875cbe0dee2229c09663f4  nois_proxy.wasm
8fb2a58af0ca8ebdde9275c8e68b09623aaa1a005f6de7c2ab01f4611e583ce7  nois_sink.wasm

Version 0.10.0

Source code: nois-contracts@v0.10.0

b2b069b49b234e317b3efae163b974759cf0bc746837d2c63fdac00b13da37db  nois_demo.wasm
1b410b590b9b25599de7bb13624e3abdf705ddd7df8da78d1dcd824316ecd95b  nois_drand.wasm
6339c243842487401065b14175239e87a2a7380c654fe63cf32ba37851d1a13d  nois_gateway.wasm
2856fea75fd9de874e85e835f8de2372532694f1b310a7ffe341be9e16ce183a  nois_icecube.wasm
4be1973f88c3f2c0dc4593c8b712f40aba860b69772fca3871258da4e252bfe9  nois_monitoring.wasm
6dbca3e24d8882642cf832b4687e5b8a6f39ce11d95ca025ca9766f8d3f45e2b  nois_payment.wasm
f29ef3687ac154a708c656515dd33b951ed8e37071c90d418c20cafe3fee6d84  nois_proxy.wasm
6d0b1b81c2ae10b0772e22041ff179d82b67a50cc2dc9a645728666ef96a9682  nois_sink.wasm

For Node Operators

Here you find information how to run a full node as well as produce blocks. If you want to run a sentry, most of the instructions are the same.

Run a full node

We assume you are on some sort of Ubuntu/Debian Linux. Other Linux distributions and macOS works very similar.

1. Update your OS and install dependencies

# Update, upgrade, reboot ‼️
sudo apt update && sudo apt upgrade -y && reboot

# Install dependencies
sudo apt install -y make gcc build-essential git jq joe unzip

2. Install Go

This way: Both Go 1.20 and 1.19 are supported.

3. Clone the noisd repository

git clone
cd noisd
git checkout <SOME TAG>

The tag to be checked out is available in the Networks section.

4. Build and install the noisd binary

make install

export PATH="$PATH:$(go env GOPATH)/bin"
# in zsh: rehash

Check the installation:

noisd version
# Shows version you checked out above

5. Init (creates folder $HOME/.noisd)

Create initial configuration files. The given argument is the moniker (a nickname for the node).

noisd init "random node"

6. Adapt config

# Update p2p setting (config.toml)
export MY_EXTERNAL_ADDR="$(curl -sS" # or set explicitely if this API does not return the correct value
sed -i 's/external_address =.*$/external_address = "'$MY_EXTERNAL_ADDR'"/' $HOME/.noisd/config/config.toml

7. Download the genesis file

See Networks for the correct URL.

wget -O "$HOME/.noisd/config/genesis.json" <GENESIS URL>

8. Draw the rest of the fucking owl

The rest is similar to running a standard Cosmos node or validator. You can check the Cosmos Hub docs for more details. For the faucet, rpc links, permanent peers and similar details visit.

Status checks

On this page you find various ways to check the status of your node.


  1. Ensure your external address is set correctly:
    curl -sS http://localhost:26657/status | jq .result.node_info.listen_addr

  2. Ensure you have a few dozen peers here:
    curl -sS http://localhost:26657/net_info | jq .result.n_peers

  3. Ensure you have a mix of outbound and inbound peers (i.e. both outgoing and incoming connections work:

    # Outbound peers
    curl -sS http://localhost:26657/net_info | jq '.result.peers | map(select(.is_outbound == true)) | length'
    # Inbound peers
    curl -sS http://localhost:26657/net_info | jq '.result.peers | map(select(.is_outbound == false)) | length'


  1. Check your height and catching up value:
    curl -sS http://localhost:26657/status | jq .result.sync_info

History settings

There are a few things you might want to set in yout node. Different settings are required for different use cases, so don't consider them recommendations.

Relayer-friendly node

Keep state snapshots of the last 24 hours:

sed -i 's/pruning =.*$/pruning = "custom"/' $HOME/.noisd/config/app.toml \
  && sed -i 's/pruning-keep-recent =.*$/pruning-keep-recent = "34560"/' $HOME/.noisd/config/app.toml \
  && sed -i 's/pruning-keep-every =.*$/pruning-keep-every = "0"/' $HOME/.noisd/config/app.toml \
  && sed -i 's/pruning-interval =.*$/pruning-interval = "100"/' $HOME/.noisd/config/app.toml

Don't store old state

In order to avoid storing snapshots of the state, in $HOME/.noisd/config/app.toml you can set pruning = "everything":

sed -i 's/pruning =.*$/pruning = "everything"/' $HOME/.noisd/config/app.toml

Checking CORS

Enabling CORS is important to allow browser-based apps to access the APIs the same way as non-browser based apps.

Check CORS with curl

The origin serves as an example app using the endpoint here.

export ENDPOINT=""

# Regular CORS request
curl -sS -I -H "Origin:" \
  "$ENDPOINT/status" | grep -i "access-control-"

# Should return status 200 and include the response header:
# - Access-Control-Allow-Origin

# Preflight request
curl -sS -I -H "Origin:" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: X-Requested-With" \
  "$ENDPOINT/status" | grep -i "access-control-"

# Should return status 200 and include the response headers:
# - Access-Control-Allow-Origin
# - Access-Control-Allow-Methods
# - Access-Control-Allow-Headers

Using systemd

You can run noisd as a service for systemd.

Creading the service file

The following script creates the service file nois.service for systemd. The file was originally provided by Kolot, thank you!.

sudo tee /etc/systemd/system/nois.service > /dev/null <<EOF
Description=Nois blockchain

ExecStart=$(which noisd) start --home $HOME/.noisd


Using the nois service

# Find the new service file
sudo systemctl daemon-reload

# Check status (should be loaded, inactive and disabled)
sudo systemctl status nois

# Enable (i.e. start automatically)
sudo systemctl enable nois

# Start/Restart
sudo systemctl restart nois

# Watch logs
sudo journalctl -u nois -f -o cat

# Watch filtered logs
sudo journalctl -u nois -f -o cat --grep "Ensure peers"

Validator Rewards

Nois rewards the network's validators by allocating a 6% of the inflation to validators in the active set. In contrast to staking rewards, every validator receives the same amount and it is not shared with stakers. This is an attempt to reduce concentration of voting power in a very few validators.

Learn how to query accumulated rewards and how to claim them.


# query by address
noisd q allocation claimable-rewards nois1r04t9nm22u2wfwpuffgyr8jgxs85ek0clsytvs

# query by operator address
noisd q allocation claimable-rewards noisvaloper1r04t9nm22u2wfwpuffgyr8jgxs85ek0c7sk24y

Claiming Rewards

noisd tx allocation claim-rewards --from [validator-key] \
    --chain-id  [chain-id] --gas-prices 0.25unois --gas-adjustment 1.5

IBC relayer

Relayers transfer packets from a chain to another via IBC. They will ship the randomness and tokens between Nois chain and the consumer chains

At Nois we have two kind of relaying:

  • ICS20 relaying: This is for token transfer between chains. (Relayers don't recevice incentives here yet)
  • wasm relaying: This is where the randomness beacon gets requested and sent to consumer chains. Relayers will get incentives by relaying this traffic.

You can check the current IBC clients, connections and channels on mainnet dashboard or on the testnet dashboard

The list of supported channels to relay on testnet is testnet channels

The list of supported channels to relay on mainnet is mainnet channels

IBC wasm relayer

In this tutorial we are using the hermes relayer software. However, feel free to use other relayer software like Hermes and if you want to contribute to the docs by providing the steps for setting up such different software let us know on discord

Setting up hermes relayer

Install hermes from this link

Confgure hermes

log_level = 'info'
enabled = true
refresh = true
misbehaviour = false
enabled = false
enabled = false
enabled = true
clear_interval = 5
clear_on_start = true
tx_confirmation = false
enabled = true
host = ''
port = 3000
enabled = true
host = ''
port = 3001

id = "nois-testnet-005"
type = "CosmosSdk"
memo_prefix = 'Relayed by Katarina'
rpc_addr = ""
grpc_addr = ""
event_source = { mode = 'pull', interval = '1s' }

rpc_timeout = "10s"
account_prefix = "nois"
key_name = "mynoiskey"
key_store_type = "Test"
store_prefix = "ibc"
default_gas = 100000
max_gas = 4000000
gas_multiplier = 1.1
max_msg_num = 30
max_tx_size = 180000
max_grpc_decoding_size = 33554432
clock_drift = "5s"
max_block_time = "30s"
ccv_consumer_chain = false
sequential_batch_tx = false

numerator = "1"
denominator = "3"

price = 0.1
denom = "unois"

policy = "allowall"


derivation = "cosmos"


id = 'nois-1'
address_type = { derivation = 'cosmos' }
memo_prefix = 'Relayed by Katarina'
ccv_consumer_chain = false
event_source = { mode = 'pull', interval = '1s' }

rpc_addr = ''
grpc_addr = ''

rpc_timeout = '20s'
account_prefix = 'nois'
key_name = 'nois'
store_prefix = 'ibc'
max_tx_size = 180000
max_gas= 4000000
gas_price = { price = 0.5, denom = 'unois' }
gas_multiplier = 1.5
max_block_time = '5s'
clock_drift = '5s'
trusting_period = '14days'
trust_threshold = { numerator = '1', denominator = '3' }
policy = "allowall"


id = 'uni-6'
type = "CosmosSdk"
event_source = { mode = 'pull', interval = '1s' }
memo_prefix = 'Relayed by Katarina'

rpc_addr = ''
grpc_addr = ''
#poll_interval= '1s'

rpc_timeout = '10s'
account_prefix = 'juno'
key_name = 'juno'
store_prefix = 'ibc'
max_tx_size = 180000
max_gas= 40000000
gas_price = { price = 0.025, denom = 'ujunox' }
gas_multiplier = 1.2
max_block_time = '15s'
clock_drift = '5s'
trusting_period = '14days'
trust_threshold = { numerator = '1', denominator = '3' }
ccv_consumer_chain = false
sequential_batch_tx = false
policy = "allowall"
derivation = "cosmos"


Relay traffic

hermes start

Set up a new client, connection and channels

Create ibc clients

hermes create client --host-chain uni-6 --reference-chain nois-testnet-005 --clock-drift 20s
#Note the client id created by this operation (will be needed later on)
hermes create client --host-chain nois-testnet-005 --reference-chain uni-6 --clock-drift 20s
#Note the client id created by this operation (will be needed later on)

Create ibc connection

#07-tendermint-19  is the client id that was generated when creating the client on uni-6
#07-tendermint-14  is the client id that was generated when creating the client on nois-testnet-005
hermes create connection --a-chain nois-1  --a-client 07-tendermint-14  --b-client   07-tendermint-19 

Create transfer channel

#change the xxx with the connection-id on uni-6 point to nois
hermes create channel --a-chain uni-6 --a-connection connection-xxx --a-port transfer  --b-port trasnfer

Create wasm channel

hermes create channel --a-chain uni-6 --a-connection connection-72 --a-port wasm.juno1blablabla(uni proxy address)  --b-port wasm.noisblabla(nois gateway address)  --channel-version nois-v7

Drand Bots


Bots bring randomness from drand to the Nois blockchain. That's the only thing the bot does. Once that randomness is on chain, it will be offered to Dapps across IBC. Bots earn incentives from bringing drand rounds that have been requested by consumer dapps.

ℹ️ Drand-bots do not and cannot generate randomness nor can they bias it. They simply relay it from drand to the Nois chain.

ℹ️ Drand-bots are never slashed and do not need to put any collateral simply because they cannot cheat.

⚠️ Although drand-bots cannot impact the outcome of the randomness, they can impact the availability of the randomness by stopping to work or by failing to submit to the Nois chain. The chain needs at least one bot to function. This is why bot operators are incentivised and constitute a critical piece of Nois.

Running a Drand Bot

You can run the drand bot whether on the host or in docker. The setup instructions are in the README of this repository.

Performance Factors of Drand Bots

the main criteria in running a fast drand-bot is being able to broadcast your tx as fast as possible in order to reach the proposer's node asap before the other drand-bots. this will allow your submission tx to be placed among the first 6 bots in the mempool of the proposer's node. Obviously you need a good cpu and a fast connection that is very close to an rpc node. Your rpc node needs to be fast in the network and eventually needs to have fast direct peers so it can reach the proposer before the competitor drand-bot operators. Choosing an rpc node that is heavily used or that many other bot operators are using would not be optimal. Using an rpc that has big voting power can slightly increase your chances because that node gets chosen to propose blocks a bit more often than other validator nodes so sometimes you get that small advantage when your RPC is the block proposer. But this is a very small difference and often validator nodes do not offer an rpc endpoint. In general if you get like +3 second delay it is not because your bot submitted the tx 3 seconds later than the other drand-bots but because they were few ms before you so the proposer did not choose to select you in the proposed block because there is a consensus blockspace that only allows 4-5 submissions. so your submission becomes leftover for the next block (in 3 seconds) and if you also miss the second block because there are more than 10 operators faster than your drand-bot. then your submission only gets included in the block afterwards so +6seconds.

Check Submissions

In order to check the submissions you can visit this Nois randomness dashboard Dashboard This tools shows randomness that was verified on the Nois blockchain. The source of randomness is drand, a decentralized random number generator which produces a so called "random beacon" every 3 seconds. Beacons are submitted as transaction to Nois by off-chain bots. Since beacons are cryptographically signed by drand, bots cannot influence the randomness. A strong and diverse set of bot operator makes the submission of beacons fast and relyable. Bots are incentivised for submissions. They receive a rewards if they are registered and allow-listed.

Badge ColorDescription
GreenBot received a reward
RedBot is registered but did not receive a reward
GrayBot is not eligible for a reward
Check if your bot is allowlisted
  • Navigate to the randomness dashboard
  • On the top right of the page click on info Info
  • Scroll down and check the allowlisted addresses

Incentive System

Drand bots earn incentives by submitting randomness to Nois. A bot gets an incentive if and only if They are among the fastest AND they are allowlisted AND The randomness round has been requested by a dapp

Add Randomness to your Chain

In order to be able to integrate Nois within your blockchain you need to deploy a nois-proxy which plays the role of an outpost contract. Good news, Nois can be integrated with any IBC enabled chain and the process is fully permissionless. The nois-proxy's role when deployed to your chain is to abstract the IBC complexity out of the randomness consumer DAPP.

Steps to integrate Nois to your chain

Decide on a nois-proxy strategy

The nois-proxy that you will deploy belongs to you and not to the Nois chain. Your nois-proxy will have a nois-payment contract at the Nois chain so it can pay for randomness. You need to decide how much dapps need to pay your proxy in prder for the proxy to forward the request to Nois. You can set this price in IBCed NOIS or you can even set the native token of your chain, or even Bitcoin. You cannot set the price of the proxy for free but you can set it extremely low like 1ujuno. If you still want to offer it for free you can fork the proxy code and make it free. Just remember that if you set the price too low some people/dapps can request the randomness from your proxy for a cheap price and end up consuming you $NOIS tokens at the other side (from you nois-payment contract on Nois chain) You are the manager of your proxy so you can at any point in time withdraw part or all the funds that your proxy has accumulated. You can make your proxy part of governance and withdraw the funds to the community pool if you wish. Proxies that use Nois frequently will get in version 0.14.0 discounts. This is not deployed yet but when it will. proxy operators can make money out of the proxying business. This article can help you better understand how the traffic between nois and a consumer chain work


Connect your chain to Nois

By the end of this step you should have an IBC transfer channel between your Chain and Nois, so that you can pay for randomness with NOIS.

  • Configure your relayer software (hermes, go-relayer, ts-relayer) to have Nois and your chain (Check the chain-registry for the details) Tutorial here
  • Create a Client, a connection, and a transfer channel between both chains like this.
  • Check that the channel has been created. You can do so in this IBC mainnet dashboard or testnet dashboard
  • Start the relayer and IBC transfer 1 NOIS from Nois chain to your chain and check the balance (on destination account) in order to get the IBCed NOIS denom. write down the IBC denom as you will need this for a later step.
Install the binary of your chain

For this step you can check the docs for your IBC chain. and atthe end of this step you should be able to run the chain binary. Example:

junod version

navigate to this link and you should find a list of releases. scroll to the latest version and expand the list of artifacts/assets then click and download nois_proxy.wasm

Store the nois-proxy contract code
junod tx wasm store \
       nois_proxy.wasm* \
       --from <your-key> \
       --chain-id uni-6 \
       --gas=auto \
       --gas-adjustment 1.4  \
       --gas-prices 0.025ujunox \
       --broadcast-mode=block \
       --node= -y
instantiate the nois-proxy contract on your chain

The Proxy contract is what will send requests for randomness to Nois Chain via IBC. It will be the central source of randomness that dapps on your chain can send requests to.

Request beacons Receive beacons

instantiation paramaters description:

managerYou can put your address here.
It will allow you to set the proxy config parameters and withdraw any funds held/made by the proxy
pricesThis field will determine how much Dapps need to pay your Proxy Contract when they request randomness. You can set this to whatever denoms and amount you like. When you set multiple denoms they are evaluated with an OR so setting the prices to [1NOIS, 1JUNO] means the dapp needs to pay 1 NOIS OR 1JUNO. For example, if you're using a Payment Mode of mode::IbcPay, you might want to do something like this:

Set Prices to 2 NOIS vec![coin("unois", 55_000_000u32)] For each request a Dapp sends to your Proxy Contract, your Proxy Contract sends 1 NOIS to the gateway for Nois fees, and you profit 5 NOIS for your service!.
Setting this to an empty list will not make the proxy price free but will stop the contract from accepting incoming beacon requests. It can be a way to stop the proxy from serving randomness
Please note that these are not the funds that will be sent over to Nois but only the proxy for the fee. | Vec<Coin> | | test_mode | Just set this to false. This is only set to true for integration testing | Boolean | | callback_gas_limit | The amount of gas that the callback to the dapp can consume.
500000 is a good value if you are not sure. | number | | mode | This defines the operational mode of the proxy:
two modes are available:
- Funded: In this mode you will need to manually make sure that the Nois Payment contract (on Nois Chain) always has enough NOIS tokens to process requests. (Each request costs 1 NOIS). You can think of your Payment Contract as your "Balance Sheet" or like a "Prepaid Nois Gift Card".
- IbcPay: In this mode the proxy contract sends IBCed NOIS to the gateway for each beacon request. You need to whether prefill this contract with NOIS or make sure you set the Nois fee on the prices field so that DAPPs will send the fee upon request. | Enum |

Nois-proxy modes explained

  • Funded Funded
  • IbcPay Receive beacons
junod tx wasm instantiate <CODE_ID>
--from <your-key>
--chain-id uni-6
--gas-adjustment 1.4
--gas-prices 0.025ujunox
--node= -y
Setup the IBC channel for the wasm relay - Transferring the randomness beacon not the tokens
  • choose your relayer software (ts-relayer or hermes or go-relayer).
  • You can create a new IBC client and connection or skip if you want to use the existing connection (the one that has been created for the token transfer).
  • Create an IBC channel where the source is the nois-proxy you have just instantiated on your chain and the destination is the nois-gateway on the Nois chain (the direction is important). When creating the channel Make sure to use the wasm port.

    ℹ️ If the nois-gateway address is nois1x55xhexprdwfl6nfju53hfxj77nsxlj5c9jzyvjuastl9f3dt6jsx6l9yg then the port will be wasm.nois1x55xhexprdwfl6nfju53hfxj77nsxlj5c9jzyvjuastl9f3dt6jsx6l9yg

  • Upon channel connection/creation the nois-gateway factory creates a payment contract for your proxy on the Nois chain. This payment contract will be your balance sheet. So long as the payment contract has enough balance your proxy will be able to request randomness beacon. So make sure the payment contract does not run out of $NOIS.
  • Check that the channel has been created. You can do so in this IBC mainnet dashboard or testnet dashboard
  • Run the relayer and ask others to run their relayers aswell.
  • If the proxy mode is on IbcPay make sure to fill the proxy with IBCed NOIS tokens. (every beacon request will consume $1 NOIS). else if the proxy is on Funded mode then make sure the payment contract is filled with NOIS tokens.
  • For performance reasons when using IbcPay mode, it is a good idea to have some initial 1 $NOIS on the payment, this allows to gateway to process the beacon even when the ibc token transfer is slower than the beacon request wasm packet.
  • If you need some NOIS tokens for your payment contract you can contact us on discord and describe your usecase so that we give you a NOIS grant
  • Congrats πŸŽ‰ you can use the proxy on your Dapp to get randomness. You can follow use_nois_randomness page for more details.

Step By Step Guide to Randdrop

First things first, a randdrop is simply an airdrop with a final touch of randomness to it. Meaning that not all preeligible wallets will get tokens but only a random subset that will earn a larger portion of airdrop.

This randdrop aproach is used by Nois to airdrop NOIS tokens to other IBC blockchains but also any other protocol wishing to make a randdrop using Nois instead of a standard airdrop can follow this guide to randrop their tokens to some community.

How it works

A randdrop contract gets instantiated in any wasm-ibc chain (i.e the chain to airdrop tokens to). The operator takes a snapshot of the chain in order to get a state in time with the addresses to airdrop to with the respective amounts. This snapshot is pretty much a json file like this file. Then you merkelise the file(a tree of cryptographic hashes), and feed the merkle root to the randdrop contract. Then the operator (person who is in charge of managing the airdrop) communicates the file to the community (twitter for example). Users can participate for a chance to win by checking the public json file containing what addresses are pre-eligible, compute their merkle proof (the webapp UI does that for them) and send the proof to the randdrop contract which request a random beacon from Nois. Upon reception of the randomness, an account has 1/3 of probability to receive the randdrop. This is interesting because it allows protocols to target with their airdrop a bigger number of communities/networks without diluting as much the airdrop amount per account.

Why Merkle trees

We aimed for a merkle randdrop because it is more elegant, cost efficient, safer and not spammy. When doing merkle randdrop you don't send tokens to all wallets, instead users who are interested will come to claim your token. This is good for many reasons:

  • Legals: Companies in certain countries don't have to justify this token that they didn't even want to claim.
  • Gas fees: Users will claim their tokens so the operator doesn't have to spend a big amount to airdrop to all these users
  • performance and efficiency: The computation is done offchain on the browser of the user to calculate the merkle proof, and the contract doens't have to hold the data containing who gets what airdrop, instead the contract only holds the merkle root which is just a small hash.
  • No waste: Tokens that are not claimed can be used for another airdrop to other community users who want it. so you can targer a larger community

Why randdrop not airdrop

  • With randdrop you can target even larger communities without diluting as much the claimed token. because a smaller subset withing a community gets a larger amount.
  • It is more fun when there is the surprise effect.

Step by Step

  • You need to export and process the snapshot
  • you need to deploy the contract

You can find the details for each step in the next pages

Randdrop Snapshot

Export the snapshot

The goal of this step is to get a list of addresses to make eligible for the randdrop. In this example we're going to airddrop to juno-1 network delegators

  • First you need to install junod
  • Run and sync a junod node
  • make a snapshot (i.e get the state ofthe chain at a specific height). ps: I did this step with 60GB of memory (RAM+SWAP) and it can take few hours tofinish
junod export --height 8372000  > juno-8372000.json

This step will leave you with a big juno-8372000.json file that contains all the state. Let's filter it out to get only the juno stakers.

Process the snapshot

Get the stakers list

cat juno-8372000.json \
| jq '[.app_state.staking.delegations | group_by(.delegator_address) | map({address: .[0].delegator_address, amount: (map(.shares | tonumber) | add)})][0]' \
| jq 'sort_by(-.amount)' \
> juno-8372000-stakers.json

now we are left with this juno-8372000-stakers.json file that holds juno stakers and the amount they have staked at block height 8372000.

We want to filter out accounts that have less than $4USD (at the time of writing juno is worth $0.5 so let's filter out all wallets with less than 8juno staked). Also there might be wallets with huge amounts, let's say that we want to make a max cap on $40K airddrop so wallets with $40K staked or more will get the same amount

cat juno-8372000-stakers.json \
|jq '[.[] | select(.amount >= 8000000)]' \
| jq 'map(if .amount > 80000000000 then .amount = 80000000000 else . end)'  \
> juno-8372000-stakers-between-8-and-80K.json

This leaves us with a juno-8372000-stakers-between-8-and-80K.json json file.

Now the amounts are in juno so you might wanna multiply them by how much you want to give on your airdrop token per ujuno.

In this case, we want to airdrop 2,6M NOIS to juno chain. This means we want to airdrop 0.07340892389 unois per ujuno

To calculate the conversion rate you might want to check the total amount of the staked token

cat juno-8372000-stakers-between-8-and-80K.json | jq '[.[].amount] | add'

Then divide the total amount you want to randdrop by the total amount staked. Let's say the total juno staked amount was 35M and we want to distribute 2.6M, CONVERSION_RATE=2.6M/35M

Once you figure out what conversion rate to apply you can extract the final json file in the token you want to randdrop

 export CONVERSION_RATE=0.07340892389
 cat juno-8372000-stakers-between-8-and-80K.json \
 | jq --argjson multiplier $CONVERSION_RATE 'map(if .amount | type == "number"   then .amount |= (. * $multiplier | floor)  else .  end)' \
 > juno-randdrop.json

This will leave us with the final juno-randdrop.json file to communicate and merkelise in the next section

Deploying the randdrop

Generate the merkle root

 merkle-airdrop-cli generateRoot --file juno-randdrop.json

Ouptut: 73d8ae84dddb8f99f08ecf141d0fb7d65fe8af7a2e4aeb7d6714f985d945851f

Make sure Nois is connected tou your chain

Check if there is a nois-proxy already on your chain to use it for the randomness. If there is no proxy you can create one yourself by following the #integrate_nois_to_your_chain_section in these docs. If you have a nois-proxy you can go ahead and move to the next step

compile, store and instantiate the randdrop contract

# This repo contains nois example contracts including the randdrop contract
 git clone
 cd nois-contracts


# This command will generate wasm files

Make sure that you have now a wasm file in this path

ls target/wasm32-unknown-unknown/release/nois_airdrop.wasm


junod tx wasm store target/wasm32-unknown-unknown/release/randdrop.wasm   \
--from deployment-key \
--chain-id=uni-6  \
--gas-prices 0.025ujunox \
--gas=auto --gas-adjustment 1.4  \
--broadcast-mode=block --node=


junod tx wasm instantiate2 1935 \
'{"manager":"juno1q6yvx8lxpheqflkcl0qf89czej4akrsfzc6xs2", "nois_proxy_address":"juno1pjpntyvkxeuxd709jlupuea3xzxlzsfq574kqefv77fr2kcg4mcqvwqedq","nois_proxy_denom":"ibc/717352A5277F3DE916E8FD6B87F4CA6A51F2FBA9CF04ABCFF2DF7202F8A8BC50","nois_proxy_amount":"50000000","randdrop_denom":"ibc/717352A5277F3DE916E8FD6B87F4CA6A51F2FBA9CF04ABCFF2DF7202F8A8BC50","merkle_root":"73d8ae84dddb8f99f08ecf141d0fb7d65fe8af7a2e4aeb7d6714f985d945851f", "test_mode":true}' 01 \
--label=randdrop --admin juno1q6yvx8lxpheqflkcl0qf89czej4akrsfzc6xs2 -\
-from deployment-key \
--chain-id uni-6 \
--gas=auto --gas-adjustment 1.2 --gas-prices=0.025ujunox \
--broadcast-mode=block --node=

Send the tokens to airdrop to the contract

The before the claiming can start you need to send the tokens to airdrop to the contract. Otherwise the contract won't be able to give the tokens to users that want to claim the randdrop

Claiming phase

Claim from the cli

Calculate the merkle proof from the

  • juno-8372000-stakers-between-8-and-80K.json json file
  • The address that will claim (needs to be in the file)
  • the amount that the address holds (needs to match what's on the file )
merkle-airdrop-cli generateProofs \
--file juno-randdrop.json \
--address juno1etltrk88jyye62lynfd8e8zhnu0lxd9udsk8fc \
--amount 74711941



Participate in the randdrop by providing the proof

junod tx wasm execute juno14tfzmpl6kw2e6lyqzsvjgcqu7a9jhsneu0u4nvdv6znulps6xufqwlw2xf \
    --from main \
    --chain-id uni-6 \
    --gas=auto --gas-adjustment 1.4 --gas-prices=0.025ujunox \
    --broadcast-mode=block \

As soon as the randomness is published the relayer will trigger the contract and give the winner participant their airdrop

Claim from the UI

We can't expect every user to use the cli to claim their randdrop so you can just use a UI like Nois randdrop UI to get the address from keplr, check the randdrop eligibility, computes the merkle proof and executes the contract to claim the randdrop