创建订单时, 预估可获得的加密币数量, 在发币时,如果差距太大, 则拒绝发币
This commit is contained in:
parent
5708c3a8db
commit
367d9b516a
@ -2,7 +2,7 @@ import logger from 'logger/logger'
|
||||
import BaseController from 'common/base.controller'
|
||||
import { ZError } from 'common/ZError'
|
||||
import { router } from 'decorators/router'
|
||||
import { createOrder, createPageSign, queryFiat, queryPrice, refreshToken } from 'service/alchemy.svr'
|
||||
import { createOrder, queryFiat, queryPrice, refreshToken } from 'service/alchemy.svr'
|
||||
import { generateKVStr } from 'utils/net.util'
|
||||
import { PayRecord, PayStatus } from 'modules/PayRecord'
|
||||
import { PriceSvr } from 'service/price.svr'
|
||||
@ -44,6 +44,11 @@ class AlchemyController extends BaseController {
|
||||
throw new ZError(13, 'daily limit')
|
||||
}
|
||||
}
|
||||
// 根据 `查询数字货币接口` 返回的数据, 预估可获得的数字货币数量
|
||||
// 用户法币接口做简单的验证
|
||||
let priceData = await queryPrice({ crypto, network, fiat, amount: fiatAmount, payWayCode, country })
|
||||
logger.debug('pirce data::', JSON.stringify(priceData))
|
||||
let amountEstimate = priceData.data.cryptoAmount
|
||||
let record = new PayRecord({
|
||||
account: user.id,
|
||||
address,
|
||||
@ -52,6 +57,7 @@ class AlchemyController extends BaseController {
|
||||
env: envStr,
|
||||
gameAccountId: accountId,
|
||||
gameOrderId: orderId,
|
||||
cryptoAmountEstimate: amountEstimate,
|
||||
})
|
||||
if (fiat) record.fiat = fiat
|
||||
if (fiatAmount) record.fiatAmount = fiatAmount
|
||||
@ -88,59 +94,59 @@ class AlchemyController extends BaseController {
|
||||
}
|
||||
return { url: payRes.data.payUrl }
|
||||
}
|
||||
@router('post /pay/alchemy/buypage')
|
||||
async beginPagePay(req, res) {
|
||||
const user = req.user
|
||||
const { network, crypto, address, fiat, fiatAmount, country } = req.params
|
||||
if (fiat || fiatAmount || country) {
|
||||
if (!fiat || !fiatAmount || !country) {
|
||||
throw new ZError(11, 'fiat, fiatAmount and country must be provided')
|
||||
}
|
||||
}
|
||||
if (network || crypto) {
|
||||
if (!network || !crypto) {
|
||||
throw new ZError(12, 'network and crypto must be provided')
|
||||
}
|
||||
}
|
||||
const tokenResult = await refreshToken(user.emailReal || user.email)
|
||||
console.log(tokenResult)
|
||||
if (!tokenResult.success || tokenResult.returnCode !== '0000') {
|
||||
logger.info(`fetch pay token error::code: ${tokenResult.returnCode} msg: ${tokenResult.returnMsg}`)
|
||||
throw new ZError(10, 'fetch pay token error')
|
||||
}
|
||||
const { id, email, accessToken } = tokenResult.data
|
||||
let record = new PayRecord({ account: user.id, address, network, crypto })
|
||||
if (fiat) record.fiat = fiat
|
||||
if (fiatAmount) record.fiatAmount = fiatAmount
|
||||
if (country) record.country = country
|
||||
await record.save()
|
||||
const merchantOrderNo = record.id
|
||||
let dataOrign: any = {
|
||||
token: accessToken,
|
||||
email,
|
||||
id,
|
||||
showTable: 'buy',
|
||||
merchantOrderNo,
|
||||
}
|
||||
if (network) dataOrign.network = network
|
||||
if (crypto) dataOrign.crypto = crypto
|
||||
if (fiat) dataOrign.fiat = fiat
|
||||
if (fiatAmount) dataOrign.fiatAmount = fiatAmount
|
||||
if (country) dataOrign.country = country
|
||||
let dataSign: any = {
|
||||
appId: process.env.ALCHEMY_APPID,
|
||||
address,
|
||||
callbackUrl: CALL_BACK_URL,
|
||||
}
|
||||
let signStr = generateKVStr({ data: dataSign, sort: true })
|
||||
let sign = createPageSign(signStr)
|
||||
dataOrign.sign = sign
|
||||
Object.assign(dataOrign, dataSign)
|
||||
const urlBase = process.env.ALCHEMY_PAGE_BASE
|
||||
let url = `${urlBase}/`
|
||||
url = generateKVStr({ data: dataOrign, encode: true, uri: url })
|
||||
return { url }
|
||||
}
|
||||
// @router('post /pay/alchemy/buypage')
|
||||
// async beginPagePay(req, res) {
|
||||
// const user = req.user
|
||||
// const { network, crypto, address, fiat, fiatAmount, country } = req.params
|
||||
// if (fiat || fiatAmount || country) {
|
||||
// if (!fiat || !fiatAmount || !country) {
|
||||
// throw new ZError(11, 'fiat, fiatAmount and country must be provided')
|
||||
// }
|
||||
// }
|
||||
// if (network || crypto) {
|
||||
// if (!network || !crypto) {
|
||||
// throw new ZError(12, 'network and crypto must be provided')
|
||||
// }
|
||||
// }
|
||||
// const tokenResult = await refreshToken(user.emailReal || user.email)
|
||||
// console.log(tokenResult)
|
||||
// if (!tokenResult.success || tokenResult.returnCode !== '0000') {
|
||||
// logger.info(`fetch pay token error::code: ${tokenResult.returnCode} msg: ${tokenResult.returnMsg}`)
|
||||
// throw new ZError(10, 'fetch pay token error')
|
||||
// }
|
||||
// const { id, email, accessToken } = tokenResult.data
|
||||
// let record = new PayRecord({ account: user.id, address, network, crypto })
|
||||
// if (fiat) record.fiat = fiat
|
||||
// if (fiatAmount) record.fiatAmount = fiatAmount
|
||||
// if (country) record.country = country
|
||||
// await record.save()
|
||||
// const merchantOrderNo = record.id
|
||||
// let dataOrign: any = {
|
||||
// token: accessToken,
|
||||
// email,
|
||||
// id,
|
||||
// showTable: 'buy',
|
||||
// merchantOrderNo,
|
||||
// }
|
||||
// if (network) dataOrign.network = network
|
||||
// if (crypto) dataOrign.crypto = crypto
|
||||
// if (fiat) dataOrign.fiat = fiat
|
||||
// if (fiatAmount) dataOrign.fiatAmount = fiatAmount
|
||||
// if (country) dataOrign.country = country
|
||||
// let dataSign: any = {
|
||||
// appId: process.env.ALCHEMY_APPID,
|
||||
// address,
|
||||
// callbackUrl: CALL_BACK_URL,
|
||||
// }
|
||||
// let signStr = generateKVStr({ data: dataSign, sort: true })
|
||||
// let sign = createPageSign(signStr)
|
||||
// dataOrign.sign = sign
|
||||
// Object.assign(dataOrign, dataSign)
|
||||
// const urlBase = process.env.ALCHEMY_PAGE_BASE
|
||||
// let url = `${urlBase}/`
|
||||
// url = generateKVStr({ data: dataOrign, encode: true, uri: url })
|
||||
// return { url }
|
||||
// }
|
||||
|
||||
@router('post /pay/alchemy/crypto_price')
|
||||
async queryCryptoPrice(req, res) {
|
||||
|
@ -8,6 +8,7 @@ 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}`)
|
||||
@ -135,14 +136,27 @@ class AlchemyOutController extends BaseController {
|
||||
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
|
||||
@ -157,6 +171,7 @@ class AlchemyOutController extends BaseController {
|
||||
returnCode: '0000', // false: 9999
|
||||
returnMsg: 'in amet',
|
||||
}
|
||||
new OrderCacheSvr().removeOrder(orderNo)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import { PayRecord, PayRecordClass, PayStatus } from 'modules/PayRecord'
|
||||
import { TransferRecord, TransferRecordClass } from 'modules/TransferRecord'
|
||||
import { hmacsha256 } from 'utils/security.util'
|
||||
import { DocumentType } from '@typegoose/typegoose'
|
||||
import { queryPrice, updateOrderStatus } from 'service/alchemy.svr'
|
||||
import { updateOrderStatus } from 'service/alchemy.svr'
|
||||
import { PriceSvr } from 'service/price.svr'
|
||||
|
||||
const calcHash = function (data: any) {
|
||||
let signStr = JSON.stringify(data)
|
||||
@ -26,8 +27,8 @@ const notify = async function (record: DocumentType<PayRecordClass>, subTask: Do
|
||||
status: record.status === PayStatus.TRANSFERED ? 'SUCCESS' : 'FAIL', // SUCCESS/FAIL
|
||||
}
|
||||
try {
|
||||
let priceData = await queryPrice({ gas: subTask.gas })
|
||||
data.networkFee = priceData.leagel
|
||||
let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM' })
|
||||
data.networkFee = parseFloat(subTask.gas) * parseFloat(subTask.gasPrice) * parseFloat(price) + ''
|
||||
let result = await updateOrderStatus(data)
|
||||
logger.info('update transfer status success::', JSON.stringify(result))
|
||||
if (result.success) {
|
||||
|
@ -57,6 +57,9 @@ export class PayRecordClass extends BaseModule {
|
||||
// 加密货币数量
|
||||
@prop()
|
||||
public cryptoAmount?: string
|
||||
// 开始创建记录时, 估算的加密货币数量
|
||||
@prop()
|
||||
public cryptoAmountEstimate: string
|
||||
|
||||
// 加密货币价格
|
||||
@prop()
|
||||
|
17
src/service/ordercache.svr.ts
Normal file
17
src/service/ordercache.svr.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { singleton } from 'decorators/singleton'
|
||||
|
||||
@singleton
|
||||
export class OrderCacheSvr {
|
||||
private orderSet: Set<string> = new Set()
|
||||
|
||||
public addOrder(orderId: string) {
|
||||
this.orderSet.add(orderId)
|
||||
}
|
||||
|
||||
public isOrderExist(orderId: string) {
|
||||
return this.orderSet.has(orderId)
|
||||
}
|
||||
public removeOrder(orderId: string) {
|
||||
this.orderSet.delete(orderId)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user