import logger from 'logger/logger' import { checkPrePaySign, createOrder, queryFiat, queryPrice, refreshToken } from 'service/alchemy.svr' import { PayRecord, PayStatus } from 'modules/PayRecord' import { PriceSvr } from 'service/price.svr' import { reportPayResult } from 'service/game.svr' import { GasSvr } from 'service/gas.svr' import { BaseController, ROLE_ANON, ZError, role, router } from 'zutils' const CALL_BACK_URL = `${process.env.ALCHEMY_PAY_CB_URL}/pay/out/alchemy/result` class AlchemyController extends BaseController { @router('post /pay/alchemy/buy') async beginApiPay(req, res) { const user = req.user logger.db('alchemy_begin_pay', req) let { network, crypto, address, fiat, fiatAmount, payWayCode, country, accountId, orderId, env, sign } = req.params const envStr = req.headers['api-env'] || env || 'dev' if (!fiat || !fiatAmount || !country || !payWayCode) { throw new ZError(11, 'fiat, fiatAmount payWayCode and country must be provided') } if (!network || !crypto) { throw new ZError(12, 'network and crypto must be provided') } const apiVersion = +(req.headers['api-version'] || '0') if (apiVersion > 0) { if (!sign) { throw new ZError(14, 'sign must be provided') } if (!checkPrePaySign(req.params)) { throw new ZError(15, 'sign error') } } const tokenResult = await refreshToken(user.emailReal || user.email) 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 { accessToken } = tokenResult.data if (crypto.toLowerCase() === 'agor') { let today = new Date() today.setHours(0, 0, 0, 0) let count = await PayRecord.countDocuments({ account: user.id, crypto, status: PayStatus.SUCCESS, createdAt: { $gte: today }, }) if (count >= 3) { throw new ZError(13, 'daily limit') } } // 根据 `查询数字货币接口` 返回的数据, 预估可获得的数字货币数量 // 用户法币接口做简单的验证 if (network.toLowerCase() === 'agor') { network = 'ARBITRUM' } let priceData = await queryPrice({ crypto, network, fiat, amount: fiatAmount, payWayCode, country }) if (!priceData.success) { throw new ZError(14, priceData.returnMsg || 'fetch price error') } logger.debug('pirce data::', JSON.stringify(priceData)) let amountEstimate = priceData.data.cryptoQuantity let record = new PayRecord({ account: user.id, address, network, crypto, env: envStr, gameAccountId: accountId, gameOrderId: orderId, cryptoAmountEstimate: amountEstimate, fiat, fiatAmount, country, payWayCode, versionCode: apiVersion, }) await record.save() let payData: any = { side: 'BUY', merchantOrderNo: record.id, amount: record.fiatAmount, fiatCurrency: record.fiat, cryptoCurrency: record.crypto, depositType: '2', address: address, network: record.network, payWayCode, alpha2: record.country, callbackUrl: CALL_BACK_URL, merchantName: 'CEBG', } if (process.env.ALCHEMY_PAY_REDIRECT) { payData.redirectUrl = process.env.ALCHEMY_PAY_REDIRECT } logger.info(`create order data::${JSON.stringify(payData)}`) let payRes = await createOrder(accessToken, payData) logger.info(`create order result::${JSON.stringify(payRes)}`) record.outData = payRes.data if (payRes.success) { record.outOrderId = payRes.data.orderNo await record.save() } else { record.status = PayStatus.FAIL await record.save() setImmediate(() => { reportPayResult(record) }) throw new ZError(payRes.returnCode, payRes.returnMsg) } return { url: payRes.data.payUrl } } @router('post /pay/alchemy/crypto_price') @router('get /pay/alchemy/crypto_price') async queryCryptoPrice(req, res) { let { token, crypto, chain, currency, env } = req.params crypto = crypto || token if (!crypto || !chain) { throw new ZError(11, 'token or network not found') } // ceg价格固定为0.1 if (crypto.toLowerCase() === 'ceg') { return { price: '0.1' } } if ((chain.toLowerCase() === 'agor' || chain.toLowerCase() === 'eth') && crypto.toLowerCase() === 'agor') { crypto = 'ETH' chain = 'ARBITRUM' } let data = { crypto, network: chain, fiat: currency || 'USD', } let result = await new PriceSvr().fetchPrice(data) return { price: result } } @router('get /pay/alchemy/fait_list') async cryptoList(req, res) { let result = await queryFiat() if (!result.success) { throw new ZError(10, result.returnMsg || 'fetch fiat list error') } return result.data } @router('get /pay/alchemy/can_i_buy_treasury') async canIBuyEth(req, res) { const user = req.user const crypto = process.env.CF_ETH_NAME let today = new Date() today.setHours(0, 0, 0, 0) const count = await PayRecord.countDocuments({ account: user.id, crypto, status: PayStatus.SUCCESS, createdAt: { $gte: today }, }) return { result: count >= 3 ? 0 : 1 } } @role(ROLE_ANON) @router('post /pay/alchemy/estimateGas') async estimateGas(req, res) { const { crypto, network } = req.params const gas = await new GasSvr().estimateGas({ crypto, network }) return { gas } } }