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(deployment): ensure usd values in deployments for managed wallets #360

Merged
merged 2 commits into from
Sep 13, 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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const SignTxRequestInputSchema = z.object({
"/akash.cert.v1beta3.MsgCreateCertificate",
"/akash.market.v1beta4.MsgCreateLease",
"/akash.deployment.v1beta3.MsgUpdateDeployment",
"/akash.deployment.v1beta3.MsgCloseDeployment"
"/akash.deployment.v1beta3.MsgCloseDeployment",
"/akash.deployment.v1beta3.MsgDepositDeployment"
baktun14 marked this conversation as resolved.
Show resolved Hide resolved
]),
value: z.string()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const AllowanceModal: React.FunctionComponent<Props> = ({ editingAllowanc

const onBalanceClick = () => {
clearErrors();
setValue("amount", denomData?.inputMax || 0);
setValue("amount", denomData?.max || 0);
};

return (
Expand Down Expand Up @@ -143,7 +143,7 @@ export const AllowanceModal: React.FunctionComponent<Props> = ({ editingAllowanc
autoFocus
min={0}
step={0.000001}
max={denomData?.inputMax}
max={denomData?.max}
startIcon={<span className="pl-2 text-xs">{denomData?.label}</span>}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const GrantModal: React.FunctionComponent<Props> = ({ editingGrant, addre

const onBalanceClick = () => {
clearErrors();
setValue("amount", denomData?.inputMax || 0);
setValue("amount", denomData?.max || 0);
};

return (
Expand Down Expand Up @@ -187,7 +187,7 @@ export const GrantModal: React.FunctionComponent<Props> = ({ editingGrant, addre
autoFocus
min={0}
step={0.000001}
max={denomData?.inputMax}
max={denomData?.max}
startIcon={<span className="pl-2 text-xs">{denomData?.label}</span>}
className="ml-4 flex-grow"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ import { event } from "nextjs-google-analytics";
import { useSnackbar } from "notistack";
import { z } from "zod";

import { browserEnvConfig } from "@src/config/browser-env.config";
import { UAKT_DENOM } from "@src/config/denom.config";
import { usePricing } from "@src/context/PricingProvider";
import { useSettings } from "@src/context/SettingsProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useUsdcDenom } from "@src/hooks/useDenom";
import { useDenomData, useWalletBalance } from "@src/hooks/useWalletBalance";
import { useGranteeGrants } from "@src/queries/useGrantsQuery";
import { AnalyticsEvents } from "@src/utils/analytics";
import { denomToUdenom, udenomToDenom } from "@src/utils/mathHelpers";
import { coinToUDenom, uaktToAKT } from "@src/utils/priceUtils";
import { coinToUDenom } from "@src/utils/priceUtils";
import { LinkTo } from "../shared/LinkTo";
import { GranteeDepositMenuItem } from "./GranteeDepositMenuItem";

type Props = {
export type DeploymentDepositModalProps = {
infoText?: string | ReactNode;
disableMin?: boolean;
denom: string;
Expand Down Expand Up @@ -67,15 +68,22 @@ const formSchema = z
{ message: "Depositor address is required.", path: ["depositorAddress"] }
);

export const DeploymentDepositModal: React.FunctionComponent<Props> = ({ handleCancel, onDeploymentDeposit, disableMin, denom, infoText = null }) => {
export const DeploymentDepositModal: React.FunctionComponent<DeploymentDepositModalProps> = ({
handleCancel,
onDeploymentDeposit,
disableMin,
denom,
infoText = null
}) => {
const formRef = useRef<HTMLFormElement>(null);
const { settings } = useSettings();
const { enqueueSnackbar } = useSnackbar();
const [error, setError] = useState("");
const [isCheckingDepositor, setIsCheckingDepositor] = useState(false);
const { address } = useWallet();
const { address, isManaged, isCustodial } = useWallet();
const { balance: walletBalance } = useWalletBalance();
const { data: granteeGrants } = useGranteeGrants(address);
const pricing = usePricing();
const depositData = useDenomData(denom);
const form = useForm<z.infer<typeof formSchema>>({
defaultValues: {
Expand All @@ -87,7 +95,6 @@ export const DeploymentDepositModal: React.FunctionComponent<Props> = ({ handleC
});
const { handleSubmit, control, watch, setValue, clearErrors, unregister } = form;
const { amount, useDepositor, depositorAddress } = watch();
const usdcIbcDenom = useUsdcDenom();
const validGrants = granteeGrants?.filter(x => compareAsc(new Date(), new Date(x.expiration)) !== 1 && x.authorization.spend_limit.denom === denom) || [];

useEffect(() => {
Expand Down Expand Up @@ -156,7 +163,7 @@ export const DeploymentDepositModal: React.FunctionComponent<Props> = ({ handleC

const onBalanceClick = () => {
clearErrors();
setValue("amount", depositData?.inputMax || 0);
setValue("amount", depositData?.max || 0);
};

const onDepositClick = event => {
Expand All @@ -167,9 +174,8 @@ export const DeploymentDepositModal: React.FunctionComponent<Props> = ({ handleC
const onSubmit = async ({ amount, depositorAddress }: z.infer<typeof formSchema>) => {
setError("");
clearErrors();
const deposit = denomToUdenom(amount);
const uaktBalance = walletBalance?.balanceUAKT || 0;
const usdcBalance = walletBalance?.balanceUUSDC || 0;
const amountInDenom = (isManaged && denom === UAKT_DENOM ? pricing.usdToAkt(amount) : amount) || 0;
const deposit = denomToUdenom(amountInDenom);

if (!disableMin && amount < (depositData?.min || 0)) {
setError(`Deposit amount must be greater or equal than ${depositData?.min}.`);
Expand All @@ -186,15 +192,12 @@ export const DeploymentDepositModal: React.FunctionComponent<Props> = ({ handleC
category: "deployments",
label: "Use depositor to deposit in deployment"
});
} else if (denom === UAKT_DENOM && deposit > uaktBalance) {
setError(`You can't deposit more than you currently have in your balance. Current balance is: ${uaktToAKT(uaktBalance)} AKT.`);
return;
} else if (denom === usdcIbcDenom && deposit > usdcBalance) {
setError(`You can't deposit more than you currently have in your balance. Current balance is: ${udenomToDenom(usdcBalance)} USDC.`);
} else if (depositData && amountInDenom > depositData?.balance) {
setError(`You can't deposit more than you currently have in your balance. Current balance is: ${depositData?.balance} ${depositData?.label}.`);
return;
}

onDeploymentDeposit(deposit, depositorAddress as string);
onDeploymentDeposit(deposit, isManaged ? browserEnvConfig.NEXT_PUBLIC_MASTER_WALLET_ADDRESS : (depositorAddress as string));
};

return (
Expand Down Expand Up @@ -249,23 +252,25 @@ export const DeploymentDepositModal: React.FunctionComponent<Props> = ({ handleC
autoFocus
min={!disableMin ? depositData?.min : 0}
step={0.000001}
max={depositData?.inputMax}
max={depositData?.max}
startIcon={<div className="pl-2 text-xs">{depositData?.label}</div>}
/>
);
}}
/>
</div>

<div className="my-4 flex items-center">
<Controller
control={control}
name="useDepositor"
render={({ field }) => {
return <CheckboxWithLabel label="Use another address to fund" checked={field.value} onCheckedChange={field.onChange} />;
}}
/>
</div>
{isCustodial && (
<div className="my-4 flex items-center">
<Controller
control={control}
name="useDepositor"
render={({ field }) => {
return <CheckboxWithLabel label="Use another address to fund" checked={field.value} onCheckedChange={field.onChange} />;
}}
/>
</div>
)}

{useDepositor && (
<FormField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ type Props = {
export const DeploymentDetailTopBar: React.FunctionComponent<Props> = ({ address, loadDeploymentDetail, removeLeases, setActiveTab, deployment }) => {
const { changeDeploymentName, getDeploymentData, getDeploymentName } = useLocalNotes();
const router = useRouter();
const { signAndBroadcastTx, isManaged } = useWallet();
const { signAndBroadcastTx } = useWallet();
const [isDepositingDeployment, setIsDepositingDeployment] = useState(false);
const storageDeploymentData = getDeploymentData(deployment?.dseq);
const deploymentName = getDeploymentName(deployment?.dseq);
const previousRoute = usePreviousRoute();
const wallet = useWallet();
const { closeDeploymentConfirm } = useManagedDeploymentConfirm();

function handleBackClick() {
Expand Down Expand Up @@ -126,11 +125,9 @@ export const DeploymentDetailTopBar: React.FunctionComponent<Props> = ({ address
</DropdownMenuContent>
</DropdownMenu>

{!wallet.isManaged && (
<Button variant="default" className="ml-2 whitespace-nowrap" onClick={() => setIsDepositingDeployment(true)} size="sm">
Add funds
</Button>
)}
<Button variant="default" className="ml-2 whitespace-nowrap" onClick={() => setIsDepositingDeployment(true)} size="sm">
Add funds
</Button>
</div>
)}

Expand Down
72 changes: 43 additions & 29 deletions apps/deploy-web/src/components/deployments/DeploymentListRow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import { ReactNode, useState } from "react";
import { ReactNode, useMemo, useState } from "react";
import {
Button,
Checkbox,
Expand Down Expand Up @@ -36,7 +36,7 @@ import { CustomDropdownLinkItem } from "../shared/CustomDropdownLinkItem";
import { PricePerMonth } from "../shared/PricePerMonth";
import { PriceValue } from "../shared/PriceValue";
import { SpecDetailList } from "../shared/SpecDetailList";
import { DeploymentDepositModal } from "./DeploymentDepositModal";
import { DeploymentDepositModal, DeploymentDepositModalProps } from "./DeploymentDepositModal";
import { LeaseChip } from "./LeaseChip";

type Props = {
Expand Down Expand Up @@ -127,7 +127,7 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
setOpen(false);
};

const onDeploymentDeposit = async (deposit, depositorAddress) => {
const onDeploymentDeposit: DeploymentDepositModalProps["onDeploymentDeposit"] = async (deposit, depositorAddress) => {
setIsDepositingDeployment(false);

const message = TransactionMessageData.getDepositDeploymentMsg(address, deployment.dseq, deposit, deployment.escrowAccount.balance.denom, depositorAddress);
Expand Down Expand Up @@ -172,12 +172,23 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
router.push(url);
};

function onDepositClicked(e?: React.MouseEvent) {
function showDepositModal(e?: React.MouseEvent) {
e?.preventDefault();
e?.stopPropagation();
setIsDepositingDeployment(true);
}

const escrowBalanceInDenom = useMemo(() => {
let uDenomBalance: number | undefined;

if (isActive && hasActiveLeases && realTimeLeft) {
uDenomBalance = realTimeLeft?.escrow;
} else {
uDenomBalance = escrowBalance;
}
return uDenomBalance && udenomToDenom(uDenomBalance, 6);
}, [isActive, hasActiveLeases, realTimeLeft, escrowBalance]);

return (
<>
<TableRow className="cursor-pointer hover:bg-muted-foreground/10 [&>td]:p-2" onClick={() => viewDeployment()}>
Expand All @@ -202,13 +213,9 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
title={
<>
Your deployment will close soon,{" "}
{isManagedWallet ? (
"Add funds"
) : (
<a href="#" onClick={onDepositClicked}>
Add Funds
</a>
)}{" "}
<a href="#" onClick={showDepositModal}>
Add Funds
</a>{" "}
to keep it running.
</>
}
Expand All @@ -220,25 +227,30 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
)}
</TableCell>
<TableCell className="text-center">
{isActive && !!escrowBalance && (
{isActive && !!escrowBalanceInDenom && !!escrowBalance && (
<div className="inline-flex">
<PriceValue
denom={deployment.escrowAccount.balance.denom}
value={udenomToDenom(isActive && hasActiveLeases && realTimeLeft ? realTimeLeft?.escrow : escrowBalance, 6)}
/>
<PriceValue denom={deployment.escrowAccount.balance.denom} value={escrowBalanceInDenom} />
<CustomTooltip
title={
<div className="text-left">
<div className="space-x-2">
<span>Balance:</span>
<strong>
{udenomToDenom(isActive && hasActiveLeases && realTimeLeft ? realTimeLeft?.escrow : escrowBalance, 6)}&nbsp;{denomData?.label}
{isManagedWallet ? (
<PriceValue denom={deployment.escrowAccount.balance.denom} value={escrowBalanceInDenom} />
) : (
`${escrowBalanceInDenom}&nbsp;{denomData?.label}`
)}
</strong>
</div>
<div className="space-x-2">
<span>Spent:</span>
<strong>
{udenomToDenom(amountSpent || 0, 2)} {denomData?.label}
{isManagedWallet ? (
<PriceValue denom={deployment.escrowAccount.balance.denom} value={udenomToDenom(amountSpent || 0, 2)} />
) : (
`${udenomToDenom(amountSpent || 0, 2)}&nbsp;${denomData?.label}`
)}
</strong>
</div>
<br />
Expand All @@ -265,15 +277,17 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
<div className="flex items-center">
<PricePerMonth denom={deployment.escrowAccount.balance.denom} perBlockValue={udenomToDenom(deploymentCost, 10)} className="whitespace-nowrap" />

<CustomTooltip
title={
<span>
{avgCost} {denomData?.label} / month
</span>
}
>
<InfoCircle className="ml-2 text-xs text-muted-foreground" />
</CustomTooltip>
{!isManagedWallet && (
<CustomTooltip
title={
<span>
{avgCost} {denomData?.label} / month
</span>
}
>
<InfoCircle className="ml-2 text-xs text-muted-foreground" />
</CustomTooltip>
)}
</div>
</div>
)}
Expand Down Expand Up @@ -318,8 +332,8 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
>
<ClickAwayListener onClickAway={() => setOpen(false)}>
<div>
{isActive && !isManagedWallet && (
<CustomDropdownLinkItem onClick={onDepositClicked} icon={<Plus fontSize="small" />}>
{isActive && (
<CustomDropdownLinkItem onClick={showDepositModal} icon={<Plus fontSize="small" />}>
Add funds
</CustomDropdownLinkItem>
)}
Expand Down
Loading
Loading