-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(trading): gas fee estimation for withdraw transaction (#5668)
- Loading branch information
Showing
13 changed files
with
464 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import BigNumber from 'bignumber.js'; | ||
import { EtherUnit, formatEther, unitiseEther } from './ether'; | ||
|
||
describe('unitiseEther', () => { | ||
it.each([ | ||
[1, '1', EtherUnit.wei], | ||
[999, '999', EtherUnit.wei], | ||
[1000, '1', EtherUnit.kwei], | ||
[9999, '9.999', EtherUnit.kwei], | ||
[10000, '10', EtherUnit.kwei], | ||
[999999, '999.999', EtherUnit.kwei], | ||
[1000000, '1', EtherUnit.mwei], | ||
[999999999, '999.999999', EtherUnit.mwei], | ||
[1000000000, '1', EtherUnit.gwei], | ||
['999999999999999999', '999999999.999999999', EtherUnit.gwei], // max gwei | ||
[1e18, '1', EtherUnit.ether], // 1 ETH | ||
[1234e18, '1234', EtherUnit.ether], // 1234 ETH | ||
])('unitises %s to [%s, %s]', (value, expectedOutput, expectedUnit) => { | ||
const [output, unit] = unitiseEther(value); | ||
expect(output.toFixed()).toEqual(expectedOutput); | ||
expect(unit).toEqual(expectedUnit); | ||
}); | ||
|
||
it('unitises to requested unit', () => { | ||
const [output, unit] = unitiseEther(1, EtherUnit.kwei); | ||
expect(output).toEqual(BigNumber(0.001)); | ||
expect(unit).toEqual(EtherUnit.kwei); | ||
}); | ||
}); | ||
|
||
describe('formatEther', () => { | ||
it.each([ | ||
[1, EtherUnit.wei, '1 wei'], | ||
[12, EtherUnit.kwei, '12 kwei'], | ||
[123, EtherUnit.gwei, '123 gwei'], | ||
[3, EtherUnit.ether, '3 ETH'], | ||
[234.67776331, EtherUnit.gwei, '235 gwei'], | ||
[12.12, EtherUnit.gwei, '12 gwei'], | ||
])('formats [%s, %s] to "%s"', (value, unit, expectedOutput) => { | ||
expect(formatEther([BigNumber(value), unit])).toEqual(expectedOutput); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { formatNumber, toBigNum } from './number'; | ||
import type BigNumber from 'bignumber.js'; | ||
|
||
export enum EtherUnit { | ||
/** 1 wei = 10^-18 ETH */ | ||
wei = '0', | ||
/** 1 kwei = 1000 wei */ | ||
kwei = '3', | ||
/** 1 mwei = 1000 kwei */ | ||
mwei = '6', | ||
/** 1 gwei = 1000 kwei */ | ||
gwei = '9', | ||
|
||
// other denominations: | ||
// microether = '12', // aka szabo, µETH | ||
// milliether = '15', // aka finney, mETH | ||
|
||
/** 1 ETH = 1B gwei = 10^18 wei */ | ||
ether = '18', | ||
} | ||
|
||
export const etherUnitMapping: Record<EtherUnit, string> = { | ||
[EtherUnit.wei]: 'wei', | ||
[EtherUnit.kwei]: 'kwei', | ||
[EtherUnit.mwei]: 'mwei', | ||
[EtherUnit.gwei]: 'gwei', | ||
// [EtherUnit.microether]: 'µETH', // szabo | ||
// [EtherUnit.milliether]: 'mETH', // finney | ||
[EtherUnit.ether]: 'ETH', | ||
}; | ||
|
||
type InputValue = string | number | BigNumber; | ||
type UnitisedTuple = [value: BigNumber, unit: EtherUnit]; | ||
|
||
/** | ||
* Converts given raw value to the unitised tuple of amount and unit | ||
*/ | ||
export const unitiseEther = ( | ||
input: InputValue, | ||
forceUnit?: EtherUnit | ||
): UnitisedTuple => { | ||
const units = Object.values(EtherUnit).reverse(); | ||
|
||
let value = toBigNum(input, Number(forceUnit || EtherUnit.ether)); | ||
let unit = forceUnit || EtherUnit.ether; | ||
|
||
if (!forceUnit) { | ||
for (const u of units) { | ||
const v = toBigNum(input, Number(u)); | ||
value = v; | ||
unit = u; | ||
if (v.isGreaterThanOrEqualTo(1)) break; | ||
} | ||
} | ||
|
||
return [value, unit]; | ||
}; | ||
|
||
/** | ||
* `formatNumber` wrapper for unitised ether values (attaches unit name) | ||
*/ | ||
export const formatEther = ( | ||
input: UnitisedTuple, | ||
decimals = 0, | ||
noUnit = false | ||
) => { | ||
const [value, unit] = input; | ||
const num = formatNumber(value, decimals); | ||
const unitName = noUnit ? '' : etherUnitMapping[unit]; | ||
|
||
return `${num} ${unitName}`.trim(); | ||
}; | ||
|
||
/** | ||
* Utility function that formats given raw amount as ETH. | ||
* Example: | ||
* Given value of `1` this will return `0.000000000000000001 ETH` | ||
*/ | ||
export const asETH = (input: InputValue, noUnit = false) => | ||
formatEther( | ||
unitiseEther(input, EtherUnit.ether), | ||
Number(EtherUnit.ether), | ||
noUnit | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { useWeb3React } from '@web3-react/core'; | ||
import { useEthereumConfig } from './use-ethereum-config'; | ||
import BigNumber from 'bignumber.js'; | ||
|
||
const DEFAULT_INTERVAL = 15000; // 15 seconds | ||
|
||
/** | ||
* These are the hex values of the collateral bridge contract methods. | ||
* | ||
* Collateral bridge address: 0x23872549cE10B40e31D6577e0A920088B0E0666a | ||
* Etherscan: https://etherscan.io/address/0x23872549cE10B40e31D6577e0A920088B0E0666a#writeContract | ||
*/ | ||
export enum ContractMethod { | ||
DEPOSIT_ASSET = '0xf7683932', | ||
EXEMPT_DEPOSITOR = '0xb76fbb75', | ||
GLOBAL_RESUME = '0xd72ed529', | ||
GLOBAL_STOP = '0x9dfd3c88', | ||
LIST_ASSET = '0x0ff3562c', | ||
REMOVE_ASSET = '0xc76de358', | ||
REVOKE_EXEMPT_DEPOSITOR = '0x6a1c6fa4', | ||
SET_ASSET_LIMITS = '0x41fb776d', | ||
SET_WITHDRAW_DELAY = '0x5a246728', | ||
WITHDRAW_ASSET = '0x3ad90635', | ||
} | ||
|
||
export type GasData = { | ||
/** The base (minimum) price of 1 unit of gas */ | ||
basePrice: BigNumber; | ||
/** The maximum price of 1 unit of gas */ | ||
maxPrice: BigNumber; | ||
/** The amount of gas (units) needed to process a transaction */ | ||
gas: BigNumber; | ||
}; | ||
|
||
type Provider = NonNullable<ReturnType<typeof useWeb3React>['provider']>; | ||
|
||
const retrieveGasData = async ( | ||
provider: Provider, | ||
account: string, | ||
contractAddress: string, | ||
contractMethod: ContractMethod | ||
) => { | ||
try { | ||
const data = await provider.getFeeData(); | ||
const estGasAmount = await provider.estimateGas({ | ||
to: account, | ||
from: contractAddress, | ||
data: contractMethod, | ||
}); | ||
|
||
if (data.lastBaseFeePerGas && data.maxFeePerGas) { | ||
return { | ||
// converts also form ethers BigNumber to "normal" BigNumber | ||
basePrice: BigNumber(data.lastBaseFeePerGas.toString()), | ||
maxPrice: BigNumber(data.maxFeePerGas.toString()), | ||
gas: BigNumber(estGasAmount.toString()), | ||
}; | ||
} | ||
} catch (err) { | ||
// NOOP - could not get the estimated gas or the fee data from | ||
// the network. This could happen if there's an issue with transaction | ||
// request parameters (e.g. to/from mismatch) | ||
} | ||
|
||
return undefined; | ||
}; | ||
|
||
/** | ||
* Gets the "current" gas price from the ethereum network. | ||
*/ | ||
export const useGasPrice = ( | ||
method: ContractMethod, | ||
interval = DEFAULT_INTERVAL | ||
): GasData | undefined => { | ||
const [gas, setGas] = useState<GasData | undefined>(undefined); | ||
const { provider, account } = useWeb3React(); | ||
const { config } = useEthereumConfig(); | ||
|
||
useEffect(() => { | ||
if (!provider || !config || !account) return; | ||
|
||
const retrieve = async () => { | ||
retrieveGasData( | ||
provider, | ||
account, | ||
config.collateral_bridge_contract.address, | ||
method | ||
).then((gasData) => { | ||
if (gasData) { | ||
setGas(gasData); | ||
} | ||
}); | ||
}; | ||
retrieve(); | ||
|
||
// Retrieves another estimation and prices in [interval] ms. | ||
let i: ReturnType<typeof setInterval>; | ||
if (interval > 0) { | ||
i = setInterval(() => { | ||
retrieve(); | ||
}, interval); | ||
} | ||
|
||
return () => { | ||
if (i) clearInterval(i); | ||
}; | ||
}, [account, config, interval, method, provider]); | ||
|
||
return gas; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.