diff --git a/src/controllers/alchemy.controller.ts b/src/controllers/alchemy.controller.ts index a363d6f..4086e66 100644 --- a/src/controllers/alchemy.controller.ts +++ b/src/controllers/alchemy.controller.ts @@ -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) { diff --git a/src/controllers/alchemyout.controller.ts b/src/controllers/alchemyout.controller.ts index 417ab23..3c26fc2 100644 --- a/src/controllers/alchemyout.controller.ts +++ b/src/controllers/alchemyout.controller.ts @@ -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 } } diff --git a/src/controllers/internal.controller.ts b/src/controllers/internal.controller.ts index 413f354..67b6e7b 100644 --- a/src/controllers/internal.controller.ts +++ b/src/controllers/internal.controller.ts @@ -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, 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) { diff --git a/src/modules/PayRecord.ts b/src/modules/PayRecord.ts index dc40f25..202a299 100644 --- a/src/modules/PayRecord.ts +++ b/src/modules/PayRecord.ts @@ -57,6 +57,9 @@ export class PayRecordClass extends BaseModule { // 加密货币数量 @prop() public cryptoAmount?: string + // 开始创建记录时, 估算的加密货币数量 + @prop() + public cryptoAmountEstimate: string // 加密货币价格 @prop() diff --git a/src/service/ordercache.svr.ts b/src/service/ordercache.svr.ts new file mode 100644 index 0000000..0fbaaa5 --- /dev/null +++ b/src/service/ordercache.svr.ts @@ -0,0 +1,17 @@ +import { singleton } from 'decorators/singleton' + +@singleton +export class OrderCacheSvr { + private orderSet: Set = 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) + } +}