pay-svr/src/controllers/internal.controller.ts
2024-01-17 17:36:30 +08:00

114 lines
4.0 KiB
TypeScript

import logger from 'logger/logger'
import { PayRecord, PayRecordClass, PayStatus } from 'modules/PayRecord'
import { TransferRecord, TransferRecordClass } from 'modules/TransferRecord'
import { DocumentType } from '@typegoose/typegoose'
import { updateOrderStatus } from 'service/alchemy.svr'
import { PriceSvr } from 'service/price.svr'
import { assembleGameData, checkGameSign } from 'service/game.svr'
import { BaseController, role, ROLE_ANON, router, ZError } from 'zutils'
import { hmacSha256 } from 'zutils/utils/security.util'
const calcHash = function (data: any) {
let signStr = JSON.stringify(data)
return hmacSha256(signStr, process.env.HASH_SALT_CHAIN).toLowerCase()
}
const notify = async function (record: DocumentType<PayRecordClass>, subTask: DocumentType<TransferRecordClass>) {
let data: any = {
orderNo: record.outOrderId, // AlchemyPay订单号
crypto: record.crypto, // 用户购买的数字货币
cryptoAmount: record.cryptoSend, //用户的提币数量
cryptoPrice: record.cryptoPrice, // 实时的价格/USDT CEG锚定USDT
txHash: record.txHash, // 给用户转账的hash
network: record.network, // 用户购买的数字货币对应的网络
// networkFee: record.networkFee, // 网络费用/USDT
address: record.address, // 用户的提币地址
status: record.tranStatus === 2 ? 'SUCCESS' : 'FAIL', // SUCCESS/FAIL
}
try {
let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' })
data.networkFee = parseFloat(subTask.gas) * parseFloat(subTask.gasPrice) * 0.0000000001 * parseFloat(price) + ''
let result = await updateOrderStatus(data)
logger.info('update transfer status success::', JSON.stringify(result))
if (result.success) {
subTask.status = 8
await subTask.save()
}
} catch (err) {
logger.error(`notify alchemy error:: ${err.message}`)
record.notofyErrCount = record.notofyErrCount + 1
await record.save()
if (record.notofyErrCount < 6) {
await notify(record, subTask)
}
}
}
export default class InternalController extends BaseController {
@role(ROLE_ANON)
@router('post /api/internal/update_task')
async updateTaskInfo(req) {
let { sign, id, result, successCount, errorCount, gas, gasPrice, hashList } = req.params
if (!sign) {
throw new ZError(10, 'sign not found')
}
let hash = calcHash({ id, result, successCount, errorCount, gas, gasPrice, hashList })
console.log(hash, sign)
if (sign !== hash) {
throw new ZError(11, 'sign not match')
}
logger.info(`task report:: ${id}|${result}|${successCount}|${errorCount}|${JSON.stringify(hashList)}}`)
if (!id) {
throw new ZError(11, 'taskId not found')
}
let record = await TransferRecord.findById(id)
if (!record) {
throw new ZError(12, 'TransferRecord not found')
}
let task = await PayRecord.findById(record.recordId)
if (!task) {
throw new ZError(13, 'PayRecord not found')
}
if (result === 2) {
record.status = 9
record.gas = gas
record.gasPrice = gasPrice
record.hashList = hashList
task.txHash = hashList[0]
task.tranStatus = 2
} else {
record.status = 10
task.tranStatus = 99
}
await record.save()
await task.save()
setImmediate(async () => {
await notify(task, record)
})
return {}
}
/**
* 供Game端二次确认支付结果
*/
@role(ROLE_ANON)
@router('get /api/internal/alchemy/order/:id')
async queryAlchemyPayOrder(req) {
let { id, timestamp, sign } = req.params
if (!id || !timestamp || !sign) {
throw new ZError(10, 'params mismatch')
}
if (timestamp < Date.now() / 1000 - 60 * 5) {
throw new ZError(11, 'timestamp expired')
}
if (!checkGameSign({ id, timestamp, sign })) {
throw new ZError(12, 'sign not match')
}
let record = await PayRecord.findById(id)
if (!record) {
throw new ZError(13, 'PayRecord not found')
}
const repData = assembleGameData(record, false)
return repData
}
}