Skip to content

Commit

Permalink
Merge pull request #689 from subquery/fix/re-deleagtion
Browse files Browse the repository at this point in the history
fix: style issue, add next ICR on indexer profile, lazy collect status, add approve allowance if user set a invalid value
  • Loading branch information
HuberTRoy authored Mar 15, 2024
2 parents 27b9d32 + ec2898c commit 7bd739b
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 20 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# SubQuery Network App

dApp for indexers, consumers and delegators interact with SubQuery Network. You can find this at [https://kepler.subquery.network](https://kepler.subquery.network/)
dApp for indexers, consumers and delegators interact with SubQuery Network. You can find this at
[https://app.subquery.network](https://app.subquery.network/)
1 change: 1 addition & 0 deletions src/components/IndexerDetails/PlansTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ const DoPurchase: React.FC<DoPurchaseProps> = ({
]}
text={modalText}
onClick={() => purchasePlan(plan.creator, last(plan.id.split(':')))}
allowanceContractAddress={ApproveContract.PlanManager}
renderContent={(onSubmit, onCancel, isLoading, error) => {
return renderAsync(planManagerAllowance.result, {
loading: () => <Spinner />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export const ModalClaimIndexerRewards: React.FC<IModalClaimIndexerRewards> = ({
try {
setIsLoading(true);
assert(contracts, 'Contracts not available');
// const batchCollectAndDistribute = await contracts.rewardsHelper.batchCollectAndDistributeRewards(indexer, 20);
// const batchCollectAndDistributeResult = await batchCollectAndDistribute.wait();

const approvalTx = await contracts.rewardsHelper.indexerCatchup(indexer);
const approvalTxResult = await approvalTx.wait();

Expand Down
9 changes: 7 additions & 2 deletions src/components/ProjectOverview/ProjectOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,12 @@ const ProjectOverview: React.FC<Props> = ({ project, metadata, deploymentDescrip

return (
<div className={styles.container}>
<div style={{ display: 'flex', flexDirection: 'column', flex: 5 }}>
{/* note the width on this element, if inner elements need width:100% to overflow or ...,
need add a width on the parent elements, flex-grow can make it dynamic,
width: 1px equal 500px,
but suggest add a reasonable value in case this rule change in the future
*/}
<div style={{ display: 'flex', flexDirection: 'column', flex: 5, width: 500 }}>
<div style={{ width: '100%' }}>
<Expand>
<Markdown.Preview>{metadata.description || 'N/A'}</Markdown.Preview>
Expand Down Expand Up @@ -220,7 +225,7 @@ const ProjectOverview: React.FC<Props> = ({ project, metadata, deploymentDescrip
<Typography variant="large" weight={600}>
{t('projectOverview.deploymentDescription')}
</Typography>
<div style={{ width: 670, marginTop: 8 }}>
<div style={{ width: '100%', marginTop: 8 }}>
<Expand>
<Markdown.Preview>{deploymentDescription || 'N/A'}</Markdown.Preview>
</Expand>
Expand Down
23 changes: 21 additions & 2 deletions src/components/TransactionModal/TransactionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { MdErrorOutline } from 'react-icons/md';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import { ApproveContract } from '@components/ModalApproveToken';
import { NotificationType, openNotification } from '@components/Notification';
import { useSQToken } from '@containers';
import { ContractTransaction } from '@ethersproject/contracts';
import { useAddAllowance } from '@hooks/useAddAllowance';
import { Button } from '@subql/components';
import { ButtonProps } from '@subql/components/dist/common/button/Button';
import { Tooltip } from 'antd';
import clsx from 'clsx';
import { constants } from 'ethers';

import { AsyncData, parseError } from '../../utils';
import { AsyncData, isInsufficientAllowance, parseError } from '../../utils';
import { Modal } from '../Modal';
import { ModalInput } from '../ModalInput';
import styles from './TransactionModal.module.css';
Expand Down Expand Up @@ -75,6 +79,7 @@ export type TransactionModalProps<P, T extends string> = {
className?: string;
buttonClassName?: string;
currentConfirmButtonLoading?: boolean;
allowanceContractAddress?: ApproveContract;
};

export interface TransactionModalRef {
Expand Down Expand Up @@ -108,6 +113,7 @@ const TransactionModal = React.forwardRef<TransactionModalRef, TransactionModalP
className = '',
buttonClassName = '',
currentConfirmButtonLoading = false,
allowanceContractAddress = ApproveContract.Staking,
},
ref,
) => {
Expand All @@ -117,6 +123,9 @@ const TransactionModal = React.forwardRef<TransactionModalRef, TransactionModalP
const [successModalText, setSuccessModalText] = React.useState<string | undefined>();
const [failureModalText, setFailureModalText] = React.useState<string | undefined>();

const { addAllowance } = useAddAllowance();
const { balance } = useSQToken();

React.useEffect(() => {
if (initialCheck) {
const { error } = initialCheck;
Expand Down Expand Up @@ -151,9 +160,19 @@ const TransactionModal = React.forwardRef<TransactionModalRef, TransactionModalP
const wrapTxAction = (action: typeof onClick, rethrow?: boolean) => async (params: string) => {
try {
if (!showModal || !action) return;
let tx: ContractTransaction;

const tx = await action(params, showModal);
setIsLoading(true);
try {
tx = await action(params, showModal);
} catch (e: any) {
if (isInsufficientAllowance(e)) {
await addAllowance(allowanceContractAddress, (balance.result.data || constants.MaxUint256)?.toString());
tx = await action(params, showModal);
} else {
throw e;
}
}
resetModal();
openNotification({ title: t('transaction.submmited') });
const result = await tx.wait();
Expand Down
32 changes: 32 additions & 0 deletions src/hooks/useAddAllowance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2020-2022 SubQuery Pte Ltd authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { ApproveContract } from '@components';
import { openNotification } from '@subql/components';

import { useWeb3Store } from 'src/stores';

export const useAddAllowance = () => {
const { contracts } = useWeb3Store();

const addAllowance = async (contractName: ApproveContract, allowance: string) => {
try {
if (!contracts) throw new Error('Contracts not available');
openNotification({
type: 'info',
description: 'Allowance not enough, increase allowance first',
duration: 5000,
});
const tx = await contracts.sqToken.approve(contracts[contractName].address, allowance);
await tx?.wait();
return tx;
} catch (e) {
console.error(e);
throw e;
}
};

return {
addAllowance,
};
};
22 changes: 16 additions & 6 deletions src/hooks/useEra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,22 @@ export function useEra(): {
limitContract(() => eraManager.eraStartTime(), makeCacheKey('eraStartTime')),
]);

const era: Era = {
startTime: bnToDate(startTime),
estEndTime: bnToDate(startTime.add(period)),
period: period.toNumber(),
index: index.toNumber(),
};
let era: Era;
if (startTime && period && index) {
era = {
startTime: bnToDate(startTime),
estEndTime: bnToDate(startTime.add(period)),
period: period.toNumber(),
index: index.toNumber(),
};
} else {
era = {
startTime: new Date(),
estEndTime: new Date(),
period: 0,
index: 0,
};
}

return era;
}, [contracts]);
Expand Down
1 change: 0 additions & 1 deletion src/hooks/useRewardCollectStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export function useRewardCollectStatus(

const fetchStatus = async (_?: boolean) => {
if (!contracts) return false;

try {
setLoading(true);
const lastClaimedEra = await limitContract(
Expand Down
3 changes: 2 additions & 1 deletion src/pages/consumer/OfferMarketplace/AcceptOffer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import dayjs from 'dayjs';

import { useWeb3Store } from 'src/stores';

import { DeploymentInfo, SummaryList } from '../../../components';
import { ApproveContract, DeploymentInfo, SummaryList } from '../../../components';
import TransactionModal from '../../../components/TransactionModal';
import { useWeb3 } from '../../../containers';
import {
Expand Down Expand Up @@ -220,6 +220,7 @@ export const AcceptOffer: React.FC<Props> = ({ deployment, offer, requiredBlockH
onSuccess={() => onAcceptOffer()}
onClick={handleClick}
onClose={() => setCurStep(0)}
allowanceContractAddress={ApproveContract.PurchaseOfferMarket}
renderContent={(onSubmit, _, isLoading, error) => {
if (curStep === 0) {
return <OfferSummary curStep={curStep} onNext={() => setCurStep(curStep + 1)} offer={offer} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const RewardsLineChart = (props: { account?: string; title?: string; data
dataDimensionsName={dataDimensionsName}
chartData={renderRewards}
onTriggerTooltip={(index, curDate) => {
return `<div class="col-flex" style="width: 280px">
return `<div class="col-flex" style="width: 280px; font-size: 12px;">
<span>${curDate.format('MMM D, YYYY')}</span>
<div class="flex-between" style="margin-top: 8px;">
<span>Total</span>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/delegator/DoDelegate/DoDelegate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const DoDelegate: React.FC<DoDelegateProps> = ({
const { contracts } = useWeb3Store();
const { stakingAllowance } = useSQToken();
const requireTokenApproval = useMemo(() => stakingAllowance?.result.data?.isZero(), [stakingAllowance?.result.data]);
const rewardClaimStatus = useRewardCollectStatus(indexerAddress);
const rewardClaimStatus = useRewardCollectStatus(indexerAddress, true);

// note why we don't use useGetIndexerLazy.
// In apollo-client, if two different query use same fragment, and the query result in the two query is different,
Expand Down
4 changes: 3 additions & 1 deletion src/pages/delegator/DoUndelegate/DoUndelegate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export const DoUndelegate: React.FC<DoUndelegateProps> = ({ indexerAddress, onSu
};

return renderAsync(mergeAsync(rewardClaimStatus, lockPeriod, delegation), {
error: (error) => '',
error: (error) => {
return '';
},
loading: () => <Spinner />,
data: (data) => {
const [indexerRewards, lock, targetDelegation] = data;
Expand Down
4 changes: 2 additions & 2 deletions src/pages/delegator/MyDelegation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,15 @@ export const MyDelegation: React.FC = () => {
// TODO: sort by GraphQL
.sort((a, b) => (`${a.id}` > `${b.id}` ? -1 : 1))
.map((delegation) => ({
value: mapEraValue(parseRawEraValue(delegation?.amount as RawEraValue, era?.index), (v) =>
value: mapEraValue(parseRawEraValue((delegation?.amount as RawEraValue) || '0', era?.index), (v) =>
formatEther(v ?? 0),
),
indexer: delegation.indexerId,
indexerActive: delegation?.indexer?.active,
}))
.filter(
(delegation) =>
parseEther(delegation.value.current).gt('0') || parseEther(delegation?.value?.after ?? '0').gt('0'),
parseEther(delegation.value.current || '0').gt('0') || parseEther(delegation?.value?.after ?? '0').gt('0'),
),
mergeAsync(delegations, currentEra),
);
Expand Down
16 changes: 15 additions & 1 deletion src/pages/indexer/IndexerProfile/IndexerProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { notEmpty, parseError } from '@utils';
import { isRPCError } from '@utils';
import { TOKEN } from '@utils/constants';
import { formatNumber, formatSQT, truncateToDecimalPlace } from '@utils/numberFormatters';
import { Skeleton, Tag } from 'antd';
import { Skeleton, Tag, Tooltip } from 'antd';
import clsx from 'clsx';
import { toChecksumAddress } from 'ethereum-checksum-address';
import { constants } from 'ethers';
Expand Down Expand Up @@ -280,6 +280,20 @@ const IndexerProfile: FC = () => {
{getCommission(fetchedResult?.indexer?.commission || 0, currentEra.data?.index).current} %
</Typography>
</div>
<div className={clsx(styles.cardContentLine, 'flex-between')}>
<Typography variant="small" style={{ visibility: 'hidden' }}>
bigo
</Typography>
<Tooltip title="Estimated for next Era">
<Typography
variant="small"
type="secondary"
style={{ transform: 'scale(0.83333) translateX(7px)', marginLeft: 3 }}
>
{getCommission(fetchedResult?.indexer?.commission || 0, currentEra.data?.index).after} %
</Typography>
</Tooltip>
</div>

<div className={clsx(styles.cardContentLine, 'flex-between')}>
<Typography variant="small" type="secondary">
Expand Down
26 changes: 25 additions & 1 deletion src/utils/parseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ export const isRPCError = (msg: Error | string | undefined): boolean => {
return false;
};

export const isInsufficientAllowance = (msg: Error | string | undefined): boolean => {
if (!msg) return false;

if (msg instanceof Error) {
if (msg.message.includes('insufficient allowance')) {
return true;
}
return false;
}

if (msg.includes('insufficient allowance')) {
return true;
}

return false;
};

export function parseError(
error: any,
options: { alert?: boolean; defaultGeneralMsg?: string | null; errorMappings?: typeof errorsMapping } = {
Expand Down Expand Up @@ -136,6 +153,12 @@ export function parseError(
}
};

const insufficientAllowance = () => {
if (isInsufficientAllowance(rawErrorMsg)) {
return 'Insufficient allowance. Please set a reasonable value when set spending cap';
}
};

const generalErrorMsg = () => {
try {
if (!rawErrorMsg.includes('Failed to fetch')) {
Expand All @@ -158,9 +181,10 @@ export function parseError(
mappingError() ??
mapContractError() ??
userDeniedSignature() ??
callRevert() ??
insufficientAllowance() ??
RpcUnavailableMsg() ??
insufficientFunds() ??
callRevert() ??
options.defaultGeneralMsg ??
generalErrorMsg()
);
Expand Down

0 comments on commit 7bd739b

Please sign in to comment.