Allowlists
Allowlists are an efficient way to enable distribution of hypercert fractions amongst a group.
First, the creator will create the hypercert with the metadata and an immutable allowlist.
With the claimId
, every account specified in the allowlist can later mint their fraction token from that allowlist.
Allow list format
The allowlist is a list of addresses and the number of units they should receive. The list can be provided in three formats:
- As a string (URI)
- As a string (Merkle tree dump)
- As an array of
AllowlistEntry
objects (in code)
When using the hypercerts infrastructure, we expect allowlists and hypercerts to be created with a total supply of 100_000_000 units. We find this to be a good default for most use cases by supporting tokens with 6 decimal places for reasonable pricing and a large enough supply for splitting fractions for most use cases.
Allow list as a string (URI)
The allowlist is stored as a CSV file in IPFS. The file must have two columns:
address
- The address of the receiverunits
- The number of units the receiver should receive
The CSV file must be encoded as a UTF-8
encoded CSV file.
You can find a template for the allowlist here.
Allow list as a string (Merkle tree dump)
You can also pass the merkle tree dump to the minting method. This allows you to parse the allowlist data in any manner you prefer but ending up with the same merkle tree root.
Review the OpenZeppelin Merkle tree library for more information on the Merkle tree dump format.
Allow list as an array of AllowlistEntry
objects
You can also pass the allowlist as an array of AllowlistEntry
objects. This is the most flexible way to specify the allowlist but also the most verbose.
import { AllowlistEntry } from "@hypercerts-org/sdk";
const allowlist: AllowlistEntry[] = [
{ address: "0x123....asfcnaes", units: 50_000_000n },
{ address: "0xabc....w2dwqwef", units: 50_000_000n },
];
Mint an hypercert with an allowlist
The mintHypercert
method in the HypercertClient
allows you to mint new hypercerts, optionally with an allowlist. This documentation focuses on the allowlist functionality and the underlying business logic.
First specify an allowlist, mapping addresses to the number of units they should receive.
import {
TransferRestrictions,
formatHypercertData,
AllowlistEntry,
} from "@hypercerts-org/sdk";
const allowlist: AllowlistEntry[] = [
{ address: "0x123....asfcnaes", units: 100n },
{ address: "0xabc....w2dwqwef", units: 100n },
];
const { metadata } = formatHypercertData(...);
const totalUnits = 100_000_000n;
const transferRestrictions = TransferRestrictions.FromCreatorOnly
const txHash = await client.mintHypercert({
allowList,
metaData,
totalUnits,
transferRestrictions: TransferRestrictions.FromCreatorOnly,
});
1. Allow list processing
The SDK supports processing of different allowlist formats.
If allowList
is a string (URI):
- The content is fetched using
fetchFromHttpsOrIpfs
- The system attempts to parse it as an OpenZeppelin Merkle tree dump
- If parsing fails, it tries to parse it as a CSV file
If allowList
is a string (Merkle tree dump):
- The content is directly processed into a Merkle tree
If allowList
is an array of AllowlistEntry
objects:
- We validate the total units and addresses
- It's directly processed into a Merkle tree
Get the root
- The resulting Merkle tree is used to generate a root for the allowlist
2. Metadata upload
The metadata and allowlist are stored on IPFS by relaying the data to our API which validates the content and uploads it to IPFS.
We store the allowlist as a dump of the OpenZeppelin Merkle tree. To understand the Merkle tree generation and data structures, check out the OpenZeppelin merkle tree library
3. Minting
If an allowlist is specified, the SDK will call the createAllowlist
function on the contract with the appropriate parameters. The SDK will return the transaction hash for further processing as you find helpfull.
We recommend using a method similar to viem's
waitForTransactionReceipt
to wait for the transaction to be processed. We also provide thegetClaimStoredDataFromTxHash
to parse the transaction logs and return the data from theClaimStored
event.
Claiming a fraction using an allowlist
Users can claim their fraction tokens for many hypercerts at once using claimFractionFromAllowlist
. A fraction is claimed by providing the claimId
, the units
and the proof
that the address is in the allowlist.
Getting merkle proofs for an address
Merkle proof can be fetched from the allowlist stored on IPFS. While this is nice for the purists, we also provide access to allow list entries using our Graph.
To get all allowlist entries for a given account you can run the following query on our graph:
query getAllowListRecordsForAddress($address: String!) {
allowlistRecords(where: {user_address: {contains: [$address]}}) {
count
data {
proof
root
hypercert_id
token_id
units
user_address
claimed
}
}
}
For a full implementation see
getAllowListRecordsForAddressByClaimed
in the hypercerts app.
Submit the claim
By submitting the user's address, the number of units contained in their fraction and the proof, the user can claim their fraction of an hypercert. When a root is not provided, the contract will catch invalid proofs. It's faster to provide the root before so we can validate in the SDK.
const txHash = await client.claimFractionFromAllowlist(
hypercertTokenId,
units,
proof,
root);
Note that the
hypercertTokenId
refers to the actualtokenId
in the minting contract, which is the third part of the hypercert ID. For example for hypercert ID11155111-0xa16DFb32Eb140a6f3F2AC68f41dAd8c7e83C4941-222544667966293755105046993260376410292224
the hypercertTokenId is222544667966293755105046993260376410292224
Claiming via the hypercerts app
By using the Profile view in the hypercert app you can easily claim allowlist fractions. Simply connect your wallet in our app and navigate to your profile. You will see a list of all your claimable fractions under Claimable.