basic working payments
This commit is contained in:
parent
0a4e05ad32
commit
ad7be5449d
|
@ -16,7 +16,8 @@
|
|||
"fetch": "1.1.0",
|
||||
"firebase-admin": "10.0.0",
|
||||
"firebase-functions": "3.16.0",
|
||||
"lodash": "4.17.21"
|
||||
"lodash": "4.17.21",
|
||||
"stripe": "8.194.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"firebase-functions-test": "0.3.3",
|
||||
|
|
|
@ -5,3 +5,4 @@ admin.initializeApp()
|
|||
export * from './keep-awake'
|
||||
export * from './place-bet'
|
||||
export * from './resolve-market'
|
||||
export * from './stripe'
|
||||
|
|
|
@ -101,7 +101,7 @@ const getPayouts = (outcome: string, contract: Contract, bets: Bet[]) => {
|
|||
]) // add creator fee
|
||||
}
|
||||
|
||||
const payUser = ([userId, payout]: [string, number]) => {
|
||||
export const payUser = ([userId, payout]: [string, number]) => {
|
||||
return firestore.runTransaction(async (transaction) => {
|
||||
const userDoc = firestore.doc(`users/${userId}`)
|
||||
const userSnap = await transaction.get(userDoc)
|
||||
|
|
78
functions/src/stripe.ts
Normal file
78
functions/src/stripe.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import Stripe from 'stripe'
|
||||
|
||||
import { payUser } from './resolve-market'
|
||||
|
||||
const stripe = new Stripe(functions.config().stripe.apikey, {
|
||||
apiVersion: '2020-08-27',
|
||||
typescript: true,
|
||||
})
|
||||
|
||||
const manticDollarStripePrice = {
|
||||
500: 'price_1K8W10GdoFKoCJW7KWORLec1',
|
||||
}
|
||||
|
||||
export const createCheckoutSession = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
.https.onRequest(async (req, res) => {
|
||||
const userId = req.query.userId?.toString()
|
||||
const manticDollarQuantity =
|
||||
req.query.manticDollarQuantity?.toString() || '500'
|
||||
|
||||
if (!userId) {
|
||||
res.send('Invalid user ID')
|
||||
return
|
||||
}
|
||||
|
||||
const referrer = req.headers.referer || 'https://mantic.markets'
|
||||
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
metadata: {
|
||||
userId,
|
||||
manticDollarQuantity,
|
||||
},
|
||||
line_items: [
|
||||
{
|
||||
price: manticDollarStripePrice[500],
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
mode: 'payment',
|
||||
success_url: `${referrer}/?success=true`,
|
||||
cancel_url: `${referrer}/?success=false`,
|
||||
})
|
||||
|
||||
res.redirect(303, session.url || '')
|
||||
})
|
||||
|
||||
export const stripeWebhook = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
.https.onRequest(async (req, res) => {
|
||||
let event
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(
|
||||
req.rawBody,
|
||||
req.headers['stripe-signature'] as string,
|
||||
functions.config().stripe.webhooksecret
|
||||
)
|
||||
} catch (e: any) {
|
||||
console.log(`Webhook Error: ${e.message}`)
|
||||
res.status(400).send(`Webhook Error: ${e.message}`)
|
||||
return
|
||||
}
|
||||
|
||||
if (event.type === 'checkout.session.completed') {
|
||||
const session = event.data.object as any
|
||||
issueMoneys(session)
|
||||
}
|
||||
|
||||
res.status(200)
|
||||
})
|
||||
|
||||
const issueMoneys = async (session: any) => {
|
||||
const { userId, manticDollarQuantity } = session.metadata
|
||||
const payout = Number.parseInt(manticDollarQuantity)
|
||||
|
||||
return await payUser([userId, payout])
|
||||
}
|
40
web/components/add-funds-button.tsx
Normal file
40
web/components/add-funds-button.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import clsx from 'clsx'
|
||||
|
||||
import { useUser } from '../hooks/use-user'
|
||||
|
||||
export function AddFundsButton(props: {}) {
|
||||
const {} = props
|
||||
const user = useUser()
|
||||
|
||||
return (
|
||||
<>
|
||||
<label htmlFor="add-funds" className={clsx('btn modal-button')}>
|
||||
Add funds
|
||||
</label>
|
||||
<input type="checkbox" id="add-funds" className="modal-toggle" />
|
||||
|
||||
<div className="modal">
|
||||
<div className="modal-box">
|
||||
Buy M$500
|
||||
<div className="modal-action">
|
||||
<label htmlFor="add-funds" className={clsx('btn')}>
|
||||
Back
|
||||
</label>
|
||||
|
||||
<form action={checkoutURL(user?.id || '', 500)} method="POST">
|
||||
<button type="submit" className="btn">
|
||||
Checkout
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const checkoutURL = (userId: string, manticDollarQuantity: number) => {
|
||||
const endpoint =
|
||||
'https://us-central1-mantic-markets.cloudfunctions.net/createCheckoutSession'
|
||||
return `${endpoint}?userId=${userId}&manticDollarQuantity=${manticDollarQuantity}`
|
||||
}
|
|
@ -16,6 +16,7 @@ import {
|
|||
getProbabilityAfterBet,
|
||||
} from '../lib/calculation/contract'
|
||||
import { firebaseLogin } from '../lib/firebase/users'
|
||||
import { AddFundsButton } from './add-funds-button'
|
||||
|
||||
export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||
const { contract, className } = props
|
||||
|
@ -136,6 +137,9 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
|||
Remaining balance
|
||||
</div>
|
||||
<div>{formatMoney(remainingBalance > 0 ? remainingBalance : 0)}</div>
|
||||
<div>
|
||||
<AddFundsButton />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user