From 12aceef4ca03a504bba3e46ef61d0f81fb7b6ac6 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Wed, 4 May 2022 11:44:24 -0400 Subject: [PATCH] Allow clients to create manalinks --- common/manalink.ts | 10 ++++----- firestore.rules | 5 +++++ web/lib/firebase/manalinks.ts | 40 +++++++++++++++++++++++++++++++++++ web/package.json | 1 + web/pages/send.tsx | 35 ++++++++++++++++++++++++++++++ yarn.lock | 5 +++++ 6 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 web/lib/firebase/manalinks.ts create mode 100644 web/pages/send.tsx diff --git a/common/manalink.ts b/common/manalink.ts index c48bebe0..9aa2a73f 100644 --- a/common/manalink.ts +++ b/common/manalink.ts @@ -1,6 +1,6 @@ export type Manalink = { // The link to send: https://manifold.markets/send/{slug} - // Also functions as the unique identifier for the link. + // Also functions as the unique id for the link. slug: string // Note: we assume both fromId and toId are of SourceType 'USER' @@ -11,10 +11,10 @@ export type Manalink = { token: 'M$' // TODO: could send eg YES shares too?? createdTime: number - // If not set, the link is valid forever - expiresTime?: number - // If not set, the link can be used infinitely - maxUses?: number + // If set to Infinity, the link is valid forever + expiresTime: number + // If set to Infinity, the link can be used infinitely + maxUses: number // Successful redemptions of the link successes: Claim[] diff --git a/firestore.rules b/firestore.rules index 28e03e64..a24d156a 100644 --- a/firestore.rules +++ b/firestore.rules @@ -85,5 +85,10 @@ service cloud.firestore { match /txns/{txnId} { allow read; } + + match /manalinks/{slug} { + allow read; + allow create, update: if request.auth.uid == request.resource.data.fromId; + } } } diff --git a/web/lib/firebase/manalinks.ts b/web/lib/firebase/manalinks.ts new file mode 100644 index 00000000..bd795035 --- /dev/null +++ b/web/lib/firebase/manalinks.ts @@ -0,0 +1,40 @@ +import { setDoc } from 'firebase/firestore' +import { doc } from 'firebase/firestore' +import { Manalink } from '../../../common/manalink' +import { db } from './init' +import { customAlphabet } from 'nanoid' + +export async function createManalink(data: { + fromId: string + amount: number + expiresTime: number + maxUses: number +}) { + const { fromId, amount, expiresTime, maxUses } = data + + // At 100 IDs per hour, using this alphabet and 8 chars, there's a 1% chance of collision in 2 years + // See https://zelark.github.io/nano-id-cc/ + const nanoid = customAlphabet( + '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + 8 + ) + const slug = nanoid() + + if (amount <= 0 || isNaN(amount) || !isFinite(amount)) + return { status: 'error', message: 'Invalid amount' } + + const manalink: Manalink = { + slug, + fromId, + amount, + token: 'M$', + createdTime: Date.now(), + expiresTime, + maxUses, + successes: [], + failures: [], + } + + const ref = doc(db, 'manalinks', slug) + await setDoc(ref, manalink) +} diff --git a/web/package.json b/web/package.json index d29a01b5..dbc5bfb7 100644 --- a/web/package.json +++ b/web/package.json @@ -29,6 +29,7 @@ "gridjs": "5.0.2", "gridjs-react": "5.0.2", "lodash": "4.17.21", + "nanoid": "^3.3.4", "next": "12.1.2", "react": "17.0.2", "react-confetti": "^6.0.1", diff --git a/web/pages/send.tsx b/web/pages/send.tsx new file mode 100644 index 00000000..9408a4c3 --- /dev/null +++ b/web/pages/send.tsx @@ -0,0 +1,35 @@ +import { Page } from '../components/page' +import { SEO } from '../components/SEO' +import { useUser } from '../hooks/use-user' +import { createManalink } from '../lib/firebase/manalinks' + +export default function SendPage() { + const user = useUser() + + return ( + + + +

Send Mana

+ {user && ( + + )} +
+ ) +} diff --git a/yarn.lock b/yarn.lock index dfcb2a69..fe279b5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3793,6 +3793,11 @@ nanoid@^3.1.30: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"