50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
import * as admin from 'firebase-admin'
|
|
|
|
import { Bet } from '../../common/bet'
|
|
import { getRedeemableAmount, getRedemptionBets } from '../../common/redeem'
|
|
|
|
import { Contract } from '../../common/contract'
|
|
import { User } from '../../common/user'
|
|
|
|
export const redeemShares = async (userId: string, contractId: string) => {
|
|
return await firestore.runTransaction(async (trans) => {
|
|
const contractDoc = firestore.doc(`contracts/${contractId}`)
|
|
const contractSnap = await trans.get(contractDoc)
|
|
if (!contractSnap.exists)
|
|
return { status: 'error', message: 'Invalid contract' }
|
|
|
|
const contract = contractSnap.data() as Contract
|
|
const { mechanism } = contract
|
|
if (mechanism !== 'cpmm-1') return { status: 'success' }
|
|
|
|
const betsColl = firestore.collection(`contracts/${contract.id}/bets`)
|
|
const betsSnap = await trans.get(betsColl.where('userId', '==', userId))
|
|
const bets = betsSnap.docs.map((doc) => doc.data() as Bet)
|
|
const { shares, loanPayment, netAmount } = getRedeemableAmount(bets)
|
|
if (netAmount === 0) {
|
|
return { status: 'success' }
|
|
}
|
|
const [yesBet, noBet] = getRedemptionBets(shares, loanPayment, contract)
|
|
|
|
const userDoc = firestore.doc(`users/${userId}`)
|
|
const userSnap = await trans.get(userDoc)
|
|
if (!userSnap.exists) return { status: 'error', message: 'User not found' }
|
|
const user = userSnap.data() as User
|
|
const newBalance = user.balance + netAmount
|
|
|
|
if (!isFinite(newBalance)) {
|
|
throw new Error('Invalid user balance for ' + user.username)
|
|
}
|
|
|
|
const yesDoc = betsColl.doc()
|
|
const noDoc = betsColl.doc()
|
|
trans.update(userDoc, { balance: newBalance })
|
|
trans.create(yesDoc, { id: yesDoc.id, userId, ...yesBet })
|
|
trans.create(noDoc, { id: noDoc.id, userId, ...noBet })
|
|
|
|
return { status: 'success' }
|
|
})
|
|
}
|
|
|
|
const firestore = admin.firestore()
|