Skip to content

Commit

Permalink
features/multi-denom-deposits (#4)
Browse files Browse the repository at this point in the history
* update repo urls for config

* added usdc balance

* added denom from SDL to deposit modal

* handle deposit amount based on denom sdl

* added caching for market data

* handle usdc denom for price display

* added usdc balance to your account component

* pre-requisites + get started multi denom

* update akashjs 0.4.11

* fix popup + deposit data

* small fix

* added caching for market data in getDeployment

* Update deploy-web/src/components/newDeploymentWizard/PrerequisiteList.tsx

Co-authored-by: Maxime Cyr <[email protected]>

---------

Co-authored-by: Maxime Cyr <[email protected]>
  • Loading branch information
baktun14 and Redm4x authored Aug 31, 2023
1 parent 76550b4 commit d445527
Show file tree
Hide file tree
Showing 49 changed files with 710 additions and 503 deletions.
1 change: 0 additions & 1 deletion api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ When running the api locally the following environment variables can be set in a
|-|-|-
HealthchecksEnabled|`true` or `false`|Specify if the [Scheduler](./src/index.ts#L42) should send health check pings.
SentryDSN|ex: `"https://[email protected]/1234"`|[Sentry DSN](https://docs.sentry.io/product/sentry-basics/dsn-explainer/) used when [initializing](./src/index.ts#L29) Sentry
HealthChecks_SyncAKTMarketData|ex: `041b2561-be28-4a36-bb3f-36a68f86224e`|[HealthChecks.io](https://healthchecks.io) check ID for the `SyncAKTMarketData` task.
AkashDatabaseCS|ex: `postgres://user:password@localhost:5432/cloudmos-akash`|Akash Database Connection String
UserDatabaseCS|ex: `postgres://user:password@localhost:5432/cloudmos-users`|User Database Connection String
Auth0JWKSUri|ex: `'https://1a2b3c.us.auth0.com/.well-known/jwks.json'`|
Expand Down
3 changes: 2 additions & 1 deletion api/src/caching/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ export const cacheKeys = {
getProviderActiveLeasesGraphData: "getProviderActiveLeasesGraphData",
getProviderAttributesSchema: "getProviderAttributesSchema",
getTemplates: "getTemplates",
getMarketData: "getMarketData",
getAuditors: "getAuditors",
getChainStats: "getChainStats",
getMainnetNodes: "getMainnetNodes",
getTestnetNodes: "getTestnetNodes",
getSandboxNodes: "getSandboxNodes",
getMainnetVersion: "getMainnetVersion",
getTestnetVersion: "getTestnetVersion",
getSandboxVersion: "getSandboxVersion",
getSandboxVersion: "getSandboxVersion"
};
4 changes: 0 additions & 4 deletions api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,6 @@ app.get("/status", (req, res) => {
app.use(Sentry.Handlers.errorHandler());

function startScheduler() {
scheduler.registerTask("Sync AKT Market Data", marketDataProvider.fetchLatestData, "5 minutes", true, {
id: env.HealthChecks_SyncAKTMarketData,
measureDuration: true
});
scheduler.start();
}

Expand Down
10 changes: 7 additions & 3 deletions api/src/providers/apiNodeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fetch from "node-fetch";
import { getDeploymentRelatedMessages } from "../db/deploymentProvider";
import { averageBlockCountInAMonth } from "@src/shared/constants";
import { round } from "@src/shared/utils/math";
import { getAktMarketData } from "./marketDataProvider";
import { getMarketData } from "./marketDataProvider";
import { coinToAsset } from "@src/shared/utils/coin";
import { getTransactionByAddress } from "@src/db/transactionsProvider";
import axios from "axios";
Expand Down Expand Up @@ -339,7 +339,9 @@ export async function getDeployment(owner: string, dseq: string) {
include: [{ model: ProviderAttribute }]
});

const aktPrice = getAktMarketData()?.price;
const marketData = await cacheResponse(60 * 5, cacheKeys.getMarketData, getMarketData);
const aktPrice = marketData?.price;
const deploymentDenom = deploymentData.escrow_account.balance.denom;

const leases = leasesData.leases.map((x) => {
const provider = providers.find((p) => p.owner === x.lease.lease_id.provider);
Expand All @@ -359,8 +361,10 @@ export async function getDeployment(owner: string, dseq: string) {
}))
},
status: x.lease.state,
denom: deploymentDenom,
monthlyCostAKT: round(monthlyUAKT / 1_000_000, 2),
monthlyCostUSD: aktPrice ? round((monthlyUAKT / 1_000_000) * aktPrice, 2) : null,
// TODO Improve
monthlyCostUSD: deploymentDenom === "uakt" ? (aktPrice ? round((monthlyUAKT / 1_000_000) * aktPrice, 2) : round(monthlyUAKT / 1_000_000, 2)) : null,
cpuUnits: group.group_spec.resources.map((r) => parseInt(r.resources.cpu.units.val) * r.count).reduce((a, b) => a + b, 0),
gpuUnits: group.group_spec.resources.map((r) => parseInt(r.resources.gpu?.units?.val) * r.count || 0).reduce((a, b) => a + b, 0),
memoryQuantity: group.group_spec.resources.map((r) => parseInt(r.resources.memory.quantity.val) * r.count).reduce((a, b) => a + b, 0),
Expand Down
30 changes: 11 additions & 19 deletions api/src/providers/marketDataProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import fetch from "node-fetch";
import axios from "axios";

interface AktMarketData {
price: number;
Expand All @@ -9,26 +9,18 @@ interface AktMarketData {
priceChangePercentage24: number;
}

let aktMarketData: AktMarketData = null;

export async function fetchLatestData() {
export async function getMarketData(): Promise<AktMarketData> {
const endpointUrl = "https://api.coingecko.com/api/v3/coins/akash-network";

// TODO USDC https://api.coingecko.com/api/v3/coins/usd-coin
console.log("Fetching latest market data from " + endpointUrl);
const response = await axios.get(endpointUrl);

const response = await fetch(endpointUrl);
const data = await response.json();

aktMarketData = {
price: parseFloat(data.market_data.current_price.usd),
volume: parseInt(data.market_data.total_volume.usd),
marketCap: parseInt(data.market_data.market_cap.usd),
marketCapRank: data.market_cap_rank,
priceChange24h: parseFloat(data.market_data.price_change_24h),
priceChangePercentage24: parseFloat(data.market_data.price_change_percentage_24h)
return {
price: parseFloat(response.data.market_data.current_price.usd),
volume: parseInt(response.data.market_data.total_volume.usd),
marketCap: parseInt(response.data.market_data.market_cap.usd),
marketCapRank: response.data.market_cap_rank,
priceChange24h: parseFloat(response.data.market_data.price_change_24h),
priceChangePercentage24: parseFloat(response.data.market_data.price_change_percentage_24h)
};
}

export const getAktMarketData = () => {
return aktMarketData;
};
2 changes: 1 addition & 1 deletion api/src/providers/providerAttributesProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const getProviderAttributesSchema = async () => {
const response = await cacheResponse(
30,
cacheKeys.getProviderAttributesSchema,
async () => await axios.get("https://raw.githubusercontent.com/ovrclk/cloudmos-config/master/provider-attributes.json")
async () => await axios.get("https://raw.githubusercontent.com/akash-network/cloudmos/main/config/provider-attributes.json")
);

return response.data;
Expand Down
16 changes: 8 additions & 8 deletions api/src/routers/apiRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from "@src/providers/apiNodeProvider";
import { getNetworkCapacity, getProviders } from "@src/providers/providerStatusProvider";
import { getDashboardData, getGraphData, getProviderActiveLeasesGraphData, getProviderGraphData } from "@src/db/statsProvider";
import * as marketDataProvider from "@src/providers/marketDataProvider";
import { round } from "@src/shared/utils/math";
import { isValidBech32Address } from "@src/shared/utils/addresses";
import { getAkashPricing, getAWSPricing, getAzurePricing, getGCPPricing } from "@src/shared/utils/pricing";
Expand All @@ -23,6 +22,7 @@ import { ProviderStatsKey } from "@src/types/graph";
import { getProviderAttributesSchema } from "@src/providers/providerAttributesProvider";
import { cacheKeys, cacheResponse } from "@src/caching/helpers";
import axios from "axios";
import { getMarketData } from "@src/providers/marketDataProvider";

export const apiRouter = express.Router();

Expand Down Expand Up @@ -233,9 +233,9 @@ apiRouter.get(
})
);

apiRouter.get("/marketData", (req, res) => {
const marketData = marketDataProvider.getAktMarketData();
res.send(marketData);
apiRouter.get("/marketData", async (req, res) => {
const response = await cacheResponse(60 * 5, cacheKeys.getMarketData, getMarketData);
res.send(response);
});

apiRouter.get(
Expand Down Expand Up @@ -368,7 +368,7 @@ apiRouter.get(
"/getAuditors",
asyncHandler(async (req, res) => {
const response = await cacheResponse(60 * 5, cacheKeys.getAuditors, async () => {
const res = await axios.get("https://raw.githubusercontent.com/ovrclk/cloudmos-config/master/auditors.json");
const res = await axios.get("https://raw.githubusercontent.com/akash-network/cloudmos/main/config/auditors.json");
return res.data;
});
res.send(response);
Expand All @@ -379,7 +379,7 @@ apiRouter.get(
"/getMainnetNodes",
asyncHandler(async (req, res) => {
const response = await cacheResponse(60 * 2, cacheKeys.getMainnetNodes, async () => {
const res = await axios.get("https://raw.githubusercontent.com/ovrclk/cloudmos-config/master/mainnet-nodes.json");
const res = await axios.get("https://raw.githubusercontent.com/akash-network/cloudmos/main/config/mainnet-nodes.json");
return res.data;
});
res.send(response);
Expand All @@ -390,7 +390,7 @@ apiRouter.get(
"/getTestnetNodes",
asyncHandler(async (req, res) => {
const response = await cacheResponse(60 * 2, cacheKeys.getTestnetNodes, async () => {
const res = await axios.get("https://raw.githubusercontent.com/ovrclk/cloudmos-config/master/testnet-nodes.json");
const res = await axios.get("https://raw.githubusercontent.com/akash-network/cloudmos/main/config/testnet-nodes.json");
return res.data;
});
res.send(response);
Expand All @@ -401,7 +401,7 @@ apiRouter.get(
"/getSandboxNodes",
asyncHandler(async (req, res) => {
const response = await cacheResponse(60 * 2, cacheKeys.getSandboxNodes, async () => {
const res = await axios.get("https://raw.githubusercontent.com/ovrclk/cloudmos-config/master/sandbox-nodes.json");
const res = await axios.get("https://raw.githubusercontent.com/akash-network/cloudmos/main/config/sandbox-nodes.json");
return res.data;
});
res.send(response);
Expand Down
1 change: 0 additions & 1 deletion api/src/shared/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import dotenv from "dotenv";
dotenv.config();

export const env = {
HealthChecks_SyncAKTMarketData: process.env.HealthChecks_SyncAKTMarketData,
SentryDSN: process.env.SentryDSN,
AKASHLYTICS_CORS_WEBSITE_URLS: process.env.AKASHLYTICS_CORS_WEBSITE_URLS,
NODE_ENV: process.env.NODE_ENV,
Expand Down
14 changes: 7 additions & 7 deletions deploy-web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion deploy-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"pretty": "prettier --write \"./**/*.{js,jsx,ts,tsx,json}\""
},
"dependencies": {
"@akashnetwork/akashjs": "^0.4.9",
"@akashnetwork/akashjs": "^0.4.11",
"@auth0/nextjs-auth0": "^3.1.0",
"@cosmjs/encoding": "^0.29.5",
"@cosmjs/stargate": "^0.29.5",
Expand Down
45 changes: 36 additions & 9 deletions deploy-web/src/components/deployment/DeploymentListRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { SpecDetailList } from "../shared/SpecDetailList";
import { useAllLeases } from "@src/queries/useLeaseQuery";
import { makeStyles } from "tss-react/mui";
import { useRouter } from "next/router";
import { getAvgCostPerMonth, getTimeLeft, uaktToAKT, useRealTimeLeft } from "@src/utils/priceUtils";
import { getAvgCostPerMonth, getTimeLeft, useRealTimeLeft } from "@src/utils/priceUtils";
import { Box, Checkbox, CircularProgress, darken, IconButton, Menu, TableCell, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material";
import { UrlService } from "@src/utils/urlUtils";
import { cx } from "@emotion/css";
Expand All @@ -32,6 +32,8 @@ import { CustomTooltip } from "../shared/CustomTooltip";
import InfoIcon from "@mui/icons-material/Info";
import { PricePerMonth } from "../shared/PricePerMonth";
import PublishIcon from "@mui/icons-material/Publish";
import { udenomToDenom } from "@src/utils/mathHelpers";
import { useDenomData } from "@src/hooks/useWalletBalance";

const useStyles = makeStyles()(theme => ({
root: {
Expand Down Expand Up @@ -126,8 +128,9 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
const amountSpent = isActive && hasActiveLeases ? realTimeLeft?.amountSpent : deployment.transferred.amount;
const isValidTimeLeft = isActive && hasActiveLeases && isValid(realTimeLeft?.timeLeft);
const theme = useTheme();
const avgCost = uaktToAKT(getAvgCostPerMonth(deploymentCost));
const avgCost = udenomToDenom(getAvgCostPerMonth(deploymentCost));
const storageDeploymentData = getDeploymentData(deployment?.dseq);
const denomData = useDenomData(deployment.escrowAccount.balance.denom);

function viewDeployment() {
router.push(UrlService.deploymentDetails(deployment.dseq));
Expand All @@ -147,7 +150,13 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
setIsDepositingDeployment(false);

try {
const message = TransactionMessageData.getDepositDeploymentMsg(address, deployment.dseq, deposit, depositorAddress);
const message = TransactionMessageData.getDepositDeploymentMsg(
address,
deployment.dseq,
deposit,
deployment.escrowAccount.balance.denom,
depositorAddress
);
const response = await signAndBroadcastTx([message]);
if (response) {
refreshDeployments();
Expand Down Expand Up @@ -227,13 +236,20 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
<TableCell align="center">
{isActive && !!escrowBalance && (
<Box marginLeft={isValidTimeLeft ? "1rem" : 0} display="flex">
<PriceValue value={uaktToAKT(isActive && hasActiveLeases ? realTimeLeft?.escrow : escrowBalance, 6)} />
<PriceValue
denom={deployment.escrowAccount.balance.denom}
value={udenomToDenom(isActive && hasActiveLeases ? realTimeLeft?.escrow : escrowBalance, 6)}
/>
<CustomTooltip
arrow
title={
<>
<strong>{uaktToAKT(isActive && hasActiveLeases ? realTimeLeft?.escrow : escrowBalance, 6)}&nbsp;AKT</strong>
<Box display="flex">{uaktToAKT(amountSpent, 2)} AKT spent</Box>
<strong>
{udenomToDenom(isActive && hasActiveLeases ? realTimeLeft?.escrow : escrowBalance, 6)}&nbsp;{denomData.label}
</strong>
<Box display="flex">
{udenomToDenom(amountSpent, 2)} {denomData.label} spent
</Box>
<br />
The escrow account balance will be fully returned to your wallet balance when the deployment is closed.{" "}
</>
Expand All @@ -258,9 +274,16 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
{isActive && !!deploymentCost && (
<Box marginLeft="1rem" display="flex">
<Box sx={{ display: "flex", alignItems: "center" }}>
<PricePerMonth perBlockValue={uaktToAKT(deploymentCost, 6)} typoVariant="body1" />
<PricePerMonth denom={deployment.escrowAccount.balance.denom} perBlockValue={udenomToDenom(deploymentCost, 6)} typoVariant="body1" />

<CustomTooltip arrow title={<span>{avgCost} AKT / month</span>}>
<CustomTooltip
arrow
title={
<span>
{avgCost} {denomData.label} / month
</span>
}
>
<InfoIcon fontSize="small" color="disabled" sx={{ marginLeft: ".5rem" }} />
</CustomTooltip>
</Box>
Expand Down Expand Up @@ -330,7 +353,11 @@ export const DeploymentListRow: React.FunctionComponent<Props> = ({ deployment,
</Menu>

{isActive && isDepositingDeployment && (
<DeploymentDepositModal handleCancel={() => setIsDepositingDeployment(false)} onDeploymentDeposit={onDeploymentDeposit} />
<DeploymentDepositModal
denom={deployment.escrowAccount.balance.denom}
handleCancel={() => setIsDepositingDeployment(false)}
onDeploymentDeposit={onDeploymentDeposit}
/>
)}
</>
);
Expand Down
Loading

0 comments on commit d445527

Please sign in to comment.