Add email airdrop Motoko demo#4044
Draft
aterga wants to merge 3 commits into
Draft
Conversation
A small demo canister that airdrops 1 ICP to each user who emails
airdrop@<domain> with a valid request.
Eligibility (all required):
- ICP address (64-hex account identifier, checksum-verified) in the Subject
- at least one Cc with a friend's address
- body contains the app link and a participation phrase (substring checks,
since mail clients append footers/signatures)
Other behaviour:
- one airdrop per email address, ever
- rewards paid while funds last; otherwise senders join a FIFO waitlist that
is drained automatically (timer) or on demand (triggerWaitlist) after a
top-up
- every attempt is stored: email_address -> last_rewarded_at_timestamp
Since the IC has no inbound SMTP, the intended wiring is an inbound-email
provider (SendGrid/Mailgun/Cloudflare Email Worker) that POSTs the raw message
to the canister's http_request_update endpoint (secret-guarded). A typed
submitEmail entrypoint exercises the same logic locally. The landing page
(GET /) shows the rules.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mm4BEJjsY8qctP4x8sU1Ju
The repo's format-check step runs Prettier over `demos`; reformat the README so it matches Prettier's style. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mm4BEJjsY8qctP4x8sU1Ju
aterga
commented
Jun 19, 2026
Per review: prefix the sample Subject with "Airdrop invite " so it also demonstrates that the ICP address is extracted as a token from within the subject, not required to be the entire subject. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mm4BEJjsY8qctP4x8sU1Ju
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A small self-contained Motoko demo (
demos/email-airdrop/) that airdrops 1 ICP to each person who emailsairdrop@<your-domain>with a valid request.The rules (shown on the landing page,
GET /)An email is eligible when all hold:
Ccwith a friend's address (a valid address that isn't the sender's).Plus: one airdrop per email address, ever; rewards are paid while funds last, otherwise the sender joins a FIFO waitlist that drains automatically (a timer) or on demand (
triggerWaitlist) after a top-up; and every attempt is stored (email_address → last_rewarded_at_timestamp, attempt count, last outcome).The key design point: canisters can't receive SMTP
There is no inbound mail server on the IC, so
airdrop@<domain>can't be served by the canister directly. The intended wiring is an inbound-email provider (SendGrid Inbound Parse / Mailgun Routes / Cloudflare Email Worker) that POSTs the raw message to the canister'shttp_request_updateendpoint (guarded by a shared secret, and ideally carrying the provider's DKIM verdict). A typedsubmitEmailentrypoint runs the same logic for local testing. This is all laid out in the README.Files
main.mo— thepersistent actor(eligibility, CRC32 address validation, ledgertransfer, waitlist, timer, HTTP gateway + rules page).icp.yaml— deploys it via the@dfinity/motokorecipe.README.md— rules, architecture diagram, run/test instructions, threat model, and open questions.sample-email.txt— a ready-to-POST raw message (with a checksum-valid address).Verification
Type-checked and compiled to Wasm against
mo:base, and the trickiest pieces were exercised in the Motoko interpreter:Cca different friend passes,Cconly yourself / empty fails;Name <addr>and comma-separated Cc).Open questions (also in the README)
This is a demo, intentionally not hardened. A few choices worth your call before going further: address format (legacy account id vs ICRC-1), one-time vs cooldown rewards, whether the Cc'd friend is a referral, requiring DKIM
pass, and timer-poll vs operator-driven waitlist draining. Questions and suggestions very welcome.🤖 Generated with Claude Code
Generated by Claude Code