@lido-sdk/react
Version:
This project is being slowly deprecated and may not receive further updates. Check out [modern Lido SDK](https://github.com/lidofinance/lido-ethereum-sdk/pulls) to access latest functionality. It is actively maintained and is built for interacting with Li
146 lines (139 loc) • 7.27 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var tslib_es6 = require('../node_modules/tslib/tslib.es6.js');
var warning = require('tiny-warning');
var invariant = require('tiny-invariant');
var react = require('react');
var bignumber = require('@ethersproject/bignumber');
var bytes = require('@ethersproject/bytes');
var useSDK = require('./useSDK.js');
var useLidoSWR = require('./useLidoSWR.js');
var useDebounceCallback = require('./useDebounceCallback.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var warning__default = /*#__PURE__*/_interopDefaultLegacy(warning);
var invariant__default = /*#__PURE__*/_interopDefaultLegacy(invariant);
const MAX_BLOCKS_PER_REQUEST = 1024;
const DEFAULT_HISTORY_BLOCKS = MAX_BLOCKS_PER_REQUEST;
const DEFAULT_CACHE_DATA = Object.freeze({
oldestBlock: -1,
baseFeePerGas: Object.freeze([]),
gasUsedRatio: Object.freeze([]),
});
const historyCache = new Map();
const getBlockNumber = (provider) => tslib_es6.__awaiter(void 0, void 0, void 0, function* () {
const cachedNumber = provider.blockNumber;
return cachedNumber === -1 ? yield provider.getBlockNumber() : cachedNumber;
});
const getChunksArguments = (fromBlock, toBlock, chunkSize = MAX_BLOCKS_PER_REQUEST) => {
invariant__default["default"](fromBlock <= toBlock, 'fromBlock should be less than or equal to toBlock');
invariant__default["default"](chunkSize > 0, 'chunkSize should be greater than 0');
const totalBlocks = toBlock - fromBlock + 1;
const totalChunks = Math.ceil(totalBlocks / chunkSize);
return Array.from({ length: totalChunks }, (_value, index) => {
const newestBlock = toBlock - chunkSize * index;
const blocks = Math.min(1 + newestBlock - fromBlock, chunkSize);
return [blocks, bytes.hexValue(bignumber.BigNumber.from(newestBlock)), []];
}).reverse();
};
const combineHistory = (...histories) => {
histories.forEach((currentHistory, index) => {
if (index === 0)
return;
const previousHistory = histories[index - 1];
invariant__default["default"](currentHistory.oldestBlock ===
previousHistory.oldestBlock + previousHistory.baseFeePerGas.length - 1, 'Histories cannot be merged');
}, []);
const lastHistory = histories[histories.length - 1];
const lastHistoryFees = lastHistory.baseFeePerGas;
const lastFeePerGas = lastHistoryFees[lastHistoryFees.length - 1];
const oldestBlock = histories[0].oldestBlock;
const baseFeePerGas = histories
.flatMap(({ baseFeePerGas }) => baseFeePerGas.slice(0, -1))
.concat(lastFeePerGas);
const gasUsedRatio = histories.flatMap(({ gasUsedRatio }) => gasUsedRatio);
return {
oldestBlock,
baseFeePerGas,
gasUsedRatio,
};
};
const trimHistory = (history, blocks) => {
invariant__default["default"](blocks > 0, 'blocks number should be greater than 0');
const currentBlocks = history.gasUsedRatio.length;
const trimmedBlocks = Math.max(0, currentBlocks - blocks);
const oldestBlock = history.oldestBlock + trimmedBlocks;
const baseFeePerGas = history.baseFeePerGas.slice(-(blocks + 1));
const gasUsedRatio = history.gasUsedRatio.slice(-blocks);
return {
oldestBlock,
baseFeePerGas,
gasUsedRatio,
};
};
const getFeeHistory = (provider, fromBlock, toBlock, chunkSize) => tslib_es6.__awaiter(void 0, void 0, void 0, function* () {
const chunksArgs = getChunksArguments(fromBlock, toBlock, chunkSize);
const histories = yield Promise.all(chunksArgs.map((args) => {
return provider.send('eth_feeHistory', args);
}));
const convertedHistories = histories.map((history) => (Object.assign(Object.assign({}, history), { oldestBlock: bignumber.BigNumber.from(history.oldestBlock).toNumber(), baseFeePerGas: history.baseFeePerGas.map((fee) => bignumber.BigNumber.from(fee)) })));
return combineHistory(...convertedHistories);
});
const useFeeHistory = (props) => {
var _a, _b;
const { shouldFetch = true, blocks = DEFAULT_HISTORY_BLOCKS, config, } = props || {};
const providerRpcFromSdk = useSDK.useSDK().providerRpc;
const providerRpc = (_a = props === null || props === void 0 ? void 0 : props.providerRpc) !== null && _a !== void 0 ? _a : providerRpcFromSdk;
const providerWeb3FromSdk = useSDK.useSDK().providerWeb3;
const providerWeb3 = (_b = props === null || props === void 0 ? void 0 : props.providerWeb3) !== null && _b !== void 0 ? _b : providerWeb3FromSdk;
const { chainId } = useSDK.useSDK();
invariant__default["default"](providerRpc != null, 'RPC Provider is not provided');
invariant__default["default"](blocks > 0, 'blocks number should be greater than 0');
const result = useLidoSWR.useLidoSWR(shouldFetch ? [providerRpc, chainId, blocks] : null, (providerRpc, chainId, blocks) => tslib_es6.__awaiter(void 0, void 0, void 0, function* () {
var _c;
const currentBlock = yield getBlockNumber(providerRpc);
const cachedHistory = (_c = historyCache.get(chainId)) !== null && _c !== void 0 ? _c : DEFAULT_CACHE_DATA;
const oldestCachedBlock = cachedHistory.oldestBlock;
const blocksInCache = cachedHistory.gasUsedRatio.length;
const newestCachedBlock = blocksInCache
? oldestCachedBlock + blocksInCache - 1
: -1;
const firstRequiredBlock = currentBlock - blocks + 1;
if (blocksInCache && newestCachedBlock >= currentBlock) {
return cachedHistory;
}
const fromBlock = Math.max(newestCachedBlock + 1, firstRequiredBlock);
const toBlock = currentBlock;
const newHistory = yield getFeeHistory(providerRpc, fromBlock, toBlock);
const shouldCombine = blocksInCache
? newestCachedBlock < newHistory.oldestBlock
: false;
const combinedHistory = shouldCombine
? combineHistory(cachedHistory, newHistory)
: newHistory;
const trimmedHistory = trimHistory(combinedHistory, blocks);
historyCache.set(chainId, trimmedHistory);
return trimmedHistory;
}), config);
const updateHistory = useDebounceCallback.useDebounceCallback(result.update);
const subscribeToUpdates = react.useCallback(() => {
const provider = providerWeb3 || providerRpc;
try {
provider.on('block', updateHistory);
return () => {
provider.off('block', updateHistory);
};
}
catch (error) {
return warning__default["default"](false, 'Cannot subscribe to Block event');
}
}, [providerRpc, providerWeb3, updateHistory]);
react.useEffect(subscribeToUpdates, [subscribeToUpdates]);
return result;
};
exports.combineHistory = combineHistory;
exports.getBlockNumber = getBlockNumber;
exports.getChunksArguments = getChunksArguments;
exports.getFeeHistory = getFeeHistory;
exports.historyCache = historyCache;
exports.trimHistory = trimHistory;
exports.useFeeHistory = useFeeHistory;