diff --git a/.env.development b/.env.development index 9910a51..9bbbaec 100644 --- a/.env.development +++ b/.env.development @@ -17,10 +17,10 @@ EMAIL_SERVER='http://127.0.0.1:3087' ALCHEMY_APPID="f83Is2y7L425rxl8" ALCHEMY_APP_SECRET="4Yn8RkxDXN71Q3p0" -ALCHEMY_API_BASE="https://openapi-test.alchemypay.org" -ALCHEMY_PAGE_BASE="https://ramptest.alchemypay.org" -# ALCHEMY_API_BASE="http://127.0.0.1:3009" -# ALCHEMY_PAGE_BASE="http://127.0.0.1:3009/pay_page" +# ALCHEMY_API_BASE="https://openapi-test.alchemypay.org" +# ALCHEMY_PAGE_BASE="https://ramptest.alchemypay.org" +ALCHEMY_API_BASE="http://127.0.0.1:3009" +ALCHEMY_PAGE_BASE="http://127.0.0.1:3009/pay_page" ALCHEMY_PAY_CB_URL="https://wallet.cebggame.com" diff --git a/src/controllers/alchemy.controller.ts b/src/controllers/alchemy.controller.ts index 4086e66..a1eccab 100644 --- a/src/controllers/alchemy.controller.ts +++ b/src/controllers/alchemy.controller.ts @@ -94,59 +94,6 @@ 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/crypto_price') async queryCryptoPrice(req, res) { diff --git a/src/controllers/alchemyout.controller.ts b/src/controllers/alchemyout.controller.ts index 3c26fc2..77cad74 100644 --- a/src/controllers/alchemyout.controller.ts +++ b/src/controllers/alchemyout.controller.ts @@ -21,53 +21,69 @@ let errorRes = function (msg: string) { } } /** - * for Alchemy call + * for Alchemy call, */ class AlchemyOutController extends BaseController { + // 购买回调 @role(ROLE_ANON) - @router('post /pay/out/alchemy/buycb') - async alchemyCallback(req, res) { + @router('post /pay/out/alchemy/result') + async buyresult(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`) + logger.info(`alchemy callback merchantOrderNo not found, ordreNo: ${orderNo}`) throw new ZError(11, 'alchemy callback merchantOrderNo not found') } let record = await PayRecord.findById(merchantOrderNo) if (!record) { - logger.info(`alchemy callback record not found`) + logger.info(`alchemy callback record not found, ordreNo: ${orderNo}`) 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`) + if (record.status !== PayStatus.PENDING && record.status !== PayStatus.PAYED) { + logger.info(`alchemy callback record status error, ordreNo: ${orderNo}`) 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') + logger.info(`alchemy callback sign error: ${orderNo}`) + throw new ZError(14, `alchemy callback sign error: orderNo: ${orderNo}`) } - let transferRecord = await TransferRecord.findByRecordId(record.id) - if (transferRecord) { - transferRecord.status = 9 - await transferRecord.save() + if (status === 'FINISHED') { + 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 + record.outDatas.push(req.params) + if (req.params.payTime) { + record.payTime = req.params.payTime + } + if (status === 'PAY_SUCCESS') { + record.status = PayStatus.PAYED + } else if (status === 'FINISHED') { + record.status = PayStatus.SUCCESS + } else { + record.status = PayStatus.FAIL + } await record.save() - setImmediate(() => { - reportPayResult(record) - }) - logger.info(`alchemy callback success, pay finished`) + if (status === 'FINISHED') { + setImmediate(async () => { + try { + await reportPayResult(record) + record.reportStatus = 1 + await record.save() + } catch (err) { + logger.info(`report pay result:: ${record.outOrderId} error: ${err.message}`) + record.reportStatus = 99 + await record.save() + } + }) + } + logger.info(`alchemy callback success, status: ${status} orderNo: ${orderNo} `) return {} } @@ -93,7 +109,7 @@ class AlchemyOutController extends BaseController { return errorRes('sign error') } let gas = 36000 * 0.0000000001 - let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM' }) + let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' }) let networkFee = gas * parseFloat(price) let result = { direct: 1, @@ -145,6 +161,8 @@ class AlchemyOutController extends BaseController { new OrderCacheSvr().removeOrder(orderNo) return errorRes('orderNo not found') } + record.outDatas.push(req.params) + await record.save() if (record.crypto != crypto || record.network != network || record.address != address) { new OrderCacheSvr().removeOrder(orderNo) return errorRes('params mismatch') @@ -161,7 +179,6 @@ class AlchemyOutController extends BaseController { 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 = { diff --git a/src/controllers/internal.controller.ts b/src/controllers/internal.controller.ts index 67b6e7b..f590937 100644 --- a/src/controllers/internal.controller.ts +++ b/src/controllers/internal.controller.ts @@ -24,11 +24,11 @@ const notify = async function (record: DocumentType, subTask: Do network: record.network, // 用户购买的数字货币对应的网络 // networkFee: record.networkFee, // 网络费用/USDT address: record.address, // 用户的提币地址 - status: record.status === PayStatus.TRANSFERED ? 'SUCCESS' : 'FAIL', // SUCCESS/FAIL + status: record.tranStatus === 2 ? 'SUCCESS' : 'FAIL', // SUCCESS/FAIL } try { - let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM' }) - data.networkFee = parseFloat(subTask.gas) * parseFloat(subTask.gasPrice) * parseFloat(price) + '' + 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) { @@ -71,10 +71,10 @@ export default class InternalController extends BaseController { record.gasPrice = gasPrice record.hashList = hashList task.txHash = hashList[0] - task.status = PayStatus.TRANSFERED + task.tranStatus = 2 } else { record.status = 10 - task.status = PayStatus.TRANSFER_FAIL + task.tranStatus = 99 } await record.save() await task.save() diff --git a/src/modules/PayRecord.ts b/src/modules/PayRecord.ts index f164166..92f730b 100644 --- a/src/modules/PayRecord.ts +++ b/src/modules/PayRecord.ts @@ -13,10 +13,9 @@ export enum PayType { export enum PayStatus { PENDING = 0, // 默认状态, 未支付 - TRANSFERING = 1, //只有国库模式才会有该状态 - TRANSFERED = 2, //只有国库模式才会有该状态 + PAYED = 3, // 已支付 SUCCESS = 9, - TRANSFER_FAIL = 98, // 转账错误 + PAY_FAIL = 97, // 用户支付失败, 国库模式 FAIL = 99, // 交易失败 } @@ -58,6 +57,7 @@ export class PayRecordClass extends BaseModule { // 加密货币数量, 实际转账金额 @prop() public cryptoAmount?: string + // 开始创建记录时, 估算的可获取加密货币数量 @prop() public cryptoAmountEstimate: string @@ -74,10 +74,18 @@ export class PayRecordClass extends BaseModule { // 交易状态 @prop({ required: true, default: PayStatus.PENDING }) public status: PayStatus + // 渠道返回的原始资料 @prop({ type: mongoose.Schema.Types.Mixed }) public outData: any + @prop({ type: () => [mongoose.Schema.Types.Mixed] }) + public outDatas: any[] + + // 支付时间, 由alchemy提供 + @prop() + public payTime: string + // 渠道返回的订单id @prop() public outOrderId: string @@ -89,6 +97,24 @@ export class PayRecordClass extends BaseModule { public gameAccountId: string @prop() public gameOrderId: string + /** + * 国库模式转账状态 + * 0: 未转账 + * 1: 提交转账成功 + * 2: 转账成功 + * 99: 转账失败 + */ + @prop({ default: 0 }) + public tranStatus: number + + /** + * 上报游戏服状态 + * 0: 未上报 + * 1: 上报成功 + * 99: 上报失败 + */ + @prop({ default: 0 }) + public reportStatus: number public static async findByRecordId(this: ReturnModelType, outOrderId: string) { return this.findOne({ outOrderId }).exec() diff --git a/src/queue/transfer.queue.ts b/src/queue/transfer.queue.ts index d32d4cb..5e6725f 100644 --- a/src/queue/transfer.queue.ts +++ b/src/queue/transfer.queue.ts @@ -91,9 +91,11 @@ export class TransferQueue { cb: process.env.PAY_TRANSFER_CB_URL, } await pushTaskToChain(reqData) - + task.tranStatus = 1 await task.save() } catch (err) { + task.tranStatus = 99 + await task.save() logger.error('error add chain task: ') logger.error(err) } diff --git a/src/service/alchemy.svr.ts b/src/service/alchemy.svr.ts index 8ad1c56..cdd260f 100644 --- a/src/service/alchemy.svr.ts +++ b/src/service/alchemy.svr.ts @@ -40,8 +40,9 @@ export function createSha1Sign() { * @returns true if the sign is valid, false otherwise */ export function checkPayResultSign(data: any) { - const { appId, orderNo, crypto, network, address, signature } = data - const sign = sha1(appId + process.env.ALCHEMY_APP_SECRET + appId + orderNo + crypto + network + address) + const { appId, appid, orderNo, crypto, network, address, signature } = data + const appIdReal = appId || appid + const sign = sha1(appIdReal + process.env.ALCHEMY_APP_SECRET + appIdReal + orderNo + crypto + network + address) return sign === signature }