Skip to content

Commit

Permalink
(registry) feat: add claiming to unit details
Browse files Browse the repository at this point in the history
  • Loading branch information
Atatakai authored and Atatakai committed Aug 16, 2024
1 parent a726a5d commit 747b25a
Show file tree
Hide file tree
Showing 15 changed files with 354 additions and 242 deletions.
13 changes: 12 additions & 1 deletion apps/autonolas-registry/common-util/Contracts/index.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ethers } from 'ethers';
import { mainnet } from 'viem/chains';
import Web3 from 'web3';

import { isL1Network } from '@autonolas/frontend-library';

import { TOKENOMICS } from 'libs/util-contracts/src/lib/abiAndAddresses/tokenomics';
import { DISPENSER, TOKENOMICS } from 'libs/util-contracts/src/lib/abiAndAddresses';

import {
AGENT_REGISTRY_CONTRACT,
Expand Down Expand Up @@ -218,3 +219,13 @@ export const getTokenomicsEthersContract = (address) => {
const contract = new ethers.Contract(address, TOKENOMICS.abi, provider);
return contract;
};

/**
* @returns dispenser contract
*/
export const getDispenserContract = () => {
const abi = DISPENSER.abi;
const address = DISPENSER.addresses[mainnet.id];
const contract = getContract(abi, address);
return contract;
};
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { Col, Flex, Row } from 'antd';
import { FC, useEffect, useState } from 'react';
import { Button, Flex, Table, Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { Address } from 'viem';
import { useAccount } from 'wagmi';

Check failure on line 5 in apps/autonolas-registry/common-util/Details/DetailsSubInfo/RewardsSection.tsx

View workflow job for this annotation

GitHub Actions / build

'useAccount' is defined but never used

import { getPendingIncentives, useClaimableIncentives } from 'libs/common-contract-functions/src';
import { UNICODE_SYMBOLS } from 'libs/util-constants/src/lib/symbols';
import { TOKENOMICS } from 'libs/util-contracts/src';
import { notifyError, notifySuccess } from 'libs/util-functions/src';

import { getEthersProviderForEthereum, getTokenomicsEthersContract } from 'common-util/Contracts';
import { claimOwnerIncentivesRequest } from 'common-util/functions/requests';
import { useHelpers } from 'common-util/hooks';

import { RewardsStatistic } from '../styles';
import { useTokenomicsUnitType } from './hooks';
import { getTokenomicsUnitType } from './utils';

type RewardsColumnProps = { title: string; statistic: null | string; loading?: boolean };

const RewardColumn = ({ title, statistic, loading }: RewardsColumnProps) => (
<Col span={24} xl={12}>
<RewardsStatistic title={title} value={statistic || '--'} loading={!!loading} />
</Col>
);
const { Text } = Typography;

type RewardsSectionProps = {
ownerAddress: Address;
Expand All @@ -26,18 +24,66 @@ type RewardsSectionProps = {
dataTestId: string;
};

type DataSourceItem = {
id: 'claimable' | 'pending';
label: string;
donations: string;
topUps: string;
};
const getColumns = (
canClaim: boolean,
handleClaim: () => void,
isClaimLoading: boolean,
): ColumnsType<DataSourceItem> => [
{
title: 'Type',
key: 'type',
dataIndex: 'label',
render: (label, { id }) => (
<Flex gap={16} align="center">
<Text>{label}</Text>
{id === 'claimable' && canClaim && (
<Button type="primary" onClick={handleClaim} loading={isClaimLoading}>
Claim
</Button>
)}
</Flex>
),
width: '40%',
},
{
title: 'Donations',
key: 'donations',
dataIndex: 'donations',
render: (donations) => <Text>{`${donations} ETH`}</Text>,
},
{
title: 'Top Ups',
key: 'topUps',
dataIndex: 'topUps',
render: (topUps) => <Text>{`${topUps} OLAS`}</Text>,
},
];

export const RewardsSection: FC<RewardsSectionProps> = ({ ownerAddress, id, type, dataTestId }) => {
const { account } = useHelpers();

const [isClaimLoading, setIsClaimLoading] = useState(false);
const [isPendingIncentivesLoading, setIsPendingIncentivesLoading] = useState<boolean>(true);
const [pendingIncentives, setPendingIncentives] = useState<{
reward: string;
topUp: string;
pendingReward: string;
pendingTopUp: string;
} | null>(null);

const tokenomicsUnitType = useTokenomicsUnitType(type);
const tokenomicsUnitType = getTokenomicsUnitType(type);

const {
isFetching,
reward: claimableReward,
topUp: claimableTopup,
rewardEth: claimableRewardEth,
topUp: claimableTopUp,
topUpEth: claimableTopUpEth,
isFetching: isClaimableIncentivesLoading,
refetch,
} = useClaimableIncentives(
TOKENOMICS.addresses[1],
TOKENOMICS.abi,
Expand All @@ -46,52 +92,99 @@ export const RewardsSection: FC<RewardsSectionProps> = ({ ownerAddress, id, type
tokenomicsUnitType,
);

useEffect(() => {
const fetchPendingIncentives = useCallback(async () => {
const provider = getEthersProviderForEthereum();
const contract = getTokenomicsEthersContract(TOKENOMICS.addresses[1]);

getPendingIncentives(provider, contract, `${tokenomicsUnitType}`, id)
.then((data) => setPendingIncentives(data))
.catch((error) => console.error(error))
.finally(() => setIsPendingIncentivesLoading(false));
}, [ownerAddress, id, tokenomicsUnitType]);
try {
const incentives = await getPendingIncentives({
provider,
contract,
unitType: `${tokenomicsUnitType}`,
unitId: id,
});
setPendingIncentives(incentives);
} catch (error) {
console.error(error);
} finally {
setIsPendingIncentivesLoading(false);
}
}, [tokenomicsUnitType, id]);

useEffect(() => {
fetchPendingIncentives();
}, [fetchPendingIncentives]);

const rewards = useMemo(() => {
if (isClaimableIncentivesLoading || isPendingIncentivesLoading) return [];
if (claimableReward == undefined || claimableTopUp === undefined || pendingIncentives === null)
return [];

return [
{
id: 'claimable',
label: 'Claimable',
donations: claimableReward,
topUps: claimableTopUp,
},
{
id: 'pending',
label: 'Pending, next epoch',
donations: pendingIncentives.pendingReward,
topUps: pendingIncentives.pendingTopUp,
},
] as DataSourceItem[];
}, [
isClaimableIncentivesLoading,
isPendingIncentivesLoading,
claimableReward,
claimableTopUp,
pendingIncentives,
]);

const canClaim = useMemo(() => {
if (account !== ownerAddress) return false;
if (claimableRewardEth === undefined || claimableTopUpEth === undefined) return false;

return claimableRewardEth > 0 || claimableTopUpEth > 0;
}, [account, ownerAddress, claimableRewardEth, claimableTopUpEth]);

const handleClaim = useCallback(async () => {
if (!account) return;
if (!canClaim) return;

try {
setIsClaimLoading(true);
const params = {
account: account as Address,
unitIds: [id],
unitTypes: [id],
};

await claimOwnerIncentivesRequest(params);
notifySuccess('Rewards claimed');
refetch();
fetchPendingIncentives();
} catch (error) {
notifyError();
console.error(error);
} finally {
setIsClaimLoading(false);
}
}, [ownerAddress, id]);

Check warning on line 174 in apps/autonolas-registry/common-util/Details/DetailsSubInfo/RewardsSection.tsx

View workflow job for this annotation

GitHub Actions / build

React Hook useCallback has missing dependencies: 'account', 'canClaim', 'fetchPendingIncentives', and 'refetch'. Either include them or remove the dependency array

return (
<Flex gap={16} vertical className="mt-12" data-testid={dataTestId}>
<Flex vertical gap={4}>
<Row>
<RewardColumn
title="Claimable Reward"
statistic={claimableReward ? `${claimableReward} ETH` : null}
loading={isFetching}
/>
<RewardColumn
title="Claimable Top Up"
statistic={claimableTopup ? `${claimableTopup} OLAS` : null}
/>
</Row>
</Flex>

<Flex vertical gap={12}>
<Row>
<RewardColumn
title="Pending Reward"
statistic={pendingIncentives ? `${pendingIncentives?.reward} ETH` : null}
loading={isPendingIncentivesLoading}
/>
<RewardColumn
title="Pending Top Up"
statistic={pendingIncentives ? `${pendingIncentives?.topUp} OLAS` : null}
loading={isPendingIncentivesLoading}
/>
</Row>

<Row>
<a href="https://tokenomics.olas.network/donate">
Make donation {UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
</Row>
</Flex>
<Table
columns={getColumns(canClaim, handleClaim, isClaimLoading)}
dataSource={rewards}
loading={isClaimableIncentivesLoading || isPendingIncentivesLoading}
pagination={false}
style={{ maxWidth: '550px' }}
/>
<a href="https://tokenomics.olas.network/donate">
Make donation {UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
</Flex>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { getTokenDetailsRequest } from '../utils';
import { RewardsSection } from './RewardsSection';
import { ServiceStatus } from './ServiceStatus';
import { ViewHashAndCode } from './ViewHashAndCode';
import { useTokenomicsUnitType } from './hooks';
import { getTokenomicsUnitType } from './utils';

const navTypesForRewards = [NAV_TYPES.COMPONENT, NAV_TYPES.AGENT];

Expand Down Expand Up @@ -56,7 +56,7 @@ export const DetailsSubInfo = ({
const { operatorWhitelistTitle, operatorWhitelistValue, operatorStatusValue } =
useOperatorWhitelistComponent(id);

const tokenomicsUnitType = useTokenomicsUnitType(type);
const tokenomicsUnitType = getTokenomicsUnitType(type);

const viewHashAndCodeButtons = (
<ViewHashAndCode
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NAV_TYPES, TOKENOMICS_UNIT_TYPES } from '../../../util/constants';

export const useTokenomicsUnitType = (type?: string) => {
export const getTokenomicsUnitType = (type?: string) => {
if (type === NAV_TYPES.COMPONENT) return TOKENOMICS_UNIT_TYPES.COMPONENT;
if (type === NAV_TYPES.AGENT) return TOKENOMICS_UNIT_TYPES.AGENT;
return;
Expand Down
7 changes: 4 additions & 3 deletions apps/autonolas-registry/common-util/Details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ import { DetailsSubInfo } from './DetailsSubInfo';
import { NftImage } from './NFTImage';
import { DetailsTitle, Header } from './styles';
import { useDetails } from './useDetails';
import { Address } from 'viem';

const { Text } = Typography;

type DetailsProps = {
id: string;
type: NavTypesValues;
getDetails: (id: string) => Promise<GenericObject>; // TODO: Define the return type
getTokenUri?: (id: string) => Promise<string>;
getOwner?: (id: string) => Promise<string>;
getDetails: (id: string) => Promise<{ unitHash: Address, dependencies: string[]}>;
getTokenUri: (id: string) => Promise<string>;
getOwner: (id: string) => Promise<string>;
handleUpdate?: () => void;
handleHashUpdate?: () => void;
navigateToDependency?: (id: string, type: NavTypesValues) => void;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Image, Statistic, Typography } from 'antd';
import { Image, Typography } from 'antd';
import styled from 'styled-components';

import { COLOR } from 'libs/ui-theme/src';
Expand Down Expand Up @@ -74,25 +74,4 @@ export const SectionContainer = styled.div`
.ant-form-item-label > label {
left: -4px;
}
`;

export const RewardsStatistic = styled((props) => <Statistic {...props} />)`
.ant-statistic-title {
font-size: 14px;
line-height: 20px;
}
.ant-statistic-content {
font-size: 24px;
font-style: normal;
font-weight: 700;
line-height: 32px;
letter-spacing: -0.72px;
}
.ant-skeleton-title {
margin: 0;
max-width: 200px;
}
.ant-statistic-skeleton {
padding-top: 12px;
}
`;
`;
Loading

0 comments on commit 747b25a

Please sign in to comment.