pay-svr/src/controllers/alchemyout.controller.ts

178 lines
6.0 KiB
TypeScript

import logger from 'logger/logger'
import BaseController, { ROLE_ANON } from 'common/base.controller'
import { ZError } from 'common/ZError'
import { role, router } from 'decorators/router'
import { checkPayResultSign, checkSha1Sign, checkSimpleSign } from 'service/alchemy.svr'
import { PayRecord, PayStatus } from 'modules/PayRecord'
import { TransferQueue } from 'queue/transfer.queue'
import { TransferRecord } from 'modules/TransferRecord'
import { reportPayResult } from 'service/game.svr'
import { PriceSvr } from 'service/price.svr'
import { OrderCacheSvr } from 'service/ordercache.svr'
let errorRes = function (msg: string) {
logger.info(`error res: ${msg}`)
return {
direct: 1,
data: null,
success: false,
returnCode: '9999',
returnMsg: msg,
}
}
/**
* for Alchemy call
*/
class AlchemyOutController extends BaseController {
@role(ROLE_ANON)
@router('post /pay/out/alchemy/buycb')
async alchemyCallback(req, res) {
let { orderNo, status, crypto, network, merchantOrderNo } = req.params
logger.info(`alchemy callback: ${orderNo}, ${status}, ${crypto}, ${network}, ${merchantOrderNo}`)
if (!merchantOrderNo) {
logger.info(`alchemy callback merchantOrderNo not found`)
throw new ZError(11, 'alchemy callback merchantOrderNo not found')
}
let record = await PayRecord.findById(merchantOrderNo)
if (!record) {
logger.info(`alchemy callback record not found`)
throw new ZError(12, 'alchemy callback record not found')
}
if (
record.status !== PayStatus.PENDING &&
record.status !== PayStatus.TRANSFERING &&
record.status !== PayStatus.TRANSFERED
) {
logger.info(`alchemy callback record status error`)
throw new ZError(13, 'alchemy callback record status error')
}
if (!checkPayResultSign(req.params)) {
logger.info(`alchemy callback sign error`)
record.status = PayStatus.FAIL
await record.save()
throw new ZError(14, 'alchemy callback sign error')
}
let transferRecord = await TransferRecord.findByRecordId(record.id)
if (transferRecord) {
transferRecord.status = 9
await transferRecord.save()
}
record.outOrderId = orderNo
record.network = network
record.crypto = crypto
record.outData = req.params
record.status = status == 'PAY_SUCCESS' ? PayStatus.SUCCESS : PayStatus.FAIL
await record.save()
setImmediate(() => {
reportPayResult(record)
})
logger.info(`alchemy callback success, pay finished`)
return {}
}
/**
* 向商户查询币价
* TODO:: calc networkFee
*/
@role(ROLE_ANON)
@router('get /pay/out/alchemy/queryprice')
async queryToken(req, res) {
const { crypto } = req.params
logger.info(`alchemy query price: ${crypto}`)
let { appId, appid, timestamp, sign } = req.headers
logger.info(`alchemy query price headers: ${appid}, ${timestamp}, ${sign}`)
if (!crypto) {
return errorRes('params mismatch')
}
appId = appId || appid
if (!appId || !timestamp || !sign) {
return errorRes('headers mismatch')
}
if (!checkSha1Sign(req.headers)) {
return errorRes('sign error')
}
let gas = 36000 * 0.0000000001
let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM' })
let networkFee = gas * parseFloat(price)
let result = {
direct: 1,
data: {
price: '1.0',
networkList: [
{
network: 'ARBITRUM',
networkFee: networkFee.toFixed(6),
},
],
},
success: true,
returnCode: '0000', // false: 9999
returnMsg: 'in amet',
}
return result
}
/**
* 通知商户打币
*/
@role(ROLE_ANON)
@router('post /pay/out/alchemy/distribute')
async distributeToken(req, res) {
const { orderNo, crypto, network, address, cryptoAmount, cryptoPrice, usdtAmount } = req.params
logger.info(
`alchemy distributeToken: orderNo: ${orderNo}, crypto: ${crypto}, network: ${network}, address: ${address}, cryptoAmount: ${cryptoAmount}, cryptoPrice: ${cryptoPrice}, usdtAmount: ${usdtAmount}`,
)
let { appId, appid, timestamp, sign } = req.headers
logger.info(`alchemy distributeToken: appId: ${appId || appid}, timestamp: ${timestamp}, sign: ${sign}`)
if (!orderNo || !crypto || !network || !address || !cryptoAmount || !cryptoPrice || !usdtAmount) {
return errorRes('params mismatch')
}
appId = appId || appid
if (!timestamp || !sign) {
return errorRes('headers mismatch')
}
// let signData = { orderNo, crypto, network, address, cryptoAmount, cryptoPrice, usdtAmount }
if (!checkSha1Sign(req.headers)) {
return errorRes('sign error')
}
if (new OrderCacheSvr().isOrderExist(orderNo)) {
return errorRes('orderNo already processing')
}
new OrderCacheSvr().addOrder(orderNo)
let record = await PayRecord.findByRecordId(orderNo)
if (!record) {
new OrderCacheSvr().removeOrder(orderNo)
return errorRes('orderNo not found')
}
if (record.crypto != crypto || record.network != network || record.address != address) {
new OrderCacheSvr().removeOrder(orderNo)
return errorRes('params mismatch')
}
// 简单的比较一下, 如果差距太大, 就不处理
if (record.cryptoAmountEstimate) {
let diff = parseFloat(cryptoAmount) / parseFloat(record.cryptoAmountEstimate)
if (diff > 3 || diff < 0.5) {
new OrderCacheSvr().removeOrder(orderNo)
return errorRes('params mismatch, cryptoAmount too big or too small')
}
}
record.cryptoAmount =
record.network.toLowerCase() === 'agor' && record.crypto.toLowerCase() === 'agor' ? '0.001' : cryptoAmount
record.cryptoPrice = cryptoPrice
record.usdtAdmount = usdtAmount
record.status = PayStatus.TRANSFERING
await record.save()
new TransferQueue().addTask(record)
let result = {
direct: 1,
data: null,
success: true,
returnCode: '0000', // false: 9999
returnMsg: 'in amet',
}
new OrderCacheSvr().removeOrder(orderNo)
return result
}
}