修改alchemy逻辑,减去gas费后再计算crypto数量
This commit is contained in:
parent
9799a86817
commit
3c7ff25fac
@ -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()
|
||||
|
@ -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, // 用户购买的数字货币对应的网络
|
||||
|
@ -61,6 +61,9 @@ export class PayRecordClass extends BaseModule {
|
||||
@prop()
|
||||
public cryptoSend?: string
|
||||
|
||||
@prop()
|
||||
public networkFee?: string
|
||||
|
||||
// 开始创建记录时, 估算的可获取加密货币数量
|
||||
@prop()
|
||||
public cryptoAmountEstimate?: string
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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
30
src/test.ts
Normal 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
218
src/utils/number.util.ts
Normal 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}`
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user