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

feat: support additional tokens required for initial funding #620

Merged
merged 2 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions electron/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const schema = {
lastSelectedAgentType: { type: 'string', default: 'trader' },
isInitialFunded_trader: { type: 'boolean', default: false },
isInitialFunded_memeooorr: { type: 'boolean', default: false },
isInitialFunded_modius: { type: 'boolean', default: false },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥲 #603

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah we didn't discuss it 🫠 still afraid of that with your approach if we need to update e.g. trader.isInitialFunded, we'll need to update the whole object:

electronApi.store?.set?.(trader, {...electronApi.store?.get('trader'), isInitialFunded: true});

imagine somewhere at the same time we update e.g. firstRewardsNotificationShown, so we may loose previous update... but maybe that's impossible?

};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const EmptyFunds = () => {
<InlineBanner text="Your safe address" address={masterEoaAddress} />
)}
<PurpleDivider />
<FundsToActivate stakingFundsRequired otherFundsRequired />
<FundsToActivate stakingFundsRequired nativeFundsRequired />
</Flex>
}
type="primary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ const { Text } = Typography;

type FundsToActivateProps = {
stakingFundsRequired: boolean;
otherFundsRequired: boolean;
nativeFundsRequired: boolean;
additionalFundsRequired?: boolean;
};

const FUNDS_REQUIRED_FOR_BY_AGENT_TYPE = {
[AgentType.PredictTrader]: 'for trading',
[AgentType.Memeooorr]: 'for agent operations',
[AgentType.Modius]: 'minimum for investment',
};

export const FundsToActivate = ({
stakingFundsRequired = true,
otherFundsRequired = true,
nativeFundsRequired = true,
additionalFundsRequired = true,
}: FundsToActivateProps) => {
const { selectedStakingProgramId } = useStakingProgram();

Expand All @@ -49,6 +52,22 @@ export const FundsToActivate = ({
return `${native} ${nativeTokenSymbol}`;
}, [homeChainId, serviceFundRequirements, nativeTokenSymbol]);

// Calculate additional tokens requirements (Eg. USDC)
const additionalTokensRequired = useMemo(() => {
const additionalTokens = Object.keys(
serviceFundRequirements[homeChainId],
).filter(
(token) => token !== TokenSymbol.OLAS && token !== nativeTokenSymbol,
);

if (additionalTokens.length === 0) return [];

return additionalTokens.map((tokenSymbol) => {
const token = serviceFundRequirements[homeChainId][tokenSymbol];
return `${token} ${tokenSymbol}`;
});
}, [homeChainId, serviceFundRequirements, nativeTokenSymbol]);

return (
<>
<Text>
Expand All @@ -63,12 +82,20 @@ export const FundsToActivate = ({
staking.
</div>
)}
{otherFundsRequired && (
{nativeFundsRequired && (
<div>
{UNICODE_SYMBOLS.BULLET} <Text strong>{nativeTokenRequired}</Text> -
{` ${FUNDS_REQUIRED_FOR_BY_AGENT_TYPE[selectedAgentType]}.`}
</div>
)}

{additionalFundsRequired &&
additionalTokensRequired.map((additionalToken) => (
<div key={additionalToken}>
{UNICODE_SYMBOLS.BULLET} <Text strong>{additionalToken}</Text> -
{` ${FUNDS_REQUIRED_FOR_BY_AGENT_TYPE[selectedAgentType]}.`}
</div>
))}
</Flex>

{masterSafeAddress && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { round } from 'lodash';
import { useMemo } from 'react';

import { getNativeTokenSymbol } from '@/config/tokens';
import { TokenSymbol } from '@/enums/Token';
import { WalletType } from '@/enums/Wallet';
import { useMasterBalances } from '@/hooks/useBalanceContext';
import { useNeedsFunds } from '@/hooks/useNeedsFunds';
Expand All @@ -22,8 +24,9 @@ export const LowFunds = () => {
masterSafeNativeGasBalance,
} = useMasterBalances();

const { nativeBalancesByChain, olasBalancesByChain, isInitialFunded } =
useNeedsFunds(selectedStakingProgramId);
const { balancesByChain, isInitialFunded } = useNeedsFunds(
selectedStakingProgramId,
);
const { tokenSymbol, masterThresholds } = useLowFundsDetails();

const chainId = selectedAgentConfig.evmHomeChainId;
Expand All @@ -50,15 +53,14 @@ export const LowFunds = () => {
// Show the empty funds alert if the agent is not funded
const isEmptyFundsVisible = useMemo(() => {
if (!isBalanceLoaded) return false;
if (!olasBalancesByChain) return false;
if (!nativeBalancesByChain) return false;
if (!balancesByChain) return false;

// If the agent is not funded, <MainNeedsFunds /> will be displayed
if (!isInitialFunded) return false;

if (
round(nativeBalancesByChain[chainId], 2) === 0 &&
round(olasBalancesByChain[chainId], 2) === 0 &&
round(balancesByChain[chainId][getNativeTokenSymbol(chainId)], 2) === 0 &&
round(balancesByChain[chainId][TokenSymbol.OLAS], 2) === 0 &&
isSafeSignerBalanceLow
) {
return true;
Expand All @@ -69,8 +71,7 @@ export const LowFunds = () => {
isBalanceLoaded,
isInitialFunded,
chainId,
nativeBalancesByChain,
olasBalancesByChain,
balancesByChain,
isSafeSignerBalanceLow,
]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const MainNeedsFunds = () => {
const {
hasEnoughEthForInitialFunding,
hasEnoughOlasForInitialFunding,
hasEnoughAdditionalTokensForInitialFunding,
isInitialFunded,
needsInitialFunding,
} = useNeedsFunds(selectedStakingProgramId);
Expand Down Expand Up @@ -54,7 +55,10 @@ export const MainNeedsFunds = () => {

<FundsToActivate
stakingFundsRequired={!hasEnoughOlasForInitialFunding}
otherFundsRequired={!hasEnoughEthForInitialFunding}
nativeFundsRequired={!hasEnoughEthForInitialFunding}
additionalFundsRequired={
!hasEnoughAdditionalTokensForInitialFunding
}
/>
</Flex>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { Button, Flex, Typography } from 'antd';

import { Pages } from '@/enums/Pages';
import { StakingProgramId } from '@/enums/StakingProgram';
import { usePageState } from '@/hooks/usePageState';
import { useStakingProgram } from '@/hooks/useStakingProgram';

import { CustomAlert } from '../../../Alert';

const { Text } = Typography;

// TODO: need to figure out how to understand if there are new staking contracts
// To show this alert; also need to hide it, when a use clicks "review"
export const NewStakingProgramAlert = () => {
const { goto } = usePageState();
const { activeStakingProgramId, isActiveStakingProgramLoaded } =
useStakingProgram();
// const { activeStakingProgramId, isActiveStakingProgramLoaded } =
// useStakingProgram();

// TODO: remove single staking program check
if (
!isActiveStakingProgramLoaded ||
activeStakingProgramId !== StakingProgramId.OptimusAlpha
)
return null;
// // TODO: remove single staking program check
// if (
// !isActiveStakingProgramLoaded ||
// activeStakingProgramId !== StakingProgramId.OptimusAlpha
// )
// return null;

return (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we keep this for "trader" and return null for other agents?

Copy link
Collaborator Author

@Tanya-atatakai Tanya-atatakai Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact, this code means show the alert if activeStakingProgramId is Optimus (which is Modius), but for the rest return null. So, as I said in the previous comment, it's not working correctly...

<CustomAlert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useFeatureFlag } from '@/hooks/useFeatureFlag';
import { AddBackupWalletAlert } from './AddBackupWalletAlert';
import { AvoidSuspensionAlert } from './AvoidSuspensionAlert';
import { LowFunds } from './LowFunds/LowFunds';
import { NewStakingProgramAlert } from './NewStakingProgramAlert';
import { NoAvailableSlotsOnTheContract } from './NoAvailableSlotsOnTheContract';
import { UpdateAvailableAlert } from './UpdateAvailableAlert';

Expand All @@ -14,7 +13,7 @@ export const AlertSections = () => {
<CardSection vertical>
<UpdateAvailableAlert />
{isBackupViaSafeEnabled && <AddBackupWalletAlert />}
<NewStakingProgramAlert />
{/* <NewStakingProgramAlert /> */}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are hiding just for "modius" should we put it behind the feature flag?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not for modius, we just agreed it doesn't work properly at all... https://valory-workspace.slack.com/archives/C07GH5D26UB/p1733992345003699

<AvoidSuspensionAlert />
<LowFunds />
<NoAvailableSlotsOnTheContract />
Expand Down
5 changes: 1 addition & 4 deletions frontend/components/SetupPage/Create/SetupEoaFunding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { useSetup } from '@/hooks/useSetup';
import { useMasterWalletContext } from '@/hooks/useWallet';
import { copyToClipboard } from '@/utils/copyToClipboard';
import { delayInSeconds } from '@/utils/delay';
import { formatEther } from '@/utils/numberFormatters';

import { SetupCreateHeader } from './SetupCreateHeader';

Expand Down Expand Up @@ -192,9 +191,7 @@ export const SetupEoaFunding = () => {
return (
<SetupEoaFundingForChain
isFunded={isFunded}
minRequiredBalance={parseFloat(
formatEther(`${currentFundingRequirements}`),
)}
minRequiredBalance={currentFundingRequirements}
currency={CHAIN_CONFIG[currentChain].nativeToken.symbol}
chainName={CHAIN_CONFIG[currentChain].name}
/>
Expand Down
15 changes: 10 additions & 5 deletions frontend/config/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,28 @@ export const AGENT_CONFIG: {
middlewareHomeChainId: MiddlewareChain.MODE,
requiresAgentSafesOn: [EvmChainId.Mode],
agentSafeFundingRequirements: {
[EvmChainId.Mode]: 5260000000000000, // 0.00526 eth
[EvmChainId.Mode]: 0.0005,
},
additionalRequirements: {
[EvmChainId.Mode]: {
[TokenSymbol.USDC]: 16,
},
},
operatingThresholds: {
[WalletOwnerType.Master]: {
[WalletType.EOA]: {
[TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct
[TokenSymbol.ETH]: 0.0002,
},
[WalletType.Safe]: {
[TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct
[TokenSymbol.ETH]: 0.001,
},
},
[WalletOwnerType.Agent]: {
[WalletType.EOA]: {
[TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct
[TokenSymbol.ETH]: 0.00005,
},
[WalletType.Safe]: {
[TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct
[TokenSymbol.ETH]: 0.0005,
},
},
},
Expand Down
11 changes: 11 additions & 0 deletions frontend/config/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ export const MODE_TOKEN_CONFIG: ChainTokenConfig = {
tokenType: TokenType.Erc20,
symbol: TokenSymbol.OLAS,
},
/**
* @warning USDC is a special case, it has 6 decimals, not 18.
* https://explorer.mode.network/address/0xd988097fb8612cc24eeC14542bC03424c656005f?tab=read_contract#313ce567
* @note When parsing or formatting units, use `decimals` (6) instead of the standard `ether` sizing (10^18).
*/
[TokenSymbol.USDC]: {
address: '0xd988097fb8612cc24eeC14542bC03424c656005f',
decimals: 6,
tokenType: TokenType.Erc20,
symbol: TokenSymbol.USDC,
},
};

export const TOKEN_CONFIG = {
Expand Down
6 changes: 3 additions & 3 deletions frontend/constants/serviceTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [
agent_id: 40,
threshold: 1,
use_staking: true,
cost_of_bond: 20000000000000000000,
monthly_gas_estimate: 5260000000000000,
cost_of_bond: +parseEther(20),
monthly_gas_estimate: +parseEther(0.00516),
fund_requirements: {
agent: 5000000000000000,
agent: +parseEther(0.001),
safe: 0,
},
},
Expand Down
7 changes: 4 additions & 3 deletions frontend/context/BalanceProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { StakedAgentService } from '@/service/agents/StakedAgentService';
import { Address } from '@/types/Address';
import { Maybe } from '@/types/Util';
import { asEvmChainId } from '@/utils/middlewareHelpers';
import { formatEther } from '@/utils/numberFormatters';
import { formatUnits } from '@/utils/numberFormatters';

import { MasterWalletContext } from './MasterWalletProvider';
import { OnlineStatusContext } from './OnlineStatusProvider';
Expand Down Expand Up @@ -228,6 +228,7 @@ const getCrossChainWalletBalances = async (
tokenType,
symbol: tokenSymbol,
address: tokenAddress,
decimals,
} of Object.values(tokensOnChain)) {
const isNative = tokenType === TokenType.NativeGas;
const isErc20 = tokenType === TokenType.Erc20;
Expand Down Expand Up @@ -258,7 +259,7 @@ const getCrossChainWalletBalances = async (
evmChainId: providerEvmChainId,
symbol: tokenSymbol,
isNative: true,
balance: Number(formatEther(balance)),
balance: Number(formatUnits(balance)),
}),
);
}
Expand Down Expand Up @@ -287,7 +288,7 @@ const getCrossChainWalletBalances = async (
evmChainId: providerEvmChainId,
symbol: tokenSymbol,
isNative: false,
balance: Number(formatEther(erc20Balances[index])),
balance: Number(formatUnits(erc20Balances[index], decimals)),
}),
) as WalletBalanceResult[];

Expand Down
2 changes: 1 addition & 1 deletion frontend/enums/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export const AgentType = {
PredictTrader: 'trader',
// Optimus: 'optimus',
Memeooorr: 'memeooorr',
Modius: 'Modius',
Modius: 'modius',
} as const;

export type AgentType = (typeof AgentType)[keyof typeof AgentType];
Loading
Loading