diff --git a/resources/images/airdrop-dark.svg b/resources/images/airdrop-dark.svg new file mode 100644 index 000000000..727155ff5 --- /dev/null +++ b/resources/images/airdrop-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/airdrop-light.svg b/resources/images/airdrop-light.svg new file mode 100644 index 000000000..05a10d01c --- /dev/null +++ b/resources/images/airdrop-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/merkle_claim_dark.svg b/resources/images/merkle_claim_dark.svg deleted file mode 100644 index 043946112..000000000 --- a/resources/images/merkle_claim_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/merkle_claim_light.svg b/resources/images/merkle_claim_light.svg deleted file mode 100644 index 3f0fc06e0..000000000 --- a/resources/images/merkle_claim_light.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/standard/tokens/airdrop.mdx b/standard/tokens/airdrop.mdx index 571eaa306..18ad3c166 100644 --- a/standard/tokens/airdrop.mdx +++ b/standard/tokens/airdrop.mdx @@ -7,7 +7,7 @@ import { Image } from '/snippets/image.jsx'; ## The problem: distributing at scale -You want to reward thousands (or millions) of users. Sending assets to each address proactively looks simple-until you see the bill. Network fees add up fast when the sender pays for every transfer. +Rewarding thousands (or millions) of users by sending assets to each address proactively looks simple until the network fees add up. Network fees scale fast when the sender pays for every transfer. ## The twist: let users claim @@ -18,44 +18,90 @@ The straightforward approach is to keep a precomputed mapping of recipient → a claim -## The naive approach-and its limit +## The naive approach and its limit -Keep a precomputed mapping of recipient → allocation in the contract. When a user sends a claim message, the contract releases the preassigned amount. This works until the list becomes too large, starting at roughly 3,000 entries, problems begin to surface with the external limit (see more in [limits](/foundations/limits#message-and-transaction-limits)). +Keep a precomputed mapping of recipient → allocation in the contract. When a user sends a claim message, the contract releases the preassigned amount. This works until the list becomes too large. Starting at roughly 3,000 entries, problems begin to surface with the external limit (see more in [limits](/foundations/limits#message-and-transaction-limits)). -## The scalable design: shard and prove +## Scalable airdrop architecture -To scale, we split the state across many contracts ([contract sharding](/contract-dev/contract-sharding)) and keep only a compact commitment to the list on-chain: a root hash of a dictionary (see [hashmap](/languages/tl-b/complex-and-non-trivial-examples#hashmap)). Users then present a [Merkle proof](/foundations/proofs/overview) to claim. +A scalable airdrop consists of two independent modules: -We must also prevent double-claims. The airdrop has a small per-user marker contract that records whether the user has already claimed. This marker blocks any subsequent attempts. +1. Double-claim prevention ensures each user can claim only once +1. Eligibility verification proves the user is entitled to claim a specific drop - +### Double-claim prevention -## How to prepare +#### Markers + +The airdrop has a small per-user marker contract that records whether the user has already claimed. This marker blocks any subsequent attempts. + +### Eligibility verification + +#### Merkle proof + +The airdrop contract stores a root hash of a dictionary (see [hashmap](/languages/tl-b/complex-and-non-trivial-examples#hashmap)) containing all allocations. Users present a [Merkle proof](/foundations/proofs/overview) to verify their allocation against this root. + +On-chain state: + +- Root hash (256 bits) + +How to prepare: 1. Prepare a list of eligible recipients and their allocations, and construct a dictionary. 1. Store the root hash in the airdrop contract. -1. Provide each user with their [Merkle proof](/foundations/proofs/overview) (or enable self-service proof retrieval). +1. Provide each user with their Merkle proof. + +#### Signed proof + +The airdrop contract stores a backend public key. The backend signs authorization messages for eligible users. Users present the signature to claim. + +On-chain state: -## Claim flow +- Backend public key (256 bits) -1. The user sends a message that deploys their per-user marker contract along with their Merkle proof. -1. If valid, the marker records that the claim has been made and rejects further requests. -1. The airdrop contract verifies the [Merkle proof](/foundations/proofs/overview) and transfers the asset to the address specified in the proof. +How to prepare: + +1. Deploy airdrop contract with backend public key. +1. Backend validates eligibility criteria on demand. +1. Backend signs authorization messages for eligible users. + +For signature implementation details and security considerations, see [signing messages](/contract-dev/signing). + +### Claim flow + +The claim process combines both modules. + +1. User sends a message that deploys their marker contract along with proof. +1. Marker contract checks it has not been deployed before (double-claim prevention). +1. Airdrop contract verifies proof (eligibility verification). +1. Airdrop contract transfers assets to recipient. Merkle claim +### Choosing an approach + +Merkle proof fits when: + +- Trustless, verifiable distribution is required. +- Eligibility list is static or changes infrequently. +- Backend control over claims is not desired. + +Signed authorization fits when: + +- Eligibility rules change frequently or depend on external data. +- Trust in the backend is acceptable (centralized projects, known organizations). +- Lower gas costs per claim are a priority. + ## Examples -- cNFT +- [cNFT](/standard/tokens/nft/comparison#cnft) - [Mintless Jetton](/standard/tokens/jettons/mintless/overview) diff --git a/standard/tokens/nft/comparison.mdx b/standard/tokens/nft/comparison.mdx index 77e45b0da..1294a5a39 100644 --- a/standard/tokens/nft/comparison.mdx +++ b/standard/tokens/nft/comparison.mdx @@ -32,7 +32,7 @@ Short overview: ### cNFT -A cNFT (compressed NFT) combines a [standard NFT](/standard/tokens/nft/overview) with an [airdrop‑style distribution](/standard/tokens/airdrop), optimized for large distributions and for shifting minting costs from the creator to end users via [Merkle‑proof](/foundations/serialization/merkle)‑based self‑deployment. NFT items are self‑deployed by users using Merkle proofs instead of [airdrop markers](/standard/tokens/airdrop#the-scalable-design%3A-shard-and-prove). +A cNFT (compressed NFT) combines a [standard NFT](/standard/tokens/nft/overview) with an [airdrop‑style distribution](/standard/tokens/airdrop), optimized for large distributions and for shifting minting costs from the creator to end users via [Merkle‑proof](/foundations/serialization/merkle)‑based self‑deployment. NFT items are self‑deployed by users using Merkle proofs instead of [airdrop markers](/standard/tokens/airdrop#markers). ### Additional: Royalty