Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(operate) feat: Add column for how much xdai needed in staking contracts page #94

Merged
merged 9 commits into from
Sep 3, 2024
70 changes: 65 additions & 5 deletions apps/operate/components/Contracts/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,65 @@ import { getAddressFromBytes32, getBytes32FromAddress } from 'libs/util-function

const ONE_YEAR = 1 * 24 * 60 * 60 * 365;

const AVAILABLE_ON: Record<Address, StakingContract['availableOn']> = {
'0x000000000000000000000000ef44fb0842ddef59d37f85d61a1ef492bba6135d': 'pearl',
'0x000000000000000000000000389b46c259631acd6a69bde8b6cee218230bae8c': 'quickstart',
'0x0000000000000000000000005344b7dd311e5d3dddd46a4f71481bd7b05aaa3e': 'quickstart',
type StakingContractDetailsInfo = {
availableOn?: StakingContract['availableOn'];
minOperatingBalance?: number;
minOperatingBalanceToken?: string;
convertUsdToEth?: boolean;
};

const STAKING_CONTRACT_DETAILS: Record<Address, StakingContractDetailsInfo> = {
'0x000000000000000000000000ef44fb0842ddef59d37f85d61a1ef492bba6135d': {
availableOn: 'pearl',
minOperatingBalance: 11.5,
minOperatingBalanceToken: 'xDAI',
},
'0x000000000000000000000000389b46c259631acd6a69bde8b6cee218230bae8c': {
availableOn: 'quickstart',
minOperatingBalance: 90,
minOperatingBalanceToken: 'xDAI',
},
'0x0000000000000000000000005344b7dd311e5d3dddd46a4f71481bd7b05aaa3e': {
availableOn: 'quickstart',
minOperatingBalance: 90,
minOperatingBalanceToken: 'xDAI',
},
'0x000000000000000000000000b964e44c126410df341ae04b13ab10a985fe3513': {
availableOn: null,
minOperatingBalance: 90,
minOperatingBalanceToken: 'xDAI',
},
'0x00000000000000000000000080fad33cadb5f53f9d29f02db97d682e8b101618': {
availableOn: null,
minOperatingBalance: 90,
minOperatingBalanceToken: 'xDAI',
},
'0x0000000000000000000000001c2f82413666d2a3fd8bc337b0268e62ddf67434': {
availableOn: null,
minOperatingBalance: 11.5,
minOperatingBalanceToken: 'xDAI',
},
'0x000000000000000000000000238eb6993b90a978ec6aad7530d6429c949c08da': {
availableOn: null,
minOperatingBalance: 45,
minOperatingBalanceToken: 'xDAI',
},
'0x00000000000000000000000088996bbde7f982d93214881756840ce2c77c4992': {
availableOn: null,
minOperatingBalance: 10,
minOperatingBalanceToken: 'ETH (OP)',
convertUsdToEth: true,
},
'0x000000000000000000000000daf34ec46298b53a3d24cbcb431e84ebd23927da': {
availableOn: null,
minOperatingBalance: 11.5,
minOperatingBalanceToken: 'xDAI',
},
'0x000000000000000000000000998defafd094817ef329f6dc79c703f1cf18bc90': {
availableOn: null,
minOperatingBalance: 45,
minOperatingBalanceToken: 'xDAI',
},
};

const getApy = (
Expand Down Expand Up @@ -116,6 +171,7 @@ export const useStakingContractsList = () => {

const apy = getApy(rewardsPerSecond, minStakingDeposit, numAgentInstances);
const stakeRequired = getStakeRequired(minStakingDeposit, numAgentInstances);
const details = STAKING_CONTRACT_DETAILS[item.account];

return {
key: item.account,
Expand All @@ -126,7 +182,10 @@ export const useStakingContractsList = () => {
maxSlots,
apy,
stakeRequired,
availableOn: AVAILABLE_ON[item.account] || null,
availableOn: details?.availableOn || null,
minOperatingBalance: details.minOperatingBalance,
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved
minOperatingBalanceToken: details?.minOperatingBalanceToken || null,
convertUsdToEth: details?.convertUsdToEth || false,
};
}) as StakingContract[];
}
Expand All @@ -139,6 +198,7 @@ export const useStakingContractsList = () => {
rewardsPerSecondList,
minStakingDepositList,
numAgentInstancesList,
availableRewardsList,
]);

return {
Expand Down
59 changes: 58 additions & 1 deletion apps/operate/components/Contracts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { DownOutlined, RightOutlined } from '@ant-design/icons';
import { Card, Table, Tag, Typography } from 'antd';
import { Card, Skeleton, Table, Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import { StakingContract } from 'types';

import { Caption, TextWithTooltip } from 'libs/ui-components/src';
import { BREAK_POINT } from 'libs/ui-theme/src';
import { CHAIN_NAMES, GOVERN_URL, NA, UNICODE_SYMBOLS } from 'libs/util-constants/src';
import { convertUsdToEth } from 'libs/util-functions/src';

import { RunAgentButton } from 'components/RunAgentButton';

Expand All @@ -21,6 +23,33 @@ const StyledMain = styled.main`

const { Title, Paragraph, Text } = Typography;

type ConvertedMinOperatingBalanceProps = { value: number; token: string | null };
const ConvertedMinOperatingBalance = ({ value, token }: ConvertedMinOperatingBalanceProps) => {
const [isConverting, setIsConverting] = useState<boolean>(false);
const [convertedValue, setConvertedValue] = useState<number | null>(null);

useEffect(() => {
const convert = async () => {
if (!value) return;

setIsConverting(true);
try {
const temp = await convertUsdToEth(value, 6);
setConvertedValue(temp);
} catch (error) {
console.error('Error converting token:', error);
} finally {
setIsConverting(false);
}
};

convert();
}, [value, token]);
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved

if (isConverting) return <Skeleton.Input active />;
return <Text>{`~${convertedValue} ${token || ''}`.trim()}</Text>;
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved
};

const columns: ColumnsType<StakingContract> = [
{
title: 'Contract',
Expand All @@ -32,25 +61,51 @@ const columns: ColumnsType<StakingContract> = [
title: 'Chain',
dataIndex: 'chainId',
key: 'chainId',
width: 120,
render: (chainId) => <Text type="secondary">{CHAIN_NAMES[chainId] || chainId}</Text>,
},
{
title: 'Available slots',
dataIndex: 'availableSlots',
key: 'availableSlots',
render: (availableSlots, record) => <Text>{`${availableSlots} / ${record.maxSlots}`}</Text>,
className: 'text-end',
},
{
title: () => <TextWithTooltip text="APY" description="Annual percentage yield" />,
dataIndex: 'apy',
key: 'apy',
render: (apy) => <Tag color="purple">{`${apy}%`}</Tag>,
className: 'text-end',
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved
},
{
title: 'Stake required, OLAS',
dataIndex: 'stakeRequired',
key: 'stakeRequired',
render: (stakeRequired) => <Text>{stakeRequired}</Text>,
className: 'text-end',
width: 148,
},
{
title: 'Minimum operating balance required',
dataIndex: 'minOperatingBalance',
key: 'minOperatingBalance',
render: (minOperatingBalance, contract) => {
const { convertUsdToEth } = contract;
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved
if (!convertUsdToEth) {
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved
const value = `${minOperatingBalance} ${contract.minOperatingBalanceToken}`.trim();
mohandast52 marked this conversation as resolved.
Show resolved Hide resolved
return <Text>{value}</Text>;
}

return (
<ConvertedMinOperatingBalance
value={minOperatingBalance}
token={contract.minOperatingBalanceToken}
/>
);
},
className: 'text-end',
width: 200,
},
{
title: () => (
Expand Down Expand Up @@ -111,6 +166,8 @@ export const ContractsPage = () => {
</>
),
}}
scroll={{ x: 1000 }}
rowHoverable={false}
/>
</Card>
</StyledMain>
Expand Down
3 changes: 3 additions & 0 deletions apps/operate/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ export type StakingContract = {
apy: number;
stakeRequired: string;
availableOn: 'pearl' | 'quickstart' | null;
minOperatingBalance: number | null;
minOperatingBalanceToken: string | null;
convertUsdToEth: boolean;
};
6 changes: 3 additions & 3 deletions libs/common-middleware/src/lib/cspHeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ const WALLET_CONNECT_LINKS = [
];

const VERCEL_LINKS = ['https://vercel.com', 'https://vercel.live/'];

const APIS = ['https://api.coingecko.com/api/'];
const GATEWAY_LINKS = [
'https://gateway.autonolas.tech/ipfs/*',
'https://gateway.pinata.cloud/ipfs/*',
'https://*.arweave.net/',
'https://i.seadn.io/s/raw/files/',
'https://www.askjimmy.xyz/images/',
];

const ALLOWED_ORIGINS = [
// internal
"'self'",
Expand Down Expand Up @@ -78,9 +77,10 @@ const ALLOWED_ORIGINS = [
'https://*.network.thegraph.com/',

...VERCEL_LINKS,
...APIS,
];

const SCRIPT_SRC = ["'self'", 'https://vercel.live/', 'https://fonts.googleapis.com/'];
const SCRIPT_SRC = ["'self'", ...VERCEL_LINKS, 'https://fonts.googleapis.com/', ...APIS];

export const getCspHeaders = () => {
if (!process.env.NEXT_PUBLIC_AUTONOLAS_SUB_GRAPH_URL) return [];
Expand Down
2 changes: 1 addition & 1 deletion libs/ui-theme/src/lib/GlobalStyles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const GlobalStyles = createGlobalStyle`
text-align: center;
}
.text-end {
text-align: end;
text-align: end !important;
}

.full-width {
Expand Down
1 change: 1 addition & 0 deletions libs/util-functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './lib/sendTransaction/helpers';
export * from './lib/notifications';
export * from './lib/requests';
export * from './lib/ethers';
export * from './lib/liveConversion';
18 changes: 18 additions & 0 deletions libs/util-functions/src/lib/liveConversion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export async function convertUsdToEth(
usdAmount: number,
roundTo: number = 4,
): Promise<number | null> {
try {
const response = await fetch(
'https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd',
);
const data = await response.json();

const ethRate = data.ethereum.usd; // USD to ETH rate
const ethAmount = usdAmount / ethRate;

return Number(ethAmount.toFixed(roundTo));
} catch (error) {
throw new Error('Error fetching conversion rate');
}
}
Loading