Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
feat: preview network fee using price factor (#295)
Browse files Browse the repository at this point in the history
feat: add price factor on preview gas fee
  • Loading branch information
luizstacio authored Jun 18, 2022
1 parent 4b2ed2e commit b237711
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 20 deletions.
2 changes: 1 addition & 1 deletion docker/fuel-core/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ghcr.io/fuellabs/fuel-core:v0.8.0
FROM ghcr.io/fuellabs/fuel-core:v0.9.2

ARG IP=0.0.0.0
ARG PORT=4000
Expand Down
3 changes: 2 additions & 1 deletion docker/fuel-core/chainConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"max_static_contracts": 255,
"max_storage_slots": 255,
"max_predicate_length": 1048576,
"max_predicate_data_length": 1048576
"max_predicate_data_length": 1048576,
"gas_price_factor": 1000000
},
"wallet": {
"address": "0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/systems/Core/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './useEthBalance';
export * from './useSlippage';
export * from './useTokensMethods';
export * from './useWallet';
export * from './useChainConfig';
8 changes: 8 additions & 0 deletions packages/app/src/systems/Core/hooks/useChainConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useQuery } from 'react-query';

import { getChainConfig } from '../utils/gas';

export function useChainConfig() {
const { data } = useQuery('ChainConfig', async () => getChainConfig());
return data;
}
83 changes: 73 additions & 10 deletions packages/app/src/systems/Core/utils/gas.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { CallResult, Overrides, ScriptTransactionRequest } from 'fuels';
import { arrayify, Provider, ReceiptType } from 'fuels';

import { toBigInt, toNumber, ZERO } from './math';
import { divideFnValidOnly, toBigInt, toNumber, ZERO } from './math';

import { BYTE_PRICE, FUEL_PROVIDER_URL, GAS_PRICE } from '~/config';

export function getGasFee(simulateResult: CallResult) {
export function getGasUsed(simulateResult: CallResult) {
const scriptResult = simulateResult.receipts.find(
(receipt) => receipt.type === ReceiptType.ScriptResult
);
Expand All @@ -15,31 +15,92 @@ export function getGasFee(simulateResult: CallResult) {
return ZERO;
}

export type ChainConfig = {
nodeInfo: {
minGasPrice: string;
minBytePrice: string;
};
chain: {
consensusParameters: {
gasPriceFactor: string;
};
latestBlock: {
height: string;
};
};
};

export async function getChainConfig(): Promise<ChainConfig> {
// TODO: replace this for a SDK provider query
const chainConfigQuery = `query {
nodeInfo {
minGasPrice
minBytePrice
}
chain {
consensusParameters {
gasPriceFactor
}
latestBlock {
height
}
}
}`;
const chainConfigResponse = await fetch(FUEL_PROVIDER_URL, {
method: 'POST',
headers: {
accept: '*/*',
'content-type': 'application/json',
},
body: JSON.stringify({
operationName: null,
variables: {},
query: chainConfigQuery,
}),
}).then<{ data: ChainConfig }>((resp) => resp.json());
return chainConfigResponse.data;
}

export type TransactionCost = {
gas: bigint;
byte: bigint;
total: bigint;
fee: bigint;
error?: string;
};

export function transactionByteSize(request: ScriptTransactionRequest) {
const byteSize = toBigInt(request.toTransactionBytes().length * BYTE_PRICE);
const witnessesByteSize = toBigInt(
request.witnesses.reduce((t, witnesses) => t + arrayify(witnesses).length, 0)
const byteSize = request.toTransactionBytes().length;
const witnessesByteSize = request.witnesses.reduce(
(t, witnesses) => t + arrayify(witnesses).length,
0
);

return byteSize - witnessesByteSize;
return toBigInt(byteSize - witnessesByteSize);
}

export function emptyTransactionCost(error?: string) {
return {
fee: ZERO,
total: ZERO,
gas: ZERO,
byte: ZERO,
error,
};
}

function getPriceByFactor(total: bigint, chainConfig: ChainConfig) {
return toBigInt(
Math.ceil(divideFnValidOnly(total, chainConfig.chain.consensusParameters.gasPriceFactor))
);
}

export function getTotalFee(gasUsed: bigint, byteSize: bigint, chainConfig?: ChainConfig) {
if (!chainConfig) return ZERO;
const gasFee = gasUsed * toBigInt(chainConfig.nodeInfo.minGasPrice);
const byteFee = byteSize * toBigInt(chainConfig.nodeInfo.minBytePrice);
return getPriceByFactor(gasFee, chainConfig) + getPriceByFactor(byteFee, chainConfig);
}

export async function getTransactionCost(
requestPromise: Promise<ScriptTransactionRequest>
): Promise<TransactionCost> {
Expand All @@ -49,17 +110,19 @@ export async function getTransactionCost(
// measure gasUsed without needing to have balance
request.gasPrice = ZERO;
request.bytePrice = ZERO;
const chainConfig = await getChainConfig();
const provider = new Provider(FUEL_PROVIDER_URL);
const dryRunResult = await provider.call(request);
const gasFee = getGasFee(dryRunResult) * toBigInt(GAS_PRICE);
const gasUsed = getGasUsed(dryRunResult);
const byte = transactionByteSize(request);
const gas = toBigInt(Math.ceil(toNumber(gasFee) * 1.1));
const gas = toBigInt(Math.ceil(toNumber(gasUsed) * 1.1));
const total = gas + byte;

return {
total,
gas,
byte,
total,
fee: getTotalFee(gasUsed, byte, chainConfig),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/systems/Mint/pages/MintPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function MintPage() {
<BsArrowDown size={20} className="text-gray-400" />
</div>
<PreviewTable className="mt-2 bg-transparent">
<NetworkFeePreviewItem networkFee={mint.txCost.total} />
<NetworkFeePreviewItem networkFee={mint.txCost.fee} />
</PreviewTable>
</>
)}
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/systems/Pool/hooks/useAddLiquidity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function useAddLiquidity({
// multi-call on fuels-ts for now we are using
// the local tx measures with a + 50% margin to avoid issues
// TODO: https://github.com/FuelLabs/swayswap-demo/issues/42
const networkFee = toBigInt(2000000);
const networkFee = toBigInt(10);

useEffect(() => {
fromInput.setGasFee(networkFee);
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/systems/Pool/pages/RemoveLiquidity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export function RemoveLiquidityPage() {
setErrors(validateRemoveLiquidity());
}, [tokenInput.amount, tokenInput.hasEnoughBalance]);

const hasEnoughBalance = (ethBalance.raw || ZERO) > txCost.total;
const hasEnoughBalance = (ethBalance.raw || ZERO) > txCost.fee;
const isRemoveButtonDisabled =
!!errors.length ||
removeLiquidityMutation.isLoading ||
Expand Down Expand Up @@ -128,7 +128,7 @@ export function RemoveLiquidityPage() {
bottomElement={<CoinBalance {...tokenInput.getCoinBalanceProps()} />}
/>
</div>
<RemoveLiquidityPreview networkFee={txCost?.total} amount={amount} />
<RemoveLiquidityPreview networkFee={txCost.fee} amount={amount} />
<Button
isFull
size="lg"
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/systems/Swap/pages/SwapPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ export function SwapPage() {
Swap
</Card.Title>
<SwapComponent
networkFee={txCost?.total}
networkFee={txCost?.fee}
previewAmount={previewAmount}
onChange={handleSwap}
isLoading={isLoading}
/>
<SwapPreview
networkFee={txCost?.total}
networkFee={txCost?.fee}
isLoading={isLoading}
swapInfo={swapInfo}
/>
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/systems/Swap/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const notHasBalanceWithSlippage = ({
);

if (swapState!.coinFrom.assetId === COIN_ETH) {
amountWithSlippage += txCost?.total || ZERO;
amountWithSlippage += txCost?.fee || ZERO;
}

return amountWithSlippage > currentBalance;
Expand All @@ -121,7 +121,7 @@ const hasEthForNetworkFee = ({ balances, txCost }: StateParams) => {
const currentBalance = toNumber(
balances?.find((coin) => coin.assetId === COIN_ETH)?.amount || ZERO
);
return currentBalance > (txCost?.total || ZERO);
return currentBalance > (txCost?.fee || ZERO);
};

export const getValidationState = (stateParams: StateParams): ValidationStateEnum => {
Expand Down

0 comments on commit b237711

Please sign in to comment.