修改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 BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||||
import { ZError } from 'common/ZError'
|
import { ZError } from 'common/ZError'
|
||||||
import { role, router } from 'decorators/router'
|
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 { PayRecord, PayStatus } from 'modules/PayRecord'
|
||||||
import { TransferQueue } from 'queue/transfer.queue'
|
import { TransferQueue } from 'queue/transfer.queue'
|
||||||
import { TransferRecord } from 'modules/TransferRecord'
|
import { TransferRecord } from 'modules/TransferRecord'
|
||||||
@ -11,6 +11,7 @@ import { PriceSvr } from 'service/price.svr'
|
|||||||
import { OrderCacheSvr } from 'service/ordercache.svr'
|
import { OrderCacheSvr } from 'service/ordercache.svr'
|
||||||
import { GasSvr } from 'service/gas.svr'
|
import { GasSvr } from 'service/gas.svr'
|
||||||
import { parse } from 'dotenv'
|
import { parse } from 'dotenv'
|
||||||
|
import { toBigInt, toWei, fromWei, EtherUnits, toBigWei } from 'utils/number.util'
|
||||||
|
|
||||||
let errorRes = function (msg: string) {
|
let errorRes = function (msg: string) {
|
||||||
logger.info(`error res: ${msg}`)
|
logger.info(`error res: ${msg}`)
|
||||||
@ -110,19 +111,13 @@ class AlchemyOutController extends BaseController {
|
|||||||
if (!checkSha1Sign(req.headers)) {
|
if (!checkSha1Sign(req.headers)) {
|
||||||
return errorRes('sign error')
|
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 price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' })
|
||||||
let priceToSend = '0.1'
|
let priceToSend = '0.1'
|
||||||
if (crypto.toLowerCase() === 'eth') {
|
if (crypto.toLowerCase() === 'eth') {
|
||||||
priceToSend = price + ''
|
priceToSend = price + ''
|
||||||
}
|
}
|
||||||
// 20230717 沟通, gas费需要换算成目标货币
|
// 20230717 沟通, gas费需要换算成目标货币
|
||||||
let networkFee = gas
|
let { networkFee } = await calcNetworkFee(crypto, priceToSend, price)
|
||||||
if (crypto.toLowerCase() === 'ceg') {
|
|
||||||
networkFee = networkFee * parseFloat(price) * 10
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = {
|
let result = {
|
||||||
direct: 1,
|
direct: 1,
|
||||||
data: {
|
data: {
|
||||||
@ -130,7 +125,7 @@ class AlchemyOutController extends BaseController {
|
|||||||
networkList: [
|
networkList: [
|
||||||
{
|
{
|
||||||
network: 'ARBITRUM',
|
network: 'ARBITRUM',
|
||||||
networkFee: networkFee.toFixed(6),
|
networkFee: fromWei(networkFee),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -189,13 +184,10 @@ class AlchemyOutController extends BaseController {
|
|||||||
}
|
}
|
||||||
record.cryptoAmount =
|
record.cryptoAmount =
|
||||||
record.network.toLowerCase() === 'agor' && record.crypto.toLowerCase() === 'agor' ? '0.001' : 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费, 需要减去后再发送
|
// 20230718 沟通, cryptoAmount包含了gas费, 需要减去后再发送
|
||||||
let networkFee = gas
|
let { networkFee } = await calcNetworkFee(crypto, cryptoPrice)
|
||||||
let price = await new PriceSvr().fetchPrice({ crypto: 'ETH', network: 'ARBITRUM', fiat: 'USD' })
|
record.cryptoSend = fromWei(toBigWei(cryptoAmount) - networkFee)
|
||||||
networkFee = (networkFee * parseFloat(price)) / parseFloat(cryptoPrice)
|
record.networkFee = fromWei(networkFee)
|
||||||
record.cryptoSend = (parseFloat(cryptoAmount) - networkFee).toFixed(10)
|
|
||||||
record.cryptoPrice = cryptoPrice
|
record.cryptoPrice = cryptoPrice
|
||||||
record.usdtAdmount = usdtAmount
|
record.usdtAdmount = usdtAmount
|
||||||
await record.save()
|
await record.save()
|
||||||
|
@ -18,7 +18,7 @@ const notify = async function (record: DocumentType<PayRecordClass>, subTask: Do
|
|||||||
let data: any = {
|
let data: any = {
|
||||||
orderNo: record.outOrderId, // AlchemyPay订单号
|
orderNo: record.outOrderId, // AlchemyPay订单号
|
||||||
crypto: record.crypto, // 用户购买的数字货币
|
crypto: record.crypto, // 用户购买的数字货币
|
||||||
cryptoAmount: record.cryptoAmount, //用户的提币数量
|
cryptoAmount: record.cryptoSend, //用户的提币数量
|
||||||
cryptoPrice: record.cryptoPrice, // 实时的价格/USDT CEG锚定USDT
|
cryptoPrice: record.cryptoPrice, // 实时的价格/USDT CEG锚定USDT
|
||||||
txHash: record.txHash, // 给用户转账的hash
|
txHash: record.txHash, // 给用户转账的hash
|
||||||
network: record.network, // 用户购买的数字货币对应的网络
|
network: record.network, // 用户购买的数字货币对应的网络
|
||||||
|
@ -61,6 +61,9 @@ export class PayRecordClass extends BaseModule {
|
|||||||
@prop()
|
@prop()
|
||||||
public cryptoSend?: string
|
public cryptoSend?: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public networkFee?: string
|
||||||
|
|
||||||
// 开始创建记录时, 估算的可获取加密货币数量
|
// 开始创建记录时, 估算的可获取加密货币数量
|
||||||
@prop()
|
@prop()
|
||||||
public cryptoAmountEstimate?: string
|
public cryptoAmountEstimate?: string
|
||||||
|
@ -3,6 +3,9 @@ import { hmacsha256, sha1 } from 'utils/security.util'
|
|||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import { generateKVStr } from 'utils/net.util'
|
import { generateKVStr } from 'utils/net.util'
|
||||||
import logger from 'logger/logger'
|
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) {
|
export function createSimpleSign(data: any) {
|
||||||
let timestamp = Date.now()
|
let timestamp = Date.now()
|
||||||
@ -221,3 +224,21 @@ export async function queryFiat() {
|
|||||||
let response = await axios(config)
|
let response = await axios(config)
|
||||||
return response.data
|
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
|
let priceData = res.data
|
||||||
if (!priceData.error) {
|
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)
|
this.priceMap.set(key, gas)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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