修改交易流程

This commit is contained in:
CounterFire2023 2023-07-14 13:53:06 +08:00
parent e5dc33970c
commit 0913368456
7 changed files with 88 additions and 95 deletions

View File

@ -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"

View File

@ -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) {

View File

@ -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 = {

View File

@ -24,11 +24,11 @@ const notify = async function (record: DocumentType<PayRecordClass>, 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()

View File

@ -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<typeof PayRecordClass>, outOrderId: string) {
return this.findOne({ outOrderId }).exec()

View File

@ -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)
}

View File

@ -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
}