Skip to content

Commit

Permalink
Merge pull request #99 from lidofinance/develop
Browse files Browse the repository at this point in the history
Develop to main
  • Loading branch information
Jeday authored Jun 12, 2023
2 parents f17e446 + 6c5d182 commit b7765f4
Show file tree
Hide file tree
Showing 28 changed files with 312 additions and 228 deletions.
4 changes: 2 additions & 2 deletions packages/constants/src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export const TOKENS_BY_NETWORK: {

export const getTokenAddress = (chainId: CHAINS, token: TOKENS): string => {
const tokens = TOKENS_BY_NETWORK[chainId];
invariant(tokens != null, 'Chain is not supported');
invariant(tokens, 'Chain is not supported');

const address = tokens[token];
invariant(address != null, 'Token is not supported');
invariant(address, 'Token is not supported');

return address;
};
2 changes: 1 addition & 1 deletion packages/constants/src/withdrawal_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export const WITHDRAWAL_QUEUE_BY_NETWORK: {

export const getWithdrawalQueueAddress = (chainId: CHAINS): string => {
const address = WITHDRAWAL_QUEUE_BY_NETWORK[chainId];
invariant(address != null, 'Chain is not supported');
invariant(address, 'Chain is not supported');
return address;
};
4 changes: 2 additions & 2 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
},
"devDependencies": {
"@ethersproject/bignumber": "^5.4.2",
"@ethersproject/bytes": "^5.4.0",
"@ethersproject/constants": "^5.4.0",
"@ethersproject/contracts": "^5.4.1",
"@ethersproject/providers": "^5.4.5",
"@ethersproject/bytes": "^5.4.0",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^7.0.2",
"@types/jest": "^27.0.2",
Expand All @@ -49,10 +49,10 @@
},
"peerDependencies": {
"@ethersproject/bignumber": "5",
"@ethersproject/bytes": "5",
"@ethersproject/constants": "5",
"@ethersproject/contracts": "5",
"@ethersproject/providers": "5",
"@ethersproject/bytes": "5",
"react": ">=16",
"react-dom": ">=16"
}
Expand Down
5 changes: 3 additions & 2 deletions packages/react/src/context/SDK.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export interface SDKContextValue {
onError: (error: unknown) => void;
}

export const SDKContext = createContext({} as SDKContextValue);
export const SDKContext = createContext<SDKContextValue | null>(null);
SDKContext.displayName = 'LidoSDKContext';

const ProviderSDK: FC<SDKContextProps> = (props) => {
const {
Expand All @@ -43,7 +44,7 @@ const ProviderSDK: FC<SDKContextProps> = (props) => {
swrConfig,
} = props;

invariant(chainId !== null, 'Chain is not supported');
invariant(chainId, 'invalid chainId');
invariant(supportedChainIds?.length, 'Supported chains are required');

const providerRpc = useMemo(() => {
Expand Down
15 changes: 14 additions & 1 deletion packages/react/src/factories/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { BaseContract } from '@ethersproject/contracts';
import { TOKENS, CHAINS, getTokenAddress } from '@lido-sdk/constants';
import {
TOKENS,
CHAINS,
getTokenAddress,
getWithdrawalQueueAddress,
} from '@lido-sdk/constants';
import {
WstethAbiFactory,
StethAbiFactory,
LdoAbiFactory,
Factory,
createContractGetter,
WithdrawalQueueAbiFactory,
} from '@lido-sdk/contracts';
import { useMemo } from 'react';
import { useSDK } from '../hooks';
Expand Down Expand Up @@ -57,3 +63,10 @@ const ldo = contractHooksFactory(LdoAbiFactory, (chainId) =>
);
export const useLDOContractRPC = ldo.useContractRPC;
export const useLDOContractWeb3 = ldo.useContractWeb3;

const withdrawalQueue = contractHooksFactory(
WithdrawalQueueAbiFactory,
(chainId) => getWithdrawalQueueAddress(chainId),
);
export const useWithdrawalQueueContractRPC = withdrawalQueue.useContractRPC;
export const useWithdrawalQueueContractWeb3 = withdrawalQueue.useContractWeb3;
24 changes: 14 additions & 10 deletions packages/react/src/hooks/useAllowance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import invariant from 'tiny-invariant';
import warning from 'tiny-warning';
import { useCallback, useEffect } from 'react';
import { useEffect } from 'react';
import { BigNumber } from '@ethersproject/bignumber';
import { getERC20Contract } from '@lido-sdk/contracts';
import { useContractSWR } from './useContractSWR';
Expand Down Expand Up @@ -31,28 +31,32 @@ export const useAllowance = (
params: [mergedOwner, spender],
});

const updateAllowance = useDebounceCallback(result.update);
const updateAllowanceDebounced = useDebounceCallback(result.update, 1000);

const subscribeToUpdates = useCallback(() => {
useEffect(() => {
if (!mergedOwner || !providerWeb3 || !contractWeb3) return;

try {
const transfer = contractWeb3.filters.Transfer(mergedOwner, spender);
const approve = contractWeb3.filters.Approval(mergedOwner, spender);

providerWeb3.on(transfer, updateAllowance);
providerWeb3.on(approve, updateAllowance);
providerWeb3.on(transfer, updateAllowanceDebounced);
providerWeb3.on(approve, updateAllowanceDebounced);

return () => {
providerWeb3.off(transfer, updateAllowance);
providerWeb3.off(approve, updateAllowance);
providerWeb3.off(transfer, updateAllowanceDebounced);
providerWeb3.off(approve, updateAllowanceDebounced);
};
} catch (error) {
return warning(false, 'Cannot subscribe to event');
}
}, [providerWeb3, contractWeb3, mergedOwner, spender, updateAllowance]);

useEffect(subscribeToUpdates, [subscribeToUpdates]);
}, [
contractWeb3,
mergedOwner,
providerWeb3,
updateAllowanceDebounced,
spender,
]);

return result;
};
8 changes: 6 additions & 2 deletions packages/react/src/hooks/useDecimals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import { getERC20Contract } from '@lido-sdk/contracts';
import { useContractSWR } from './useContractSWR';
import { SWRResponse } from './useLidoSWR';
import { useSDK } from './useSDK';
import { SWRConfiguration } from 'swr';

export const useDecimals = (token: string): SWRResponse<number> => {
export const useDecimals = (
token: string,
config?: SWRConfiguration<number>,
): SWRResponse<number> => {
const { providerRpc } = useSDK();

invariant(token != null, 'Token address is required');

const contract = getERC20Contract(token, providerRpc);
const result = useContractSWR({ contract, method: 'decimals' });
const result = useContractSWR({ contract, method: 'decimals', config });

return result;
};
74 changes: 16 additions & 58 deletions packages/react/src/hooks/useEthPrice.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,29 @@
import { SWRConfiguration } from 'swr';
import { BigNumber } from '@ethersproject/bignumber';
import { getAggregatorContract } from '@lido-sdk/contracts';
import { getAggregatorAddress, CHAINS } from '@lido-sdk/constants';
import { divide } from '@lido-sdk/helpers';
import { useSDK } from './useSDK';
import { SWRResponse } from './useLidoSWR';
import { useContractSWR } from './useContractSWR';
import { useCallback, useMemo } from 'react';
import { SWRResponse, useLidoSWR } from './useLidoSWR';

const getEthPrice = (decimals?: number, latestAnswer?: BigNumber) => {
if (decimals == null || latestAnswer == null) {
return undefined;
}
type useEthPriceResult = number;

return divide(latestAnswer, BigNumber.from(10).pow(decimals));
};

export const useEthPrice = (): Omit<SWRResponse<number>, 'mutate'> => {
export const useEthPrice = (
config?: SWRConfiguration<useEthPriceResult, unknown>,
): SWRResponse<useEthPriceResult> => {
const { providerMainnetRpc } = useSDK();
const address = getAggregatorAddress(CHAINS.Mainnet);
const aggregatorContract = getAggregatorContract(address, providerMainnetRpc);

const decimals = useContractSWR({
contract: aggregatorContract,
method: 'decimals',
});

const latestAnswer = useContractSWR({
contract: aggregatorContract,
method: 'latestAnswer',
});

const decimalsData = decimals.data;
const latestAnswerData = latestAnswer.data;

const data = useMemo(() => {
return getEthPrice(decimalsData, latestAnswerData);
}, [decimalsData, latestAnswerData]);

const updateDecimals = decimals.update;
const updateLatestAnswer = latestAnswer.update;

const update = useCallback(async () => {
const [decimals, latestAnswer] = await Promise.all([
updateDecimals(),
updateLatestAnswer(),
]);

return getEthPrice(decimals, latestAnswer);
}, [updateDecimals, updateLatestAnswer]);

return {
update,
data,

/*
* support dependency collection
* https://swr.vercel.app/advanced/performance#dependency-collection
*/

get loading() {
return decimals.loading || latestAnswer.loading;
},
get initialLoading() {
return decimals.initialLoading || latestAnswer.initialLoading;
},
get error() {
return decimals.error || latestAnswer.error;
return useLidoSWR(
['lido-swr:eth-price', aggregatorContract],
async () => {
const [decimals, latestAnswer] = await Promise.all([
aggregatorContract.decimals(),
aggregatorContract.latestAnswer(),
]);
return divide(latestAnswer, BigNumber.from(10).pow(decimals));
},
};
config,
);
};
17 changes: 9 additions & 8 deletions packages/react/src/hooks/useEthereumBalance.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import warning from 'tiny-warning';
import { useCallback, useEffect } from 'react';
import { useEffect } from 'react';
import { BigNumber } from '@ethersproject/bignumber';
import { useSDK } from './useSDK';
import { useEthereumSWR } from './useEthereumSWR';
import { SWRResponse } from './useLidoSWR';
import { SWRConfiguration } from 'swr';
import { useDebounceCallback } from './useDebounceCallback';

export const useEthereumBalance = (
account?: string,
config?: SWRConfiguration<BigNumber, Error>,
): SWRResponse<BigNumber> => {
const { providerWeb3, account: sdkAccount } = useSDK();
const mergedAccount = account ?? sdkAccount;
Expand All @@ -16,25 +18,24 @@ export const useEthereumBalance = (
shouldFetch: !!mergedAccount,
method: 'getBalance',
params: [mergedAccount, 'latest'],
config,
});

const updateBalance = useDebounceCallback(result.update);
const updateBalanceDebounced = useDebounceCallback(result.update, 1000);

const subscribeToUpdates = useCallback(() => {
useEffect(() => {
if (!mergedAccount || !providerWeb3) return;

try {
providerWeb3.on('block', updateBalance);
providerWeb3.on('block', updateBalanceDebounced);

return () => {
providerWeb3.off('block', updateBalance);
providerWeb3.off('block', updateBalanceDebounced);
};
} catch (error) {
return warning(false, 'Cannot subscribe to Block event');
}
}, [providerWeb3, mergedAccount, updateBalance]);

useEffect(subscribeToUpdates, [subscribeToUpdates]);
}, [providerWeb3, mergedAccount, updateBalanceDebounced]);

return result;
};
2 changes: 1 addition & 1 deletion packages/react/src/hooks/useLidoSWR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type SWRResponse<Data, Error = unknown> = {
};

export const useLidoSWR = <Data = unknown, Error = unknown>(
key: Key,
key: Key | null,
fetcher: Fetcher<Data> | null,
config?: SWRConfiguration<Data, Error>,
): SWRResponse<Data, Error> => {
Expand Down
5 changes: 4 additions & 1 deletion packages/react/src/hooks/useSDK.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useContext } from 'react';
import { SDKContext, SDKContextValue } from '../context';
import invariant from 'tiny-invariant';

export const useSDK = (): SDKContextValue => {
return useContext(SDKContext);
const contextValue = useContext(SDKContext);
invariant(contextValue, 'useSDK was used outside of SDKContext');
return contextValue;
};
21 changes: 11 additions & 10 deletions packages/react/src/hooks/useTokenBalance.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import invariant from 'tiny-invariant';
import warning from 'tiny-warning';
import { useCallback, useEffect } from 'react';
import { useEffect } from 'react';
import { BigNumber } from '@ethersproject/bignumber';
import { getERC20Contract } from '@lido-sdk/contracts';
import { useContractSWR } from './useContractSWR';
import { SWRResponse } from './useLidoSWR';
import { useSDK } from './useSDK';
import { SWRConfiguration } from 'swr';
import { useDebounceCallback } from './useDebounceCallback';

export const useTokenBalance = (
token: string,
account?: string,
config?: SWRConfiguration<BigNumber>,
): SWRResponse<BigNumber> => {
const { providerRpc, providerWeb3, account: sdkAccount } = useSDK();
const mergedAccount = account ?? sdkAccount;
Expand All @@ -27,30 +29,29 @@ export const useTokenBalance = (
contract: contractRpc,
method: 'balanceOf',
params: [mergedAccount],
config,
});

const updateBalance = useDebounceCallback(result.update);
const updateBalanceDebounced = useDebounceCallback(result.update, 1000);

const subscribeToUpdates = useCallback(() => {
useEffect(() => {
if (!mergedAccount || !providerWeb3 || !contractWeb3) return;

try {
const fromMe = contractWeb3.filters.Transfer(mergedAccount, null);
const toMe = contractWeb3.filters.Transfer(null, mergedAccount);

providerWeb3.on(fromMe, updateBalance);
providerWeb3.on(toMe, updateBalance);
providerWeb3.on(fromMe, updateBalanceDebounced);
providerWeb3.on(toMe, updateBalanceDebounced);

return () => {
providerWeb3.off(fromMe, updateBalance);
providerWeb3.off(toMe, updateBalance);
providerWeb3.off(fromMe, updateBalanceDebounced);
providerWeb3.off(toMe, updateBalanceDebounced);
};
} catch (error) {
return warning(false, 'Cannot subscribe to events');
}
}, [providerWeb3, contractWeb3, mergedAccount, updateBalance]);

useEffect(subscribeToUpdates, [subscribeToUpdates]);
}, [providerWeb3, contractWeb3, mergedAccount, updateBalanceDebounced]);

return result;
};
Loading

0 comments on commit b7765f4

Please sign in to comment.