In this tutorial we will be creating a SEP-41 token and distributing it to a curated list of recipients using a merkle tree.

We will start by collecting a list of addresses who are currently using Stellar’s SDEX, then we will form these into a merkle tree and store the merkle root and proofs (more on how this works below).
We will then deploy a SEP-41 token contract using OpenZeppelin standards with a built in claim function so those wallets that previously interacted with SDEX can claim their tokens.
Finally we will put together a little frontend to provide a user interface for our lucky recipients. Lets go.
All the code is open-source and available on Github: https://github.com/jamesbachini/Stellar-Airdrop-Token
I’ll be using OpenZeppelin libraries for this which were originally based on the work by Philip Liu.
Curating The Airdrop Recipients
There are a million and one ways you can put together a list of recipients. I decided to use Stellar SDEX users as I had some code I had used previously which could be modified.
git clone https://github.com/jamesbachini/Stellar-Airdrop-Token.git
cd build-list
cargo run
This will output a list of SDEX users and there is a hard coded amount value in the build-list/src/main.rs file which includes decimals. You can adjust this if you have different criteria or factors influencing how much each users gets.
The script will output a JSON file in the following format:
[
{
"address": "GCCVUYBUSWH4H3RTBPWEY63SGHUDIHHGGJCFLCQOWFYFWD2FSRZOQVC7",
"amount": 1000000000
},
{
"address": "GCX3AXMOAISB2ET4EVU2E2GVR332HQYBMCGAXS5TNOHSJDK4NMQPQRVJ",
"amount": 1000000000
}
]
Once we have our recipient list we can build the merkle tree.
Creating A Merkle Tree
Merkle trees are used to verify large amounts of data on-chain. Because decentralized storage is relatively expensive we can store a single hash known as the merkle root. And then users can submit proofs which are delivered via a web app or elsewhere to prove their address is included in the airdrop.

Let’s copy our recipient list in and generate the merkle root hash and list of proofs.
cd merkle
cargo run -- ../build-list/sdex-traders.json proofs.json
Here we are passing in the list of recipients in sdex-traders.json and output a merkle root to the console and the proofs to a proofs.json file.
Now let’s deploy the token contract.
Deploy An Airdrop Token
Note. This uses the OpenZeppelin Merkle_Distributor library which is not audited yet and still under security review.
The claim function is below.
pub fn claim(e: &Env, index: u32, receiver: Address, amount: i128, proof: Vec<BytesN<32>>) {
receiver.require_auth();
let data = Receiver { index, address: receiver.clone(), amount };
Distributor::verify_and_set_claimed(e, data, proof);
Base::mint(e, &receiver, amount);
}
So we are sending across our address, the amount and the proofs (as a vector). We then check to ensure the receiver is who they say they are with require_auth(). Then we check the data and proofs before minting the tokens direct to the recipients wallet.
We can deploy this to testnet using the stellar-cli

Note the way we pass in the merkle root as a named constructor argument after a — separator.
Creating A Web3 UI
This UI is based forked from Philip Liu’s example here.
We need to update frontend/.env.example and save it as .env
When adding the proofs.json data I flattened the file removing any whitespace and line breaks.
I also added the contract address to frontend/src/packages/contract.ts
You can run this locally with
cd frontend/
npm install
npm run dev

Go ahead and claim some tokens but only if your address is in that merkle tree.