Quickstart

This guide will introduce the flow of using the airdrop SDK library.

Prerequisite:

Add the SDK to your repository:

npm i @uniblock/launcher-airdrop @openzeppelin/merkle-tree

or

yarn add @uniblock/launcher-airdrop @openzeppelin/merkle-tree

Step 1: Initialize the SDK:

To initialize the SDK, you must first create an airdrop contract through the Uniblock dashboard. Then you have to provide a Uniblock API key which can be found after creating a project on the site. Then copy the address chain ID of your deployed contract and pass them into the initialize function with your Uniblock API key:

  • Nodejs:
import { initializeAirDrop } from "@uniblock/launcher-airdrop"

const uniblockApiKey = <YOUR_UNIBLOCK_API_KEY>
const contractAddress = <YOUR_AIRDROP_CONTRACT_ADDRESS>
const chainId = <YOUR_CHAIN_ID>
const option = {
    rpc: <YOUR_RPC_URL> // You can assign your own rpc url
}

const airdropSdk = await initializeAirDrop(uniblockApiKey, {contractAddress, chainId}, option)
// or if you don't have your own rpc url, you can use uniblock sdk default url
// and use the following code:
// const airdropSdk = await initializeAirDrop(uniblockApiKey, {contractAddress, chainId})
// also chainId is optional and the default chainId of the following code will be 1:
// const airdropSdk = await initializeAirDrop(uniblockApiKey, {contractAddress})
  • Web browser
<script type="module">
    import { initializeAirDrop } from "https://cdn.jsdelivr.net/npm/@uniblock/launcher-airdrop/index.esm.min.js"
    const uniblockApiKey = <YOUR_UNIBLOCK_API_KEY>
    const marketplaceContractAddress = <YOUR_CONTRACT_ADDRESS>
    const chainId = <YOUR_CHAIN_ID>
    const option = {
        rpc: <YOUR_RPC_URL> // You can assign your own rpc url
    }
    
    const airdropSdk = await initializeAirDrop(uniblockApiKey, {contractAddress: marketplaceContractAddress, chainId}, option)
</script>

Step 2: Create a Signer instance

We first need to create a signer:

  • Nodejs:
const provider = new ethers.providers.JsonRpcProvider("RPC_URL", 5);
// needs the RPC Url of the specific chain, which can be found on chainlist:
// https://chainlist.org/chain/5
const signer = new ethers.Wallet("WALLET_PRIVATE_KEY", provider);
  • Web browser:
import { initializeWagmi } from "@uniblock/wagmi"
const chainId = <CHAIN_ID>
const wagmi = await initializeWagmi(uniblock_api_key);
const { chains, provider, webSocketProvider } = wagmi.configureChains([chainId]);
const client = wagmi.createClient(
  provider,
  webSocketProvider,
  chains,
  [
    connector.METAMASK_CONNECTOR,
  ],
);
await wagmi.connectWallet(client, connector.METAMASK_CONNECTOR);
const signer = await wagmi.getSigner();

Note: To use the wagmi, install it through yarn add @uniblock/wagmi or npm install @uniblock/wagmi

Step 3: Ensure allowance

Next, ensure the supplied token contract allows the airdrop contract to transfer the fees during the call of the registerTree method. This can be done by going to Etherscan to call the increaseAllowance method or by running the following code:

// increase allowance for fee token
const amount = await airdrop.getFee()
const feeToken = await airdrop.getFeeToken()
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
if(feeToken !== ZERO_ADDRESS){
    const allowance = await airdrop.getAllowance(feeToken, await signer.getAddress())
    if(allowance.lt(amount)){
        const feeIncrementAllowance = amount.sub(allowance).toString()
        await airdrop.increaseAllowance(feeToken, feeIncrementAllowance, signer)
    }
}


// increase allowance for the transferred token
const tokenAddress = <YOUR_CRYPTO_TOKEN>
const supply = amounts.reduce((acc, curr) => acc + curr)
// assume amounts store the amount of token for each recipient in an airdrop
if(tokenAddress !== ZERO_ADDRESS){
    const allowance = await airdrop.getAllowance(tokenAddress, await signer.getAddress())
    if(allowance.lt(supply)){
        const transferIncrementAllowance = supply.sub(allowance).toString()
        await airdrop.increaseAllowance(tokenAddress, transferIncrementAllowance, signer)
    }
}

Step 4: Create an airdrop

For users who want to start an airdrop in the contracts, run the following code:

// step 1: get tree root
import { StandardMerkleTree } from "@openzeppelin/merkle-tree"

const calculateERC20Tree = (recipients, amounts) => {
  if (recipients.length !== amounts.length) {
    throw new BadRequestException('Recipients and amounts mismatched length');
  }
  const treeValues = recipients.map((recipient, i) => [recipient, amounts[i]]);
  const tree = StandardMerkleTree.of(treeValues, ['address', 'uint256']);
  return { tree: JSON.stringify(tree.dump()), root: tree.root };
};

const recipients = [<RECIPIENT_ADDRESS>]
const amounts = [3] 
const {tree, root} = calculateERC20Tree(recipients, amounts)

// step 2: run register tree method to store token:
const tokenAddress = <YOUR_CRYPTO_TOKEN>
const amount = amounts.reduce((acc, curr) => acc + curr);
const supply = (tokenAddress === feeToken ? amount + await airdrop.fee() : amount)
// startTime and endTime are Unix time epoch where current time is between startTime and endTime
await airdrop.registerTree(tokenAddress, supply, startTime, endTime, root)

// step 3: Get the id of the airdrop you just created
const id = await airdrop.getAirdropCount()

Step 5: Claim the airdrop

To allow users to claim their tokens, run the following after initializing the SDK instance:

// step 1: pass the tree from the code snippet above to obtain the proof
const getUserAirdrop = (storedTree, recipient) => {
  const tree = StandardMerkleTree.load(storedTree);
  for (const [i, [address, amount]] of tree.entries()) {
    if (address === recipient) {
      return {
        recipient,
        amount,
        proof: tree.getProof(i),
      };
    }
  }

  throw new NotFoundException('User not found in Airdrop');
};
// variable tree is obtained from calculateERC20Tree in the above code snippet
const { proof, amount } = getUserAirdrop(JSON.parse(tree), recipients[0])


// step 2: call claim
await airdrop.claim(
    walletAddress, // walletAddress must be an address from recipients in the above code snippet
    id,            // id is the get from getAirdropCount in the above code snippet
    amount.toString(),        // if walletAddress is the i^{th} element of recipients, then amount is amounts[i] in above code snippet
    proof, 
    signer
)