Skip to content

Commit

Permalink
rewards fix (#208)
Browse files Browse the repository at this point in the history
* rewards fix

* overlaying tooltip

* nikita feedback

---------

Co-authored-by: jmzwar <james@jmzwar.com>
  • Loading branch information
jmzwar and jmzwar authored Mar 29, 2024
1 parent d95abaa commit 2689926
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 148 deletions.
4 changes: 3 additions & 1 deletion liquidity/components/Amount/Amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ export function Amount({
prefix = '',
suffix = '',
'data-testid': testid,
showTooltip,
}: {
prefix?: string;
value?: Wei;
suffix?: string;
'data-testid'?: string;
showTooltip?: boolean;
}) {
const { formattedValue, preciseValue, isMaxUint } = useMemo(() => {
if (!value) {
Expand Down Expand Up @@ -45,7 +47,7 @@ export function Amount({
)}
</>
}
isDisabled={formattedValue === preciseValue}
isDisabled={formattedValue === preciseValue || !showTooltip}
>
<span data-testid={testid}>
{prefix}
Expand Down
286 changes: 147 additions & 139 deletions liquidity/lib/useRewards/useRewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,161 +89,169 @@ export function useRewards(
}
if (distributors.length === 0) return [];

const { abi } = await importRewardDistributor(network?.id, network?.preset);
try {
const { abi } = await importRewardDistributor(network?.id, network?.preset);

const ifaceRD = new utils.Interface(abi);
const ifaceERC20 = new utils.Interface(erc20Abi);
const ifaceRD = new utils.Interface(abi);
const ifaceERC20 = new utils.Interface(erc20Abi);

const [{ returnData: distributorReturnData }, ...historicalData] = await Promise.all([
await Multicall3.callStatic.aggregate(
distributors.flatMap(({ id: address }) => [
const [{ returnData: distributorReturnData }, ...historicalData] = await Promise.all([
await Multicall3.callStatic.aggregate(
distributors.flatMap(({ id: address }) => [
{
target: address,
callData: ifaceRD.encodeFunctionData('name', []),
},
{
target: address,
callData: ifaceRD.encodeFunctionData('token', []),
},
])
),
...distributors.map(async ({ id: address }) => {
return await fetch(getSubgraphUrl(network?.name), {
method: 'POST',
body: JSON.stringify({
query: RewardsDataDocument,
variables: { accountId, distributor: address },
}),
}).then((res) => res.json());
}),
]);

const distributorResult = distributors.map(({ id: address, rewards_distributions }, i) => {
const name = ifaceRD.decodeFunctionResult(
'name',
distributorReturnData[i * 2]
)[0] as string;
const token = ifaceRD.decodeFunctionResult(
'token',
distributorReturnData[i * 2 + 1]
)[0] as string;

let duration = 0;

if (rewards_distributions.length > 0) {
duration = parseInt(rewards_distributions[0].duration);
}

const lifetimeClaimed: number = historicalData[i].data.rewardsClaimeds
.reduce((acc: Wei, item: { amount: string; id: string }) => {
return acc.add(wei(item.amount, 18, true));
}, wei(0))
.toNumber();

// See if it is still active (i.e rewards are still being emitted)
const { duration: distribution_duration, created_at } = rewards_distributions[0];

const expiry = parseInt(distribution_duration) + parseInt(created_at);

// const total =
const hasExpired = new Date().getTime() / 1000 > expiry;

return {
address,
name,
token,
duration,
total: hasExpired ? '0' : rewards_distributions[0].amount, // Take the latest amount
lifetimeClaimed,
};
});

const { returnData: ercReturnData } = await Multicall3.callStatic.aggregate(
distributorResult.flatMap(({ token, address }) => [
{
target: token,
callData: ifaceERC20.encodeFunctionData('name', []),
},
{
target: token,
callData: ifaceERC20.encodeFunctionData('symbol', []),
},
{
target: address,
callData: ifaceRD.encodeFunctionData('name', []),
target: token,
callData: ifaceERC20.encodeFunctionData('decimals', []),
},
{
target: address,
callData: ifaceRD.encodeFunctionData('token', []),
target: CoreProxy.address,
callData: CoreProxy.interface.encodeFunctionData('getRewardRate', [
BigNumber.from(poolId),
token,
address,
]),
},
])
),
...distributors.map(async ({ id: address }) => {
return await fetch(getSubgraphUrl(network?.name), {
method: 'POST',
body: JSON.stringify({
query: RewardsDataDocument,
variables: { accountId, distributor: address },
}),
}).then((res) => res.json());
}),
]);

const distributorResult = distributors.map(({ id: address, rewards_distributions }, i) => {
const name = ifaceRD.decodeFunctionResult(
'name',
distributorReturnData[i * 2]
)[0] as string;
const token = ifaceRD.decodeFunctionResult(
'token',
distributorReturnData[i * 2 + 1]
)[0] as string;

let duration = 0;

if (rewards_distributions.length > 0) {
duration = parseInt(rewards_distributions[0].duration);
}

const lifetimeClaimed = historicalData[i].data.rewardsClaimeds.reduce(
(acc: number, item: { amount: string; id: string }) => {
return (acc += parseInt(item.amount));
},
0
);

// See if it is still active (i.e rewards are still being emitted)
const { duration: distribution_duration, created_at } = rewards_distributions[0];

const expiry = parseInt(distribution_duration) + parseInt(created_at);

// const total =
const hasExpired = new Date().getTime() / 1000 > expiry;

return {
address,
name: name,
token: token,
duration,
total: hasExpired ? '0' : rewards_distributions[0].amount, // Take the latest amount
lifetimeClaimed,
};
});

const { returnData: ercReturnData } = await Multicall3.callStatic.aggregate(
distributorResult.flatMap(({ token }) => [
{
target: token,
callData: ifaceERC20.encodeFunctionData('name', []),
},
{
target: token,
callData: ifaceERC20.encodeFunctionData('symbol', []),
},
{
target: token,
callData: ifaceERC20.encodeFunctionData('decimals', []),
},
])
);

const rewardRates = await Promise.all(
distributorResult.map(async ({ address }) => {
const response = await CoreProxy.callStatic.getRewardRate(
BigNumber.from(poolId),
collateralAddress,
address
);
const result = distributorResult.map((item, i) => {
const name = ifaceERC20.decodeFunctionResult('name', ercReturnData[i * 4])[0] as string;

return response;
})
);

const result = distributorResult.map((item, i) => {
const name = ifaceERC20.decodeFunctionResult('name', ercReturnData[i * 3])[0] as string;
const symbol = ifaceERC20.decodeFunctionResult(
'symbol',
ercReturnData[i * 3 + 1]
)[0] as string;
const decimals = ifaceERC20.decodeFunctionResult(
'decimals',
ercReturnData[i * 3 + 2]
)[0] as number;

const total = parseInt(item.total);

return {
...item,
name,
symbol,
decimals,
// Reward rate is the amount of rewards per second
rewardRate: wei(rewardRates[i]),
total,
};
});

// TODO: Refactor this to use a view function
const balances: RewardsResponseArray = [];
for (const item of result) {
try {
const response = await CoreProxy.callStatic.claimRewards(
BigNumber.from(accountId),
BigNumber.from(poolId),
collateralAddress,
item.address
const symbol = ifaceERC20.decodeFunctionResult(
'symbol',
ercReturnData[i * 4 + 1]
)[0] as string;

const decimals = ifaceERC20.decodeFunctionResult(
'decimals',
ercReturnData[i * 4 + 2]
)[0] as number;

const rewardRate = CoreProxy.interface.decodeFunctionResult(
'getRewardRate',
ercReturnData[i * 4 + 3]
);

balances.push({
...item,
claimableAmount: wei(response),
distributorAddress: item.address,
rate: item.rewardRate.toNumber(),
});
} catch (error) {
balances.push({
const total = wei(item.total, 18, true).toNumber();

return {
...item,
claimableAmount: wei(0),
distributorAddress: item.address,
rate: item.rewardRate.toNumber(),
});
name,
symbol,
decimals,
// Reward rate is the amount of rewards per second
rewardRate: wei(rewardRate),
total,
};
});

// TODO: Refactor this to use a view function
const balances: RewardsResponseArray = [];
for (const item of result) {
try {
const response = await CoreProxy.callStatic.claimRewards(
BigNumber.from(accountId),
BigNumber.from(poolId),
collateralAddress,
item.address
);

balances.push({
...item,
claimableAmount: wei(response),
distributorAddress: item.address,
rate: item.rewardRate.toNumber(),
});
} catch (error) {
balances.push({
...item,
claimableAmount: wei(0),
distributorAddress: item.address,
rate: item.rewardRate.toNumber(),
});
}
}
}

const sortedBalances = [...balances].sort(
(a, b) => b.claimableAmount.toNumber() - a.claimableAmount.toNumber()
);
const sortedBalances = [...balances].sort(
(a, b) => b.claimableAmount.toNumber() - a.claimableAmount.toNumber()
);

return RewardsResponseSchema.parse(sortedBalances);
return RewardsResponseSchema.parse(sortedBalances);
} catch (error) {
// eslint-disable-next-line no-console
console.warn(error);
return [];
}
},
});
}
9 changes: 3 additions & 6 deletions liquidity/ui/src/components/Rewards/RewardsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ export const RewardsRow = ({
return 'Claimed';
};

// Note adjustment will need to be made for decimals
const totalAmount = total / 1e18;

const link = etherscanLink({ chain: network?.name || 'mainnet', address });

return (
Expand All @@ -90,11 +87,11 @@ export const RewardsRow = ({
fontWeight={500}
lineHeight="20px"
>
<Amount value={wei(totalAmount)} suffix={symbol} />
<Amount showTooltip={false} value={wei(total)} suffix={` ${symbol}`} />
</Text>
</Tooltip>
</Link>
{frequencyString && totalAmount > 0 && (
{frequencyString && total > 0 && (
<Text color="gray.500" fontSize="12px" fontFamily="heading" lineHeight="16px">
{frequencyString}
</Text>
Expand All @@ -117,7 +114,7 @@ export const RewardsRow = ({
{lifetimeClaimed > 0 && (
<Text color="gray.500" fontSize="12px" fontFamily="heading" lineHeight="16px">
<Tooltip label="Total claimed over lifetime">Lifetime: &nbsp;</Tooltip>
<Amount value={wei(lifetimeClaimed.toString(), 18, true)} />
<Amount value={wei(lifetimeClaimed)} />
{symbol}
</Text>
)}
Expand Down
4 changes: 2 additions & 2 deletions liquidity/ui/src/pages/Teleporter/TeleporterModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ export const TeleporterModalUi: FC<{
<>
{state.matches(State.success) ? (
<Text>
Teleport for <Amount value={amount} suffix={` snxUSD`} /> to {toNetworkName}{' '}
executed. Check{' '}
Teleport for <Amount showTooltip value={amount} suffix={` snxUSD`} /> to{' '}
{toNetworkName} executed. Check{' '}
<Link
color="cyan.500"
href={`https://ccip.chain.link/tx/${txnHash}`}
Expand Down

0 comments on commit 2689926

Please sign in to comment.