From a7c350339116c49e2c2721383b18fb26fe29f460 Mon Sep 17 00:00:00 2001 From: Maxime Beauchamp <15185355+baktun14@users.noreply.github.com> Date: Tue, 5 Mar 2024 21:54:10 -0500 Subject: [PATCH] features/min-deposit-onchain (#115) * implement deployment deposit params query on chain * handle min value in deployment deposit * fix typo --- .../deployment/DeploymentListRow.tsx | 1 + .../DeploymentDepositModal.tsx | 21 +++++++++++------- .../DeploymentDetailTopBar.tsx | 1 + .../newDeploymentWizard/ManifestEdit.tsx | 1 - .../src/components/sdl/RentGpusForm.tsx | 1 - deploy-web/src/hooks/useWalletBalance.ts | 19 ++++++++++++---- deploy-web/src/queries/queryKeys.ts | 1 + deploy-web/src/queries/useSettings.ts | 19 +++++++++++++++- deploy-web/src/types/deployment.ts | 22 +++++++++++++++---- deploy-web/src/types/network.ts | 2 +- deploy-web/src/utils/apiUtils.ts | 3 +++ deploy-web/src/utils/deploymentDetailUtils.ts | 2 +- 12 files changed, 72 insertions(+), 21 deletions(-) diff --git a/deploy-web/src/components/deployment/DeploymentListRow.tsx b/deploy-web/src/components/deployment/DeploymentListRow.tsx index 3e5814749..9ee1c9c57 100644 --- a/deploy-web/src/components/deployment/DeploymentListRow.tsx +++ b/deploy-web/src/components/deployment/DeploymentListRow.tsx @@ -360,6 +360,7 @@ export const DeploymentListRow: React.FunctionComponent = ({ deployment, {isActive && isDepositingDeployment && ( setIsDepositingDeployment(false)} onDeploymentDeposit={onDeploymentDeposit} /> diff --git a/deploy-web/src/components/deploymentDetail/DeploymentDepositModal.tsx b/deploy-web/src/components/deploymentDetail/DeploymentDepositModal.tsx index d711a6657..ae3d7a7be 100644 --- a/deploy-web/src/components/deploymentDetail/DeploymentDepositModal.tsx +++ b/deploy-web/src/components/deploymentDetail/DeploymentDepositModal.tsx @@ -20,14 +20,14 @@ import { GranteeDepositMenuItem } from "./GranteeDepositMenuItem"; type Props = { infoText?: string | ReactNode; - min?: number; + disableMin?: boolean; denom: string; onDeploymentDeposit: (deposit: number, depositorAddress: string) => void; handleCancel: () => void; children?: ReactNode; }; -export const DeploymentDepositModal: React.FunctionComponent = ({ handleCancel, onDeploymentDeposit, denom, min = 0, infoText = null }) => { +export const DeploymentDepositModal: React.FunctionComponent = ({ handleCancel, onDeploymentDeposit, disableMin, denom, infoText = null }) => { const formRef = useRef(null); const { settings } = useSettings(); const { enqueueSnackbar } = useSnackbar(); @@ -35,6 +35,7 @@ export const DeploymentDepositModal: React.FunctionComponent = ({ handleC const [isCheckingDepositor, setIsCheckingDepositor] = useState(false); const { walletBalances, address } = useWallet(); const { data: granteeGrants } = useGranteeGrants(address); + const depositData = useDenomData(denom); const { handleSubmit, control, @@ -45,15 +46,20 @@ export const DeploymentDepositModal: React.FunctionComponent = ({ handleC unregister } = useForm({ defaultValues: { - amount: min, + amount: 0, useDepositor: false, depositorAddress: "" } }); const { amount, useDepositor, depositorAddress } = watch(); - const depositData = useDenomData(denom); const usdcIbcDenom = useUsdcDenom(); + useEffect(() => { + if (depositData && amount === 0 && !disableMin) { + setValue("amount", depositData?.min || 0); + } + }, [depositData]); + useEffect(() => { clearErrors(); setError(""); @@ -127,8 +133,8 @@ export const DeploymentDepositModal: React.FunctionComponent = ({ handleC clearErrors(); const deposit = denomToUdenom(amount); - if (deposit < denomToUdenom(min)) { - setError(`Deposit amount must be greater or equal than ${min}.`); + if (!disableMin && deposit < depositData?.min) { + setError(`Deposit amount must be greater or equal than ${depositData?.min}.`); return; } @@ -209,7 +215,7 @@ export const DeploymentDepositModal: React.FunctionComponent = ({ handleC autoFocus error={!!fieldState.error} helperText={fieldState.error && helperText} - inputProps={{ min: min, step: 0.000001, max: depositData?.inputMax }} + inputProps={{ min: (!disableMin && depositData?.min) || 0, step: 0.000001, max: depositData?.inputMax }} InputProps={{ startAdornment: {depositData?.label} }} @@ -265,4 +271,3 @@ export const DeploymentDepositModal: React.FunctionComponent = ({ handleC ); }; - diff --git a/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx b/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx index 4c01f44e4..eb6a08fee 100644 --- a/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx +++ b/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx @@ -206,6 +206,7 @@ export const DeploymentDetailTopBar: React.FunctionComponent = ({ address {isDepositingDeployment && ( setIsDepositingDeployment(false)} onDeploymentDeposit={onDeploymentDeposit} /> diff --git a/deploy-web/src/components/newDeploymentWizard/ManifestEdit.tsx b/deploy-web/src/components/newDeploymentWizard/ManifestEdit.tsx index 4c4452cc8..b0b085345 100644 --- a/deploy-web/src/components/newDeploymentWizard/ManifestEdit.tsx +++ b/deploy-web/src/components/newDeploymentWizard/ManifestEdit.tsx @@ -315,7 +315,6 @@ export const ManifestEdit: React.FunctionComponent = ({ editedManifest, s setIsDepositingDeployment(false)} onDeploymentDeposit={onDeploymentDeposit} - min={5} // TODO Query from chain params denom={sdlDenom} infoText={ diff --git a/deploy-web/src/components/sdl/RentGpusForm.tsx b/deploy-web/src/components/sdl/RentGpusForm.tsx index 9e7ac9215..0737c8ae4 100644 --- a/deploy-web/src/components/sdl/RentGpusForm.tsx +++ b/deploy-web/src/components/sdl/RentGpusForm.tsx @@ -215,7 +215,6 @@ export const RentGpusForm: React.FunctionComponent = ({}) => { setIsDepositingDeployment(false)} onDeploymentDeposit={onDeploymentDeposit} - min={5} // TODO Query from chain params denom={currentService?.placement?.pricing?.denom || sdlDenom} infoText={ diff --git a/deploy-web/src/hooks/useWalletBalance.ts b/deploy-web/src/hooks/useWalletBalance.ts index 671b8e90e..810c696ed 100644 --- a/deploy-web/src/hooks/useWalletBalance.ts +++ b/deploy-web/src/hooks/useWalletBalance.ts @@ -5,6 +5,7 @@ import { udenomToDenom } from "@src/utils/mathHelpers"; import { uaktToAKT } from "@src/utils/priceUtils"; import { useEffect, useState } from "react"; import { useUsdcDenom } from "./useDenom"; +import { useDepositParams } from "@src/queries/useSettings"; export const useTotalWalletBalance = () => { const { isLoaded, price } = usePricing(); @@ -24,6 +25,7 @@ export const useTotalWalletBalance = () => { }; type DenomData = { + min: number; label: string; balance: number; inputMax: number; @@ -34,20 +36,30 @@ export const useDenomData = (denom: string) => { const { walletBalances } = useWallet(); const [depositData, setDepositData] = useState(null); const usdcIbcDenom = useUsdcDenom(); + const { data: depositParams, refetch: getDepositParams } = useDepositParams({ enabled: false }); useEffect(() => { - if (isLoaded && walletBalances) { - let depositData: DenomData = null; + getDepositParams(); + }, []); + + useEffect(() => { + if (isLoaded && walletBalances && depositParams) { + let depositData: DenomData = null, + params = null; switch (denom) { case uAktDenom: + params = depositParams.find(p => p.denom === uAktDenom); depositData = { + min: uaktToAKT(parseInt(params?.amount || 0)), label: "AKT", balance: uaktToAKT(walletBalances.uakt, 6), inputMax: uaktToAKT(Math.max(walletBalances.uakt - txFeeBuffer, 0), 6) }; break; case usdcIbcDenom: + params = depositParams.find(p => p.denom === usdcIbcDenom); depositData = { + min: udenomToDenom(parseInt(params?.amount || 0)), label: "USDC", balance: udenomToDenom(walletBalances.usdc, 6), inputMax: udenomToDenom(Math.max(walletBalances.usdc - txFeeBuffer, 0), 6) @@ -59,8 +71,7 @@ export const useDenomData = (denom: string) => { setDepositData(depositData); } - }, [denom, isLoaded, price, walletBalances, usdcIbcDenom]); + }, [denom, isLoaded, price, walletBalances, usdcIbcDenom, depositParams]); return depositData; }; - diff --git a/deploy-web/src/queries/queryKeys.ts b/deploy-web/src/queries/queryKeys.ts index 6d1c84a5b..1f7bf54ad 100644 --- a/deploy-web/src/queries/queryKeys.ts +++ b/deploy-web/src/queries/queryKeys.ts @@ -43,4 +43,5 @@ export class QueryKeys { static getBalancesKey = (address: string) => ["BALANCES", address]; static getTemplatesKey = () => ["TEMPLATES"]; static getProviderAttributesSchema = () => ["PROVIDER_ATTRIBUTES_SCHEMA"]; + static getDepositParamsKey = () => ["DEPOSIT_PARAMS"]; } diff --git a/deploy-web/src/queries/useSettings.ts b/deploy-web/src/queries/useSettings.ts index b19559a5c..10b5e4a86 100644 --- a/deploy-web/src/queries/useSettings.ts +++ b/deploy-web/src/queries/useSettings.ts @@ -1,8 +1,12 @@ +import { useSettings } from "@src/context/SettingsProvider"; import { useCustomUser } from "@src/hooks/useCustomUser"; import { UserSettings } from "@src/types/user"; +import { ApiUrlService } from "@src/utils/apiUtils"; import axios, { AxiosResponse } from "axios"; import { useSnackbar } from "notistack"; -import { useMutation } from "react-query"; +import { useMutation, useQuery } from "react-query"; +import { QueryKeys } from "./queryKeys"; +import { DepositParams, RpcDepositParams } from "@src/types/deployment"; export function useSaveSettings() { const { enqueueSnackbar } = useSnackbar(); @@ -19,3 +23,16 @@ export function useSaveSettings() { } }); } + +async function getDepositParams(apiEndpoint: string) { + const depositParamsQuery = await axios.get(ApiUrlService.depositParams(apiEndpoint)); + const depositParams = depositParamsQuery.data as RpcDepositParams; + const params = JSON.parse(depositParams.param.value) as DepositParams[]; + + return params; +} + +export function useDepositParams(options = {}) { + const { settings } = useSettings(); + return useQuery(QueryKeys.getDepositParamsKey(), () => getDepositParams(settings.apiEndpoint), options); +} diff --git a/deploy-web/src/types/deployment.ts b/deploy-web/src/types/deployment.ts index d7d105218..e4a9f6edb 100644 --- a/deploy-web/src/types/deployment.ts +++ b/deploy-web/src/types/deployment.ts @@ -63,26 +63,26 @@ interface DeploymentResource_V2 { units: { val: string; }; - attributes: {key: string, value: string}[]; + attributes: { key: string; value: string }[]; }; gpu: { units: { val: string; }; - attributes: {key: string, value: string}[]; + attributes: { key: string; value: string }[]; }; memory: { quantity: { val: string; }; - attributes: {key: string, value: string}[]; + attributes: { key: string; value: string }[]; }; storage: Array<{ name: string; quantity: { val: string; }; - attributes: {key: string, value: string}[]; + attributes: { key: string; value: string }[]; }>; endpoints: Array<{ kind: string; @@ -319,3 +319,17 @@ export interface BidDto { count: number; }>; } + +export interface RpcDepositParams { + param: { + subspace: string; + key: string; + // Array of { denom: string, amount: string } + value: string; + }; +} + +export interface DepositParams { + denom: string; + amount: string; +} diff --git a/deploy-web/src/types/network.ts b/deploy-web/src/types/network.ts index fb151485f..8347bc5b4 100644 --- a/deploy-web/src/types/network.ts +++ b/deploy-web/src/types/network.ts @@ -9,4 +9,4 @@ export type Network = { rpcEndpoint?: string; version: string; enabled: boolean; -}; +}; \ No newline at end of file diff --git a/deploy-web/src/utils/apiUtils.ts b/deploy-web/src/utils/apiUtils.ts index 18b2cb78e..b01626dc3 100644 --- a/deploy-web/src/utils/apiUtils.ts +++ b/deploy-web/src/utils/apiUtils.ts @@ -3,6 +3,9 @@ import axios from "axios"; import { appendSearchParams } from "./urlUtils"; export class ApiUrlService { + static depositParams(apiEndpoint: string) { + return `${apiEndpoint}/cosmos/params/v1beta1/params?subspace=deployment&key=MinDeposits`; + } static deploymentList(apiEndpoint: string, address: string) { return `${apiEndpoint}/akash/deployment/${networkVersion}/deployments/list?filters.owner=${address}`; } diff --git a/deploy-web/src/utils/deploymentDetailUtils.ts b/deploy-web/src/utils/deploymentDetailUtils.ts index 7321470c9..79a2e8bfe 100644 --- a/deploy-web/src/utils/deploymentDetailUtils.ts +++ b/deploy-web/src/utils/deploymentDetailUtils.ts @@ -1,4 +1,4 @@ -import { DeploymentDto, LeaseDto, RpcDeployment, RpcLease } from "@src/types/deployment"; +import { DeploymentDto, DepositParams, LeaseDto, RpcDeployment, RpcDepositParams, RpcLease } from "@src/types/deployment"; import { coinToUDenom } from "./priceUtils"; export function deploymentResourceSum(deployment: RpcDeployment, resourceSelector) {