修改alchemy逻辑,减去gas费后再计算crypto数量

This commit is contained in:
CounterFire2023 2023-07-19 11:25:26 +08:00
parent 9799a86817
commit 3c7ff25fac
7 changed files with 281 additions and 17 deletions

View File

@ -2,7 +2,7 @@ import logger from 'logger/logger'
import BaseController, { ROLE_ANON } from 'common/base.controller'
import { ZError } from 'common/ZError'
import { role, router } from 'decorators/router'
import { checkPayResultSign, checkSha1Sign, checkSimpleSign } from 'service/alchemy.svr'
import { calcNetworkFee, checkPayResultSign, checkSha1Sign, checkSimpleSign } from 'service/alchemy.svr'
import { PayRecord, PayStatus } from 'modules/PayRecord'
import { TransferQueue } from 'queue/transfer.queue'
import { TransferRecord } from 'modules/TransferRecord'
@ -11,6 +11,7 @@ import { PriceSvr } from 'service/price.svr'
import { OrderCacheSvr } from 'service/ordercache.svr'
import { GasSvr } from 'service/gas.svr'
import { parse } from 'dotenv'
import { toBigInt, toWei, fromWei, EtherUnits, toBigWei } from 'utils/number.util'
let errorRes = function (msg: string) {
logger.info(`error res: ${msg}`)
@ -110,19 +111,13 @@ class AlchemyOutController extends BaseController {
if (!checkSha1Sign(req.headers)) {
return errorRes('sign error')
}
let gas = await new GasSvr().estimateGas({ crypto, network: 'ARBITRUM' })
gas = gas * 0.0000000001
let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' })
let priceToSend = '0.1'
if (crypto.toLowerCase() === 'eth') {
priceToSend = price + ''
}
// 20230717 沟通, gas费需要换算成目标货币
let networkFee = gas
if (crypto.toLowerCase() === 'ceg') {
networkFee = networkFee * parseFloat(price) * 10
}
let { networkFee } = await calcNetworkFee(crypto, priceToSend, price)
let result = {
direct: 1,
data: {
@ -130,7 +125,7 @@ class AlchemyOutController extends BaseController {
networkList: [
{
network: 'ARBITRUM',
networkFee: networkFee.toFixed(6),
networkFee: fromWei(networkFee),
},
],
},
@ -189,13 +184,10 @@ class AlchemyOutController extends BaseController {
}
record.cryptoAmount =
record.network.toLowerCase() === 'agor' && record.crypto.toLowerCase() === 'agor' ? '0.001' : cryptoAmount
let gas = await new GasSvr().estimateGas({ crypto, network: 'ARBITRUM' })
gas = gas * 0.0000000001
// 20230718 沟通, cryptoAmount包含了gas费, 需要减去后再发送
let networkFee = gas
let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' })
networkFee = (networkFee * parseFloat(price)) / parseFloat(cryptoPrice)
record.cryptoSend = (parseFloat(cryptoAmount) - networkFee).toFixed(10)
let { networkFee } = await calcNetworkFee(crypto, cryptoPrice)
record.cryptoSend = fromWei(toBigWei(cryptoAmount) - networkFee)
record.networkFee = fromWei(networkFee)
record.cryptoPrice = cryptoPrice
record.usdtAdmount = usdtAmount
await record.save()

View File

@ -18,7 +18,7 @@ const notify = async function (record: DocumentType<PayRecordClass>, subTask: Do
let data: any = {
orderNo: record.outOrderId, // AlchemyPay订单号
crypto: record.crypto, // 用户购买的数字货币
cryptoAmount: record.cryptoAmount, //用户的提币数量
cryptoAmount: record.cryptoSend, //用户的提币数量
cryptoPrice: record.cryptoPrice, // 实时的价格/USDT CEG锚定USDT
txHash: record.txHash, // 给用户转账的hash
network: record.network, // 用户购买的数字货币对应的网络

View File

@ -61,6 +61,9 @@ export class PayRecordClass extends BaseModule {
@prop()
public cryptoSend?: string
@prop()
public networkFee?: string
// 开始创建记录时, 估算的可获取加密货币数量
@prop()
public cryptoAmountEstimate?: string

View File

@ -3,6 +3,9 @@ import { hmacsha256, sha1 } from 'utils/security.util'
import crypto from 'crypto'
import { generateKVStr } from 'utils/net.util'
import logger from 'logger/logger'
import { GasSvr } from './gas.svr'
import { toBigInt, toBigWei } from 'utils/number.util'
import { PriceSvr } from './price.svr'
export function createSimpleSign(data: any) {
let timestamp = Date.now()
@ -221,3 +224,21 @@ export async function queryFiat() {
let response = await axios(config)
return response.data
}
/**
* gas费,
* fromGwei转换成wei
* @param cryptoPrice
* @returns
*/
export async function calcNetworkFee(crypto: string, cryptoPrice: string, ethPrice?: string) {
let gasLimit = await new GasSvr().estimateGas({ crypto, network: 'ARBITRUM' })
// let gas = gas * 0.0000000001
const gasPriceArb = '100,000,000' // arbitrum one 上gasprice固定为0.1Gwei
let eth = toBigInt(gasLimit) * toBigInt(gasPriceArb)
// 20230718 沟通, cryptoAmount包含了gas费, 需要减去后再发送
if (!ethPrice) {
ethPrice = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' })
}
let networkFee = (eth * toBigWei(ethPrice)) / toBigWei(cryptoPrice)
return { networkFee, ethPrice }
}

View File

@ -33,7 +33,7 @@ export class GasSvr {
}
let priceData = res.data
if (!priceData.error) {
let gas = parseInt(priceData.result) * +process.env.CHAIN_GAS_BOOST
let gas = ((priceData.result | 1) * +process.env.CHAIN_GAS_BOOST) | 1
this.priceMap.set(key, gas)
}
} catch (e) {

30
src/test.ts Normal file
View File

@ -0,0 +1,30 @@
import { GasSvr } from 'service/gas.svr'
import { PriceSvr } from 'service/price.svr'
import { fromWei, toBigInt, toBigWei } from 'utils/number.util'
async function main() {
let cryptoPrice = '0.1'
let cryptoAmount = '10.305'
let crypto = 'CEG'
let gasLimit = '1,031,856'
// let gas = gas * 0.0000000001
let gas = toBigWei(gasLimit) / toBigInt('10,000,000,000')
// 20230718 沟通, cryptoAmount包含了gas费, 需要减去后再发送
let price = '1,980.2'
let networkFee = (gas * toBigWei(price)) / toBigWei(cryptoPrice)
console.log('networkFee::' + fromWei(networkFee))
let cryptoSend = fromWei(toBigWei(cryptoAmount) - networkFee)
console.log(cryptoSend)
// let gas = gas * 0.0000000001
const gasPriceArb = '100,000,000' // arbitrum one 上gasprice固定为0.1Gwei
let eth = toBigInt(gasLimit) * toBigInt(gasPriceArb)
let ethPrice = '1,980.2'
let networkFee2 = (eth * toBigWei(ethPrice)) / toBigWei(cryptoPrice)
console.log('networkFee2::' + fromWei(networkFee2))
let cryptoSend2 = fromWei(toBigWei(cryptoAmount) - networkFee2)
console.log(fromWei(toBigWei(cryptoSend2)))
}
main()

218
src/utils/number.util.ts Normal file
View File

@ -0,0 +1,218 @@
export declare type HexString = string
export declare type Numbers = number | bigint | string | HexString
const isHexStrict = hex => typeof hex === 'string' && /^((-)?0x[0-9a-f]+|(0x))$/i.test(hex)
export declare type ValidInputTypes = Uint8Array | bigint | string | number | boolean
export const isHex = (hex: ValidInputTypes): boolean =>
typeof hex === 'number' ||
typeof hex === 'bigint' ||
(typeof hex === 'string' && /^((-0x|0x|-)?[0-9a-f]+|(0x))$/i.test(hex))
const base = BigInt(10)
const expo10 = (expo: number) => base ** BigInt(expo)
export const ethUnitMap = {
noether: BigInt('0'),
wei: BigInt(1),
kwei: expo10(3),
Kwei: expo10(3),
babbage: expo10(3),
femtoether: expo10(3),
mwei: expo10(6),
Mwei: expo10(6),
lovelace: expo10(6),
picoether: expo10(6),
gwei: expo10(9),
Gwei: expo10(9),
shannon: expo10(9),
nanoether: expo10(9),
nano: expo10(9),
szabo: expo10(12),
microether: expo10(12),
micro: expo10(12),
finney: expo10(15),
milliether: expo10(15),
milli: expo10(15),
ether: expo10(18),
kether: expo10(21),
grand: expo10(21),
mether: expo10(24),
gether: expo10(27),
tether: expo10(30),
}
export type EtherUnits = keyof typeof ethUnitMap
/**
* Converts value to it's number representation
*/
export const hexToNumber = (value: string): bigint | number => {
if (!isHexStrict(value)) {
throw new Error('Invalid hex string')
}
const [negative, hexValue] = value.startsWith('-') ? [true, value.slice(1)] : [false, value]
const num = BigInt(hexValue)
if (num > Number.MAX_SAFE_INTEGER) {
return negative ? -num : num
}
if (num < Number.MIN_SAFE_INTEGER) {
return num
}
return negative ? -1 * Number(num) : Number(num)
}
export const toNumber = (value: Numbers): number | bigint => {
if (typeof value === 'number') {
return value
}
if (typeof value === 'bigint') {
return value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER ? Number(value) : value
}
if (typeof value === 'string' && isHexStrict(value)) {
return hexToNumber(value)
}
try {
return toNumber(BigInt(value))
} catch {
throw new Error('ivalid number: ' + value)
}
}
/**
* Auto converts any given value into it's bigint representation
*
* @param value - The value to convert
* @returns - Returns the value in bigint representation
* @example
* ```ts
* console.log(web3.utils.toBigInt(1));
* > 1n
* ```
*/
export const toBigInt = (value: unknown): bigint => {
if (typeof value === 'number') {
return BigInt(value)
}
if (typeof value === 'bigint') {
return value
}
// isHex passes for dec, too
if (typeof value === 'string' && isHex(value)) {
return BigInt(value)
}
if (typeof value === 'string' && value.indexOf(',') >= 0) {
return BigInt(value.replace(/,/g, ''))
}
throw new Error('invalid number' + value)
}
export const toBigWei = (number: Numbers, unit: EtherUnits = 'ether'): bigint => {
return toBigInt(toWei(number, unit))
}
export const toWei = (number: Numbers, unit: EtherUnits = 'ether'): string => {
const denomination = ethUnitMap[unit]
if (!denomination) {
throw new Error('error unit: ' + unit)
}
// if value is decimal e.g. 24.56 extract `integer` and `fraction` part
// to avoid `fraction` to be null use `concat` with empty string
typeof number === 'string' && number.indexOf(',') >= 0 && (number = number.replace(/,/g, ''))
const [integer, fraction] = String(typeof number === 'string' && !isHexStrict(number) ? number : toNumber(number))
.split('.')
.concat('')
// join the value removing `.` from
// 24.56 -> 2456
const value = BigInt(`${integer}${fraction}`)
// multiply value with denomination
// 2456 * 1000000 -> 2456000000
const updatedValue = value * denomination
// count number of zeros in denomination
const numberOfZerosInDenomination = denomination.toString().length - 1
// check which either `fraction` or `denomination` have lower number of zeros
const decimals = Math.min(fraction.length, numberOfZerosInDenomination)
if (decimals === 0) {
return updatedValue.toString()
}
// Add zeros to make length equal to required decimal points
// If string is larger than decimal points required then remove last zeros
return updatedValue.toString().padStart(decimals, '0').slice(0, -decimals)
}
/**
* Takes a number of wei and converts it to any other ether unit.
* @param number - The value in wei
* @param unit - The unit to convert to
* @returns - Returns the converted value in the given unit
*
* @example
* ```ts
* console.log(web3.utils.fromWei("1", "ether"));
* > 0.000000000000000001
*
* console.log(web3.utils.fromWei("1", "shannon"));
* > 0.000000001
* ```
*/
export const fromWei = (number: Numbers, unit: EtherUnits = 'ether'): string => {
const denomination = ethUnitMap[unit]
if (!denomination) {
throw new Error('invalid unit: ' + unit)
}
// value in wei would always be integer
// 13456789, 1234
const value = String(toNumber(number))
// count number of zeros in denomination
// 1000000 -> 6
const numberOfZerosInDenomination = denomination.toString().length - 1
if (numberOfZerosInDenomination <= 0) {
return value.toString()
}
// pad the value with required zeros
// 13456789 -> 13456789, 1234 -> 001234
const zeroPaddedValue = value.padStart(numberOfZerosInDenomination, '0')
// get the integer part of value by counting number of zeros from start
// 13456789 -> '13'
// 001234 -> ''
const integer = zeroPaddedValue.slice(0, -numberOfZerosInDenomination)
// get the fraction part of value by counting number of zeros backward
// 13456789 -> '456789'
// 001234 -> '001234'
const fraction = zeroPaddedValue.slice(-numberOfZerosInDenomination).replace(/\.?0+$/, '')
if (integer === '') {
return `0.${fraction}`
}
if (fraction === '') {
return integer
}
return `${integer}.${fraction}`
}