diff --git a/api/src/caching/helpers.ts b/api/src/caching/helpers.ts index 07a735d143..24494fdbe4 100644 --- a/api/src/caching/helpers.ts +++ b/api/src/caching/helpers.ts @@ -51,6 +51,7 @@ export const cacheKeys = { getProviderAttributesSchema: "getProviderAttributesSchema", getTemplates: "getTemplates", getAuditors: "getAuditors", + getChainStats: "getChainStats", getMainnetNodes: "getMainnetNodes", getTestnetNodes: "getTestnetNodes", getSandboxNodes: "getSandboxNodes", diff --git a/api/src/providers/apiNodeProvider.ts b/api/src/providers/apiNodeProvider.ts index 0f43f19bd2..305d9b5076 100644 --- a/api/src/providers/apiNodeProvider.ts +++ b/api/src/providers/apiNodeProvider.ts @@ -9,37 +9,47 @@ import axios from "axios"; import { Validator } from "@shared/dbSchemas/base"; import { Op } from "sequelize"; import { Provider, ProviderAttribute } from "@shared/dbSchemas/akash"; +import { cacheKeys, cacheResponse } from "@src/caching/helpers"; const apiNodeUrl = process.env.Network === "testnet" ? "https://api.testnet-02.aksh.pw:443" : "https://rest.cosmos.directory/akash"; const betaTypeVersion = process.env.Network === "testnet" ? "v1beta3" : "v1beta2"; export async function getChainStats() { - const bondedTokensQuery = axios.get(`${apiNodeUrl}/cosmos/staking/v1beta1/pool`); - const supplyQuery = axios.get(`${apiNodeUrl}/cosmos/bank/v1beta1/supply`); - const communityPoolQuery = axios.get(`${apiNodeUrl}/cosmos/distribution/v1beta1/community_pool`); - const inflationQuery = axios.get(`${apiNodeUrl}/cosmos/mint/v1beta1/inflation`); - const distributionQuery = axios.get(`${apiNodeUrl}/cosmos/distribution/v1beta1/params`); - - const [bondedTokensResponse, supplyResponse, communityPoolResponse, inflationResponse, distributionResponse] = await Promise.all([ - bondedTokensQuery, - supplyQuery, - communityPoolQuery, - inflationQuery, - distributionQuery - ]); - - const communityPool = parseFloat(communityPoolResponse.data.pool.find((x) => x.denom === "uakt").amount); - const inflation = parseFloat(inflationResponse.data.inflation); - const communityTax = parseFloat(distributionResponse.data.params.community_tax); - const bondedTokens = parseInt(bondedTokensResponse.data.pool.bonded_tokens); - const totalSupply = parseInt(supplyResponse.data.supply.find((x) => x.denom === "uakt").amount); + const result: { communityPool: number; inflation: number; communityTax: number; bondedTokens: number; totalSupply: number } = await cacheResponse( + 60 * 5, // 5 minutes + cacheKeys.getChainStats, + async () => { + const bondedTokensQuery = axios.get(`${apiNodeUrl}/cosmos/staking/v1beta1/pool`); + const supplyQuery = axios.get(`${apiNodeUrl}/cosmos/bank/v1beta1/supply`); + const communityPoolQuery = axios.get(`${apiNodeUrl}/cosmos/distribution/v1beta1/community_pool`); + const inflationQuery = axios.get(`${apiNodeUrl}/cosmos/mint/v1beta1/inflation`); + const distributionQuery = axios.get(`${apiNodeUrl}/cosmos/distribution/v1beta1/params`); + + const [bondedTokensResponse, supplyResponse, communityPoolResponse, inflationResponse, distributionResponse] = await Promise.all([ + bondedTokensQuery, + supplyQuery, + communityPoolQuery, + inflationQuery, + distributionQuery + ]); + + return { + communityPool: parseFloat(communityPoolResponse.data.pool.find((x) => x.denom === "uakt").amount), + inflation: parseFloat(inflationResponse.data.inflation), + communityTax: parseFloat(distributionResponse.data.params.community_tax), + bondedTokens: parseInt(bondedTokensResponse.data.pool.bonded_tokens), + totalSupply: parseInt(supplyResponse.data.supply.find((x) => x.denom === "uakt").amount) + }; + }, + true + ); return { - bondedTokens: bondedTokens, - totalSupply: totalSupply, - communityPool: communityPool, - inflation: inflation, - stakingAPR: (inflation * (1 - communityTax)) / (bondedTokens / totalSupply) + bondedTokens: result.bondedTokens, + totalSupply: result.totalSupply, + communityPool: result.communityPool, + inflation: result.inflation, + stakingAPR: (result.inflation * (1 - result.communityTax)) / (result.bondedTokens / result.totalSupply) }; } diff --git a/deploy-web/next.config.js b/deploy-web/next.config.js index 5011c7108d..ac4c832feb 100644 --- a/deploy-web/next.config.js +++ b/deploy-web/next.config.js @@ -30,6 +30,13 @@ const moduleExports = { sentry: { hideSourceMaps: true }, + webpack: config => { + // Fixes npm packages that depend on `node:crypto` module + config.externals.push({ + "node:crypto": "crypto" + }); + return config; + }, redirects: async () => { return [ { diff --git a/deploy-web/package-lock.json b/deploy-web/package-lock.json index 719d7be1fe..1dc9892a3a 100644 --- a/deploy-web/package-lock.json +++ b/deploy-web/package-lock.json @@ -9,7 +9,7 @@ "version": "1.3.5", "license": "Apache-2.0", "dependencies": { - "@akashnetwork/akashjs": "^0.4.0", + "@akashnetwork/akashjs": "^0.4.9", "@auth0/nextjs-auth0": "^1.9.1", "@cosmjs/encoding": "^0.29.5", "@cosmjs/stargate": "^0.29.5", @@ -88,9 +88,9 @@ } }, "node_modules/@akashnetwork/akashjs": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@akashnetwork/akashjs/-/akashjs-0.4.0.tgz", - "integrity": "sha512-b87XZDAjWF9TiMR8QvS5VfzUowtwmN7rKRJgArY72jE5bwwUAEcsM+U4puzJUXOfuDlcO3nPjpeuxG66bSTELg==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@akashnetwork/akashjs/-/akashjs-0.4.9.tgz", + "integrity": "sha512-E3m1W1/McGqz0A4ml6ksIF6TRX0zRIjOgT7zY1tbnvYkUUT1xbAs7BYuBurNj3YQs89rmab9vhWRm/l27RYgNQ==", "dependencies": { "@cosmjs/launchpad": "^0.27.0", "@cosmjs/proto-signing": "^0.28.11", @@ -27959,9 +27959,9 @@ }, "dependencies": { "@akashnetwork/akashjs": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@akashnetwork/akashjs/-/akashjs-0.4.0.tgz", - "integrity": "sha512-b87XZDAjWF9TiMR8QvS5VfzUowtwmN7rKRJgArY72jE5bwwUAEcsM+U4puzJUXOfuDlcO3nPjpeuxG66bSTELg==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@akashnetwork/akashjs/-/akashjs-0.4.9.tgz", + "integrity": "sha512-E3m1W1/McGqz0A4ml6ksIF6TRX0zRIjOgT7zY1tbnvYkUUT1xbAs7BYuBurNj3YQs89rmab9vhWRm/l27RYgNQ==", "requires": { "@cosmjs/launchpad": "^0.27.0", "@cosmjs/proto-signing": "^0.28.11", diff --git a/deploy-web/package.json b/deploy-web/package.json index aa55e8915a..9c7dc52f4d 100644 --- a/deploy-web/package.json +++ b/deploy-web/package.json @@ -12,7 +12,7 @@ "type-check": "tsc" }, "dependencies": { - "@akashnetwork/akashjs": "^0.4.0", + "@akashnetwork/akashjs": "^0.4.9", "@auth0/nextjs-auth0": "^1.9.1", "@cosmjs/encoding": "^0.29.5", "@cosmjs/stargate": "^0.29.5", diff --git a/deploy-web/public/sw.js b/deploy-web/public/sw.js index bef3a2725e..2761cd63be 100644 --- a/deploy-web/public/sw.js +++ b/deploy-web/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,s={};const a=(a,c)=>(a=new URL(a+".js",c).href,s[a]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()})).then((()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(c,i)=>{const n=e||("document"in self?document.currentScript.src:"")||location.href;if(s[n])return;let t={};const r=e=>a(e,n),d={module:{uri:n},exports:t,require:r};s[n]=Promise.all(c.map((e=>d[e]||r(e)))).then((e=>(i(...e),t)))}}define(["./workbox-19663cdd"],(function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/chunks/1335-d73c269694583478.js",revision:"d73c269694583478"},{url:"/_next/static/chunks/1350-07f9659f28f558f8.js",revision:"07f9659f28f558f8"},{url:"/_next/static/chunks/1443-476ed025db3dd4b1.js",revision:"476ed025db3dd4b1"},{url:"/_next/static/chunks/1553-95b0c0d29fbb3445.js",revision:"95b0c0d29fbb3445"},{url:"/_next/static/chunks/1710-666ff1ead13f838d.js",revision:"666ff1ead13f838d"},{url:"/_next/static/chunks/2018-fc14dcb8e6f0c032.js",revision:"fc14dcb8e6f0c032"},{url:"/_next/static/chunks/2331.80fdf1c43b91f669.js",revision:"80fdf1c43b91f669"},{url:"/_next/static/chunks/4044-80c30f3a2b5e944f.js",revision:"80c30f3a2b5e944f"},{url:"/_next/static/chunks/4400-481f1f09599f62a2.js",revision:"481f1f09599f62a2"},{url:"/_next/static/chunks/449.0c771afcc1995d26.js",revision:"0c771afcc1995d26"},{url:"/_next/static/chunks/4729-899a5d4ff8ee3aca.js",revision:"899a5d4ff8ee3aca"},{url:"/_next/static/chunks/4848-98d5115b09d0bc29.js",revision:"98d5115b09d0bc29"},{url:"/_next/static/chunks/5054-3be601e5ff47a6b1.js",revision:"3be601e5ff47a6b1"},{url:"/_next/static/chunks/5105-27d232f986a447c2.js",revision:"27d232f986a447c2"},{url:"/_next/static/chunks/5632.889b47838578051c.js",revision:"889b47838578051c"},{url:"/_next/static/chunks/5644-8b5cbb139a37740c.js",revision:"8b5cbb139a37740c"},{url:"/_next/static/chunks/609-deabd5ec9a55d407.js",revision:"deabd5ec9a55d407"},{url:"/_next/static/chunks/6183-cb7bbe9f563fd4cb.js",revision:"cb7bbe9f563fd4cb"},{url:"/_next/static/chunks/652.94ff65c899230787.js",revision:"94ff65c899230787"},{url:"/_next/static/chunks/659-5c9173913cac5403.js",revision:"5c9173913cac5403"},{url:"/_next/static/chunks/6698-4f9830af81c66dbc.js",revision:"4f9830af81c66dbc"},{url:"/_next/static/chunks/678-08876ec4989a640b.js",revision:"08876ec4989a640b"},{url:"/_next/static/chunks/6782.fee4f7987d5f0efa.js",revision:"fee4f7987d5f0efa"},{url:"/_next/static/chunks/6886-fa7338eaa9ba83dd.js",revision:"fa7338eaa9ba83dd"},{url:"/_next/static/chunks/69fc0a3a-4b10f93d935c96d6.js",revision:"4b10f93d935c96d6"},{url:"/_next/static/chunks/7047-9a583fff28dfc3e1.js",revision:"9a583fff28dfc3e1"},{url:"/_next/static/chunks/7449-2549ca7b57bd6471.js",revision:"2549ca7b57bd6471"},{url:"/_next/static/chunks/8329.3e3b26692eec5f3b.js",revision:"3e3b26692eec5f3b"},{url:"/_next/static/chunks/8364-525ff7c5ef9bd630.js",revision:"525ff7c5ef9bd630"},{url:"/_next/static/chunks/8446-d0c2d9e64c060c9b.js",revision:"d0c2d9e64c060c9b"},{url:"/_next/static/chunks/8487-d3900a8beded1bb1.js",revision:"d3900a8beded1bb1"},{url:"/_next/static/chunks/8606-41f13b88a2de459f.js",revision:"41f13b88a2de459f"},{url:"/_next/static/chunks/8705-d2c5e4e46530ef3a.js",revision:"d2c5e4e46530ef3a"},{url:"/_next/static/chunks/9130-1e3c1f7d477129e9.js",revision:"1e3c1f7d477129e9"},{url:"/_next/static/chunks/9179-9e8c296964e2d66d.js",revision:"9e8c296964e2d66d"},{url:"/_next/static/chunks/9188-cbbec32407303a76.js",revision:"cbbec32407303a76"},{url:"/_next/static/chunks/9196-9b4def108a2c6ae9.js",revision:"9b4def108a2c6ae9"},{url:"/_next/static/chunks/9266-e0eca9eae0c5af3a.js",revision:"e0eca9eae0c5af3a"},{url:"/_next/static/chunks/942-dc48eacaaac6db13.js",revision:"dc48eacaaac6db13"},{url:"/_next/static/chunks/9604-189ed1e3ef3ddfd1.js",revision:"189ed1e3ef3ddfd1"},{url:"/_next/static/chunks/9778-bd4ea537f0629051.js",revision:"bd4ea537f0629051"},{url:"/_next/static/chunks/9912-3b8166bd0ea324e7.js",revision:"3b8166bd0ea324e7"},{url:"/_next/static/chunks/9f96d65d-7b812644c8c0f1f1.js",revision:"7b812644c8c0f1f1"},{url:"/_next/static/chunks/ed150ef9.ec0fa51ac82b6bd3.js",revision:"ec0fa51ac82b6bd3"},{url:"/_next/static/chunks/framework-4ed89e9640adfb9e.js",revision:"4ed89e9640adfb9e"},{url:"/_next/static/chunks/main-75a41b17c9b01e3f.js",revision:"75a41b17c9b01e3f"},{url:"/_next/static/chunks/pages/404-ab9b7d32c55398fc.js",revision:"ab9b7d32c55398fc"},{url:"/_next/static/chunks/pages/500-d4e5b18ce237340e.js",revision:"d4e5b18ce237340e"},{url:"/_next/static/chunks/pages/_error-7423268f1234c13b.js",revision:"7423268f1234c13b"},{url:"/_next/static/chunks/pages/addresses/%5Baddress%5D-3370aa9e3f7cbdc8.js",revision:"3370aa9e3f7cbdc8"},{url:"/_next/static/chunks/pages/addresses/%5Baddress%5D/deployments-c51da00df0e852dc.js",revision:"c51da00df0e852dc"},{url:"/_next/static/chunks/pages/addresses/%5Baddress%5D/transactions-e6f64d450588ed13.js",revision:"e6f64d450588ed13"},{url:"/_next/static/chunks/pages/analytics-8ed9a4fd28298a18.js",revision:"8ed9a4fd28298a18"},{url:"/_next/static/chunks/pages/blocks-7a53ae2168d67a64.js",revision:"7a53ae2168d67a64"},{url:"/_next/static/chunks/pages/blocks/%5Bheight%5D-4bd91f069b2c1060.js",revision:"4bd91f069b2c1060"},{url:"/_next/static/chunks/pages/contact-dde75c7b4337b91c.js",revision:"dde75c7b4337b91c"},{url:"/_next/static/chunks/pages/deployment/%5Bowner%5D/%5Bdseq%5D-8f41254ce3690df1.js",revision:"8f41254ce3690df1"},{url:"/_next/static/chunks/pages/deployments-5d919633187e18aa.js",revision:"5d919633187e18aa"},{url:"/_next/static/chunks/pages/deployments/%5Bdseq%5D-9a6d30004d233446.js",revision:"9a6d30004d233446"},{url:"/_next/static/chunks/pages/get-started-18e522372d94db60.js",revision:"18e522372d94db60"},{url:"/_next/static/chunks/pages/get-started/wallet-ba64061ef9ef5a50.js",revision:"ba64061ef9ef5a50"},{url:"/_next/static/chunks/pages/graph/%5Bsnapshot%5D-406919dd43df3886.js",revision:"406919dd43df3886"},{url:"/_next/static/chunks/pages/index-1c595c5aaff41497.js",revision:"1c595c5aaff41497"},{url:"/_next/static/chunks/pages/maintenance-03d4198918f37d40.js",revision:"03d4198918f37d40"},{url:"/_next/static/chunks/pages/new-deployment-d62b31aa51c83e7d.js",revision:"d62b31aa51c83e7d"},{url:"/_next/static/chunks/pages/price-compare-42fcdb06ef32f8fd.js",revision:"42fcdb06ef32f8fd"},{url:"/_next/static/chunks/pages/privacy-policy-699c9d9fb984eb28.js",revision:"699c9d9fb984eb28"},{url:"/_next/static/chunks/pages/profile/%5Busername%5D-33dced36a498a422.js",revision:"33dced36a498a422"},{url:"/_next/static/chunks/pages/provider-graph/%5Bsnapshot%5D-71f3b46573e1d247.js",revision:"71f3b46573e1d247"},{url:"/_next/static/chunks/pages/providers-f46d10e3d3db881f.js",revision:"f46d10e3d3db881f"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D-4bb403cffc80277d.js",revision:"4bb403cffc80277d"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D/edit-6202455b3afe3399.js",revision:"6202455b3afe3399"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D/leases-9339eb33f4ed5878.js",revision:"9339eb33f4ed5878"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D/raw-187a3bcef0106ee4.js",revision:"187a3bcef0106ee4"},{url:"/_next/static/chunks/pages/sdl-builder-1fa70817019dff92.js",revision:"1fa70817019dff92"},{url:"/_next/static/chunks/pages/settings-a33c53bdd92c8c63.js",revision:"a33c53bdd92c8c63"},{url:"/_next/static/chunks/pages/settings/authorizations-3294f5feb8680e5c.js",revision:"3294f5feb8680e5c"},{url:"/_next/static/chunks/pages/template/%5Bid%5D-b340d594b9179568.js",revision:"b340d594b9179568"},{url:"/_next/static/chunks/pages/templates-e26fd6831e42abf6.js",revision:"e26fd6831e42abf6"},{url:"/_next/static/chunks/pages/templates/%5BtemplateId%5D-f9e3055302569508.js",revision:"f9e3055302569508"},{url:"/_next/static/chunks/pages/terms-of-service-6b011651835c0b04.js",revision:"6b011651835c0b04"},{url:"/_next/static/chunks/pages/transactions-d8020405d66da97d.js",revision:"d8020405d66da97d"},{url:"/_next/static/chunks/pages/transactions/%5Bhash%5D-f431f8c60fcd5ea7.js",revision:"f431f8c60fcd5ea7"},{url:"/_next/static/chunks/pages/user/settings-f56906f0117632aa.js",revision:"f56906f0117632aa"},{url:"/_next/static/chunks/pages/user/settings/address-book-a760a644f2abace6.js",revision:"a760a644f2abace6"},{url:"/_next/static/chunks/pages/user/settings/favorites-525b7109302336ff.js",revision:"525b7109302336ff"},{url:"/_next/static/chunks/pages/validators-92eac74a7fa28ceb.js",revision:"92eac74a7fa28ceb"},{url:"/_next/static/chunks/pages/validators/%5Baddress%5D-957ac8aa1757ffbd.js",revision:"957ac8aa1757ffbd"},{url:"/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js",revision:"837c0df77fd5009c9e46d446188ecfd0"},{url:"/_next/static/chunks/webpack-31830f6f3227d397.js",revision:"31830f6f3227d397"},{url:"/_next/static/css/60da0364ed65e94f.css",revision:"60da0364ed65e94f"},{url:"/_next/static/css/6bfa921e6cb2b44b.css",revision:"6bfa921e6cb2b44b"},{url:"/_next/static/css/92e074b97232c763.css",revision:"92e074b97232c763"},{url:"/_next/static/tb21YIrvWwmDqdPlJLTLl/_buildManifest.js",revision:"fb2b968b7c4a981b76c60751e8c66124"},{url:"/_next/static/tb21YIrvWwmDqdPlJLTLl/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/android-chrome-192x192.png",revision:"67aea0e4bc700134b81b51e635a95144"},{url:"/android-chrome-256x256.png",revision:"b0dc3017fadbf0f4c323636535f582b7"},{url:"/apple-touch-icon.png",revision:"97f107fd40c94f768de409ffb68e2e73"},{url:"/browserconfig.xml",revision:"e41ebb6b49206a59d8eafce8220ebeac"},{url:"/favicon-16x16.png",revision:"5b31d0a554060dec7c59e86af2c3b47d"},{url:"/favicon-32x32.png",revision:"794696d75ba46e490df7a68d1309cb20"},{url:"/favicon.ico",revision:"c6fc431554c8de94be347a8180e562aa"},{url:"/images/akash-logo-dark.png",revision:"b1623e407dad710a4c0c73461bbb8bb3"},{url:"/images/akash-logo-flat-dark.png",revision:"50b4ad6438e791047d97da0af65b96f5"},{url:"/images/akash-logo-flat-light.png",revision:"2befec2d17a2b6a32b1a0517ca1baf01"},{url:"/images/akash-logo-light.png",revision:"0ea30905c72eda674ad74c65d0c062bf"},{url:"/images/akash-logo.svg",revision:"4a5f3eaf31bf0f88ff3baec6281c8de3"},{url:"/images/chains/akash.png",revision:"d0b3f8ccaa3b0d18ef4039f86edf4436"},{url:"/images/chains/atom.png",revision:"6e4d88ad2c295e811fee29cc89edfcb1"},{url:"/images/chains/evmos.png",revision:"487a456e9091dec9ddf18892531401f8"},{url:"/images/chains/huahua.png",revision:"f0ba8427522833bba44962e87e982412"},{url:"/images/chains/juno.png",revision:"933b7d992dc67fd2f0d0f35e182b3361"},{url:"/images/chains/kuji.png",revision:"9c31e679007e5ae16fc28e067d907f79"},{url:"/images/chains/osmo.png",revision:"6940c69c28e5d85d99ba498fc7e95a26"},{url:"/images/chains/scrt.png",revision:"0dd98be17447cf7c47d27153f534ca60"},{url:"/images/chains/stars.png",revision:"56d0bd40e52f010c7267eb78c53138f2"},{url:"/images/chains/strd.png",revision:"eebdfb53ba0bc9bba88b0bede7a44f6d"},{url:"/images/cloudmos-logo-light.png",revision:"a7423327e4280225e176da92c6176c28"},{url:"/images/cloudmos-logo-small.jpg",revision:"4b339b83e7dc396894537b83d794726d"},{url:"/images/cloudmos-logo.png",revision:"56d87e0230a0ad5dd745efd486a33a58"},{url:"/images/docker.png",revision:"fde0ed6a2add0ffabfbc5a7749fdfff2"},{url:"/images/keplr-logo.png",revision:"50397e4902a33a6045c0f23dfe5cb1bd"},{url:"/images/powered-by-akash-dark.svg",revision:"3ea920f030ede7926a02c2dc17e332c4"},{url:"/images/powered-by-akash.svg",revision:"24b2566094fafded6c325246fe84c2a9"},{url:"/images/ubuntu.png",revision:"c631b8fae270a618c1fe1c9d43097189"},{url:"/images/wallet-connect-logo.png",revision:"8379e4d4e7267b47a0b5b89807a4d8f8"},{url:"/manifest.json",revision:"c2dfab0494ea8373287634bcf6da2233"},{url:"/mstile-150x150.png",revision:"4639e24da644e14af4e4daba3dd7af08"},{url:"/robots.txt",revision:"c2bb774b8071c957d2b835beaa28a58b"},{url:"/safari-pinned-tab.svg",revision:"a0fde4130c84e0d723dde3ece4a14fa8"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:a,state:c})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")}),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")}),new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>!(self.origin===e.origin)),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")})); +if(!self.define){let e,s={};const a=(a,c)=>(a=new URL(a+".js",c).href,s[a]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()})).then((()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(c,i)=>{const n=e||("document"in self?document.currentScript.src:"")||location.href;if(s[n])return;let t={};const r=e=>a(e,n),d={module:{uri:n},exports:t,require:r};s[n]=Promise.all(c.map((e=>d[e]||r(e)))).then((e=>(i(...e),t)))}}define(["./workbox-19663cdd"],(function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/XiLjPu57a-iqzFzEwM_-o/_buildManifest.js",revision:"ca3f3a83d4afb0c81d0132215a627d9b"},{url:"/_next/static/XiLjPu57a-iqzFzEwM_-o/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/1335-d73c269694583478.js",revision:"d73c269694583478"},{url:"/_next/static/chunks/1350-07f9659f28f558f8.js",revision:"07f9659f28f558f8"},{url:"/_next/static/chunks/1443-476ed025db3dd4b1.js",revision:"476ed025db3dd4b1"},{url:"/_next/static/chunks/1553-95b0c0d29fbb3445.js",revision:"95b0c0d29fbb3445"},{url:"/_next/static/chunks/1710-666ff1ead13f838d.js",revision:"666ff1ead13f838d"},{url:"/_next/static/chunks/2018-fc14dcb8e6f0c032.js",revision:"fc14dcb8e6f0c032"},{url:"/_next/static/chunks/2331.80fdf1c43b91f669.js",revision:"80fdf1c43b91f669"},{url:"/_next/static/chunks/4044-80c30f3a2b5e944f.js",revision:"80c30f3a2b5e944f"},{url:"/_next/static/chunks/4400-481f1f09599f62a2.js",revision:"481f1f09599f62a2"},{url:"/_next/static/chunks/449.0c771afcc1995d26.js",revision:"0c771afcc1995d26"},{url:"/_next/static/chunks/4729-899a5d4ff8ee3aca.js",revision:"899a5d4ff8ee3aca"},{url:"/_next/static/chunks/4769-acce898f5483d147.js",revision:"acce898f5483d147"},{url:"/_next/static/chunks/4848-98d5115b09d0bc29.js",revision:"98d5115b09d0bc29"},{url:"/_next/static/chunks/5054-3be601e5ff47a6b1.js",revision:"3be601e5ff47a6b1"},{url:"/_next/static/chunks/5105-27d232f986a447c2.js",revision:"27d232f986a447c2"},{url:"/_next/static/chunks/5632.889b47838578051c.js",revision:"889b47838578051c"},{url:"/_next/static/chunks/5644-8b5cbb139a37740c.js",revision:"8b5cbb139a37740c"},{url:"/_next/static/chunks/609-deabd5ec9a55d407.js",revision:"deabd5ec9a55d407"},{url:"/_next/static/chunks/6183-cb7bbe9f563fd4cb.js",revision:"cb7bbe9f563fd4cb"},{url:"/_next/static/chunks/652.94ff65c899230787.js",revision:"94ff65c899230787"},{url:"/_next/static/chunks/659-5c9173913cac5403.js",revision:"5c9173913cac5403"},{url:"/_next/static/chunks/6698-4f9830af81c66dbc.js",revision:"4f9830af81c66dbc"},{url:"/_next/static/chunks/678-08876ec4989a640b.js",revision:"08876ec4989a640b"},{url:"/_next/static/chunks/6782.fee4f7987d5f0efa.js",revision:"fee4f7987d5f0efa"},{url:"/_next/static/chunks/6886-fa7338eaa9ba83dd.js",revision:"fa7338eaa9ba83dd"},{url:"/_next/static/chunks/69fc0a3a-4b10f93d935c96d6.js",revision:"4b10f93d935c96d6"},{url:"/_next/static/chunks/7047-9a583fff28dfc3e1.js",revision:"9a583fff28dfc3e1"},{url:"/_next/static/chunks/7449-2549ca7b57bd6471.js",revision:"2549ca7b57bd6471"},{url:"/_next/static/chunks/8329.3e3b26692eec5f3b.js",revision:"3e3b26692eec5f3b"},{url:"/_next/static/chunks/8364-525ff7c5ef9bd630.js",revision:"525ff7c5ef9bd630"},{url:"/_next/static/chunks/8446-d0c2d9e64c060c9b.js",revision:"d0c2d9e64c060c9b"},{url:"/_next/static/chunks/8487-d3900a8beded1bb1.js",revision:"d3900a8beded1bb1"},{url:"/_next/static/chunks/8606-41f13b88a2de459f.js",revision:"41f13b88a2de459f"},{url:"/_next/static/chunks/8705-d2c5e4e46530ef3a.js",revision:"d2c5e4e46530ef3a"},{url:"/_next/static/chunks/9130-9aca6afb71fb70c8.js",revision:"9aca6afb71fb70c8"},{url:"/_next/static/chunks/9179-6a3b460e53bb2c54.js",revision:"6a3b460e53bb2c54"},{url:"/_next/static/chunks/9188-cbbec32407303a76.js",revision:"cbbec32407303a76"},{url:"/_next/static/chunks/9196-9b4def108a2c6ae9.js",revision:"9b4def108a2c6ae9"},{url:"/_next/static/chunks/9266-e0eca9eae0c5af3a.js",revision:"e0eca9eae0c5af3a"},{url:"/_next/static/chunks/942-dc48eacaaac6db13.js",revision:"dc48eacaaac6db13"},{url:"/_next/static/chunks/9604-189ed1e3ef3ddfd1.js",revision:"189ed1e3ef3ddfd1"},{url:"/_next/static/chunks/9912-3b8166bd0ea324e7.js",revision:"3b8166bd0ea324e7"},{url:"/_next/static/chunks/9f96d65d-7b812644c8c0f1f1.js",revision:"7b812644c8c0f1f1"},{url:"/_next/static/chunks/ed150ef9.ec0fa51ac82b6bd3.js",revision:"ec0fa51ac82b6bd3"},{url:"/_next/static/chunks/framework-4ed89e9640adfb9e.js",revision:"4ed89e9640adfb9e"},{url:"/_next/static/chunks/main-75a41b17c9b01e3f.js",revision:"75a41b17c9b01e3f"},{url:"/_next/static/chunks/pages/404-1339d0dfd9798111.js",revision:"1339d0dfd9798111"},{url:"/_next/static/chunks/pages/500-c1d927dfeeb50011.js",revision:"c1d927dfeeb50011"},{url:"/_next/static/chunks/pages/_error-d7faa34a8a9ea44c.js",revision:"d7faa34a8a9ea44c"},{url:"/_next/static/chunks/pages/addresses/%5Baddress%5D-782380a6d79f47ba.js",revision:"782380a6d79f47ba"},{url:"/_next/static/chunks/pages/addresses/%5Baddress%5D/deployments-2d414781b7f51c42.js",revision:"2d414781b7f51c42"},{url:"/_next/static/chunks/pages/addresses/%5Baddress%5D/transactions-179682275b0b7d3c.js",revision:"179682275b0b7d3c"},{url:"/_next/static/chunks/pages/analytics-3771c7da67c4558b.js",revision:"3771c7da67c4558b"},{url:"/_next/static/chunks/pages/blocks-a27f184f99cb6fae.js",revision:"a27f184f99cb6fae"},{url:"/_next/static/chunks/pages/blocks/%5Bheight%5D-bad2b0056b3fa8a3.js",revision:"bad2b0056b3fa8a3"},{url:"/_next/static/chunks/pages/contact-e6b0427ab8750e84.js",revision:"e6b0427ab8750e84"},{url:"/_next/static/chunks/pages/deployment/%5Bowner%5D/%5Bdseq%5D-8fe086eab5a19d70.js",revision:"8fe086eab5a19d70"},{url:"/_next/static/chunks/pages/deployments-f8f3e02e1b1b4807.js",revision:"f8f3e02e1b1b4807"},{url:"/_next/static/chunks/pages/deployments/%5Bdseq%5D-d4778574ab8561e7.js",revision:"d4778574ab8561e7"},{url:"/_next/static/chunks/pages/get-started-ae47131cc002379c.js",revision:"ae47131cc002379c"},{url:"/_next/static/chunks/pages/get-started/wallet-deeb4d38a71b467c.js",revision:"deeb4d38a71b467c"},{url:"/_next/static/chunks/pages/graph/%5Bsnapshot%5D-14ae45aacfcf7eeb.js",revision:"14ae45aacfcf7eeb"},{url:"/_next/static/chunks/pages/index-1abf24e194465158.js",revision:"1abf24e194465158"},{url:"/_next/static/chunks/pages/maintenance-03d4198918f37d40.js",revision:"03d4198918f37d40"},{url:"/_next/static/chunks/pages/new-deployment-07d4de50764810c2.js",revision:"07d4de50764810c2"},{url:"/_next/static/chunks/pages/price-compare-fbea83d7fe597965.js",revision:"fbea83d7fe597965"},{url:"/_next/static/chunks/pages/privacy-policy-c51f80ec2363dd44.js",revision:"c51f80ec2363dd44"},{url:"/_next/static/chunks/pages/profile/%5Busername%5D-0d83b372dbdafdf8.js",revision:"0d83b372dbdafdf8"},{url:"/_next/static/chunks/pages/provider-graph/%5Bsnapshot%5D-42d9f4e01c902280.js",revision:"42d9f4e01c902280"},{url:"/_next/static/chunks/pages/providers-13393b7d74bf7a6b.js",revision:"13393b7d74bf7a6b"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D-cf6071b5db355496.js",revision:"cf6071b5db355496"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D/edit-36a2680ded3fa13f.js",revision:"36a2680ded3fa13f"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D/leases-b6f2e28a10c52c09.js",revision:"b6f2e28a10c52c09"},{url:"/_next/static/chunks/pages/providers/%5Bowner%5D/raw-2502a6f3c9ed3ddd.js",revision:"2502a6f3c9ed3ddd"},{url:"/_next/static/chunks/pages/sdl-builder-7f8d9e6185c61875.js",revision:"7f8d9e6185c61875"},{url:"/_next/static/chunks/pages/settings-662f3e217d9baa20.js",revision:"662f3e217d9baa20"},{url:"/_next/static/chunks/pages/settings/authorizations-d922645679beb27f.js",revision:"d922645679beb27f"},{url:"/_next/static/chunks/pages/template/%5Bid%5D-3438b96b94bcf5eb.js",revision:"3438b96b94bcf5eb"},{url:"/_next/static/chunks/pages/templates-cfcbadde168aadff.js",revision:"cfcbadde168aadff"},{url:"/_next/static/chunks/pages/templates/%5BtemplateId%5D-ff490fadb2c3f6e4.js",revision:"ff490fadb2c3f6e4"},{url:"/_next/static/chunks/pages/terms-of-service-8092af12806d9644.js",revision:"8092af12806d9644"},{url:"/_next/static/chunks/pages/transactions-08d6df91026b2cc7.js",revision:"08d6df91026b2cc7"},{url:"/_next/static/chunks/pages/transactions/%5Bhash%5D-945f01f1c82f9be2.js",revision:"945f01f1c82f9be2"},{url:"/_next/static/chunks/pages/user/settings-6c8a3b489adcf89c.js",revision:"6c8a3b489adcf89c"},{url:"/_next/static/chunks/pages/user/settings/address-book-f47ba9c07692b9d4.js",revision:"f47ba9c07692b9d4"},{url:"/_next/static/chunks/pages/user/settings/favorites-ac885b7abd44d927.js",revision:"ac885b7abd44d927"},{url:"/_next/static/chunks/pages/validators-4d370a45c03a5aeb.js",revision:"4d370a45c03a5aeb"},{url:"/_next/static/chunks/pages/validators/%5Baddress%5D-ec04e9e6415e1e23.js",revision:"ec04e9e6415e1e23"},{url:"/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js",revision:"837c0df77fd5009c9e46d446188ecfd0"},{url:"/_next/static/chunks/webpack-7c00bef40e5577ce.js",revision:"7c00bef40e5577ce"},{url:"/_next/static/css/60da0364ed65e94f.css",revision:"60da0364ed65e94f"},{url:"/_next/static/css/6bfa921e6cb2b44b.css",revision:"6bfa921e6cb2b44b"},{url:"/_next/static/css/92e074b97232c763.css",revision:"92e074b97232c763"},{url:"/android-chrome-192x192.png",revision:"67aea0e4bc700134b81b51e635a95144"},{url:"/android-chrome-256x256.png",revision:"b0dc3017fadbf0f4c323636535f582b7"},{url:"/apple-touch-icon.png",revision:"97f107fd40c94f768de409ffb68e2e73"},{url:"/browserconfig.xml",revision:"e41ebb6b49206a59d8eafce8220ebeac"},{url:"/favicon-16x16.png",revision:"5b31d0a554060dec7c59e86af2c3b47d"},{url:"/favicon-32x32.png",revision:"794696d75ba46e490df7a68d1309cb20"},{url:"/favicon.ico",revision:"c6fc431554c8de94be347a8180e562aa"},{url:"/images/akash-logo-dark.png",revision:"b1623e407dad710a4c0c73461bbb8bb3"},{url:"/images/akash-logo-flat-dark.png",revision:"50b4ad6438e791047d97da0af65b96f5"},{url:"/images/akash-logo-flat-light.png",revision:"2befec2d17a2b6a32b1a0517ca1baf01"},{url:"/images/akash-logo-light.png",revision:"0ea30905c72eda674ad74c65d0c062bf"},{url:"/images/akash-logo.svg",revision:"4a5f3eaf31bf0f88ff3baec6281c8de3"},{url:"/images/chains/akash.png",revision:"d0b3f8ccaa3b0d18ef4039f86edf4436"},{url:"/images/chains/atom.png",revision:"6e4d88ad2c295e811fee29cc89edfcb1"},{url:"/images/chains/evmos.png",revision:"487a456e9091dec9ddf18892531401f8"},{url:"/images/chains/huahua.png",revision:"f0ba8427522833bba44962e87e982412"},{url:"/images/chains/juno.png",revision:"933b7d992dc67fd2f0d0f35e182b3361"},{url:"/images/chains/kuji.png",revision:"9c31e679007e5ae16fc28e067d907f79"},{url:"/images/chains/osmo.png",revision:"6940c69c28e5d85d99ba498fc7e95a26"},{url:"/images/chains/scrt.png",revision:"0dd98be17447cf7c47d27153f534ca60"},{url:"/images/chains/stars.png",revision:"56d0bd40e52f010c7267eb78c53138f2"},{url:"/images/chains/strd.png",revision:"eebdfb53ba0bc9bba88b0bede7a44f6d"},{url:"/images/cloudmos-logo-light.png",revision:"a7423327e4280225e176da92c6176c28"},{url:"/images/cloudmos-logo-small.jpg",revision:"4b339b83e7dc396894537b83d794726d"},{url:"/images/cloudmos-logo.png",revision:"56d87e0230a0ad5dd745efd486a33a58"},{url:"/images/docker.png",revision:"fde0ed6a2add0ffabfbc5a7749fdfff2"},{url:"/images/keplr-logo.png",revision:"50397e4902a33a6045c0f23dfe5cb1bd"},{url:"/images/powered-by-akash-dark.svg",revision:"3ea920f030ede7926a02c2dc17e332c4"},{url:"/images/powered-by-akash.svg",revision:"24b2566094fafded6c325246fe84c2a9"},{url:"/images/ubuntu.png",revision:"c631b8fae270a618c1fe1c9d43097189"},{url:"/images/wallet-connect-logo.png",revision:"8379e4d4e7267b47a0b5b89807a4d8f8"},{url:"/manifest.json",revision:"c2dfab0494ea8373287634bcf6da2233"},{url:"/mstile-150x150.png",revision:"4639e24da644e14af4e4daba3dd7af08"},{url:"/robots.txt",revision:"c2bb774b8071c957d2b835beaa28a58b"},{url:"/safari-pinned-tab.svg",revision:"a0fde4130c84e0d723dde3ece4a14fa8"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:a,state:c})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")}),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")}),new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>!(self.origin===e.origin)),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")})); diff --git a/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx b/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx index ce67dd561a..b11b0dd6a3 100644 --- a/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx +++ b/deploy-web/src/components/deploymentDetail/DeploymentDetailTopBar.tsx @@ -28,7 +28,7 @@ const useStyles = makeStyles()(theme => ({ marginLeft: ".5rem", display: "flex", alignItems: "center", - "& .MuiButtonBase-root:first-child": { + "& .MuiButtonBase-root:first-of-type": { marginLeft: 0 } }, @@ -130,7 +130,7 @@ export function DeploymentDetailTopBar({ address, loadDeploymentDetail, removeLe sx={{ display: "flex", alignItems: "center", - padding: "0 .5rem .5rem", + padding: "0 .5rem .5rem" }} > diff --git a/deploy-web/src/components/deploymentDetail/LeaseRow.tsx b/deploy-web/src/components/deploymentDetail/LeaseRow.tsx index 06c5820311..aa5743b3e6 100644 --- a/deploy-web/src/components/deploymentDetail/LeaseRow.tsx +++ b/deploy-web/src/components/deploymentDetail/LeaseRow.tsx @@ -37,7 +37,7 @@ import { LinkTo } from "../shared/LinkTo"; import { SpecDetail } from "../shared/SpecDetail"; import { PricePerMonth } from "../shared/PricePerMonth"; import { PriceEstimateTooltip } from "../shared/PriceEstimateTooltip"; -import { getAvgCostPerMonth, uaktToAKT } from "@src/utils/priceUtils"; +import { uaktToAKT } from "@src/utils/priceUtils"; import Link from "next/link"; import { UrlService } from "@src/utils/urlUtils"; import { FavoriteButton } from "../shared/FavoriteButton"; @@ -187,7 +187,7 @@ export const LeaseRow = React.forwardRef(({ lease, setActi setIsSendingManifest(true); try { const doc = yaml.load(deploymentManifest); - const manifest = deploymentData.Manifest(doc); + const manifest = deploymentData.getManifest(doc, true); await sendManifestToProvider(providerInfo, manifest, dseq, localCert); diff --git a/deploy-web/src/components/deploymentDetail/ManifestUpdate.tsx b/deploy-web/src/components/deploymentDetail/ManifestUpdate.tsx index b43c2e7e84..b1f2a50c7b 100644 --- a/deploy-web/src/components/deploymentDetail/ManifestUpdate.tsx +++ b/deploy-web/src/components/deploymentDetail/ManifestUpdate.tsx @@ -11,9 +11,8 @@ import { deploymentData } from "@src/utils/deploymentData"; import { sendManifestToProvider } from "@src/utils/deploymentUtils"; import { ManifestErrorSnackbar } from "../shared/ManifestErrorSnackbar"; import { Snackbar } from "../shared/Snackbar"; -import { Alert, Box, Button, CircularProgress, Tooltip, Typography } from "@mui/material"; +import { Alert, Box, Button, CircularProgress, Typography } from "@mui/material"; import { LinkTo } from "../shared/LinkTo"; -import { cx } from "@emotion/css"; import { LinearLoadingSkeleton } from "../shared/LinearLoadingSkeleton"; import ViewPanel from "../shared/ViewPanel"; import { DynamicMonacoEditor } from "../shared/DynamicMonacoEditor"; @@ -52,7 +51,7 @@ export function ManifestUpdate({ deployment, leases, closeManifestEditor }) { setEditedManifest(localDeploymentData?.manifest); const yamlVersion = yaml.load(localDeploymentData?.manifest); - const version = await deploymentData.getManifestVersion(yamlVersion); + const version = await deploymentData.getManifestVersion(yamlVersion, true); setDeploymentVersion(version); } else { @@ -129,7 +128,7 @@ export function ManifestUpdate({ deployment, leases, closeManifestEditor }) { const doc = yaml.load(editedManifest); const dd = await deploymentData.NewDeploymentData(settings.apiEndpoint, doc, parseInt(deployment.dseq), address); // TODO Flags - const mani = deploymentData.Manifest(doc); + const mani = deploymentData.getManifest(doc, true); // If it's actual update, send a transaction, else just send the manifest if (dd.version !== deployment.version) { diff --git a/deploy-web/src/components/newDeploymentWizard/CreateLease.tsx b/deploy-web/src/components/newDeploymentWizard/CreateLease.tsx index 2d38dd8d64..7039ba31ca 100644 --- a/deploy-web/src/components/newDeploymentWizard/CreateLease.tsx +++ b/deploy-web/src/components/newDeploymentWizard/CreateLease.tsx @@ -195,11 +195,6 @@ export const CreateLease: React.FunctionComponent = ({ dseq }) => { try { const messages = bidKeys.map(gseq => selectedBids[gseq]).map(bid => TransactionMessageData.getCreateLeaseMsg(bid)); - // if (isProd) { - // const feeMessage = TransactionMessageData.getSendTokensMsg(address, treasuryAddress, cloudmosFee.fee); - // messages.push(feeMessage as any); - // } - const response = await signAndBroadcastTx([...messages]); if (!response) throw new Error("Rejected transaction"); @@ -227,7 +222,7 @@ export const CreateLease: React.FunctionComponent = ({ dseq }) => { try { const yamlJson = yaml.load(localDeploymentData.manifest); - const mani = deploymentData.Manifest(yamlJson); + const mani = deploymentData.getManifest(yamlJson, true); for (let i = 0; i < bidKeys.length; i++) { const currentBid = selectedBids[bidKeys[i]]; @@ -373,7 +368,7 @@ export const CreateLease: React.FunctionComponent = ({ dseq }) => { {(isLoadingBids || bids.length === 0) && !maxRequestsReached && !isSendingManifest && ( - + Waiting for bids... diff --git a/deploy-web/src/components/shared/Markdown.tsx b/deploy-web/src/components/shared/Markdown.tsx index 79860f864f..aada3301fa 100644 --- a/deploy-web/src/components/shared/Markdown.tsx +++ b/deploy-web/src/components/shared/Markdown.tsx @@ -1,5 +1,5 @@ import ReactMarkdown from "react-markdown"; -import { darken, lighten, useTheme } from "@mui/material"; +import { lighten, useTheme } from "@mui/material"; import { makeStyles } from "tss-react/mui"; import remarkGfm from "remark-gfm"; @@ -18,9 +18,6 @@ const useStyles = makeStyles()(theme => ({ ".codeStyle, pre, code, code span": { // Your SyntaxHighlighter override styles here }, - "p:first-child": { - margin: 0 - }, code: { // Your general code styles here }, diff --git a/deploy-web/src/components/shared/Popup.tsx b/deploy-web/src/components/shared/Popup.tsx index 5c099ba675..86909f725e 100644 --- a/deploy-web/src/components/shared/Popup.tsx +++ b/deploy-web/src/components/shared/Popup.tsx @@ -277,31 +277,31 @@ export const Popup: React.FC = props => { case "custom": { const leftButtons = props.actions ?.filter(x => x.side === "left") - .map((_, idx) => ( - )); const rightButtons = props.actions ?.filter(x => x.side === "right") - .map((_, idx) => ( - )); diff --git a/deploy-web/src/context/KeplrWalletProvider/KeplrWalletProvider.tsx b/deploy-web/src/context/KeplrWalletProvider/KeplrWalletProvider.tsx index 9bc929214d..3ca05e7d1c 100644 --- a/deploy-web/src/context/KeplrWalletProvider/KeplrWalletProvider.tsx +++ b/deploy-web/src/context/KeplrWalletProvider/KeplrWalletProvider.tsx @@ -9,7 +9,7 @@ import { Snackbar } from "@src/components/shared/Snackbar"; import { customRegistry } from "@src/utils/customRegistry"; import { TransactionModal } from "@src/components/layout/TransactionModal"; import { OpenInNew } from "@mui/icons-material"; -import { Box, CircularProgress, Typography, useTheme } from "@mui/material"; +import { useTheme } from "@mui/material"; import { event } from "nextjs-google-analytics"; import { AnalyticsEvents } from "@src/utils/analytics"; import { useRouter } from "next/router"; diff --git a/deploy-web/src/pages/providers/[owner]/index.tsx b/deploy-web/src/pages/providers/[owner]/index.tsx index 0a0f3c1400..f368aee123 100644 --- a/deploy-web/src/pages/providers/[owner]/index.tsx +++ b/deploy-web/src/pages/providers/[owner]/index.tsx @@ -56,17 +56,22 @@ const ProviderDetailPage: React.FunctionComponent = ({ owner }) => { enabled: false, retry: false, onSuccess: _providerStatus => { - setProvider(provider => (provider ? { ...provider, ...providerStatus } : providerStatus)); + setProvider(provider => (provider ? { ...provider, ..._providerStatus } : _providerStatus)); } }); const isLoading = isLoadingProviders || isLoadingStatus || isLoadingLeases || isLoadingSchema; useEffect(() => { - if (provider) { - refresh(); - } + getProviders(); + getLeases(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [provider]); + }, []); + + useEffect(() => { + if (provider && !providerStatus) { + getProviderStatus(); + } + }, [provider, providerStatus]); useEffect(() => { const providerFromList = providers?.find(d => d.owner === owner); @@ -98,7 +103,7 @@ const ProviderDetailPage: React.FunctionComponent = ({ owner }) => { )} - {provider && !provider.isActive && ( + {provider && !provider.isActive && !isLoading && ( = ({}) => { - {shownTemplates.map(template => ( - + {shownTemplates.map((template, id) => ( + ))} diff --git a/deploy-web/src/utils/TransactionMessageData.ts b/deploy-web/src/utils/TransactionMessageData.ts index e343d1e013..e371bdeb71 100644 --- a/deploy-web/src/utils/TransactionMessageData.ts +++ b/deploy-web/src/utils/TransactionMessageData.ts @@ -1,6 +1,4 @@ -import { protoTypes } from "./protoTypes"; import { networkVersion } from "./constants"; -import { Attribute, ProviderInfo } from "./proto/akash/v1beta3"; export function setMessageTypes() { TransactionMessageData.Types.MSG_CLOSE_DEPLOYMENT = `/akash.deployment.${networkVersion}.MsgCloseDeployment`; @@ -45,10 +43,6 @@ export class TransactionMessageData { } }; - const err = protoTypes.MsgRevokeCertificate.verify(message.value); - - if (err) throw err; - return message; } @@ -62,10 +56,6 @@ export class TransactionMessageData { } }; - const err = protoTypes.MsgCreateCertificate.verify(message.value); - - if (err) throw err; - return message; } @@ -73,7 +63,7 @@ export class TransactionMessageData { const message = { typeUrl: TransactionMessageData.Types.MSG_CREATE_LEASE, value: { - bid_id: { + bidId: { owner: bid.owner, dseq: parseInt(bid.dseq), gseq: bid.gseq, @@ -83,10 +73,6 @@ export class TransactionMessageData { } }; - const err = protoTypes.MsgCreateLease.verify(message.value); - - if (err) throw err; - return message; } @@ -102,11 +88,6 @@ export class TransactionMessageData { } }; - // TODO - //const err = protoTypes.MsgCreateDeployment.verify(txData.value); - let err = null; - if (err) throw err; - return message; } @@ -119,11 +100,6 @@ export class TransactionMessageData { } }; - // const err = protoTypes.MsgUpdateDeployment.verify(txData.value); - - let err = null; - if (err) throw err; - return message; } @@ -143,10 +119,6 @@ export class TransactionMessageData { } }; - const err = protoTypes.MsgDepositDeployment.verify(message.value); - - if (err) throw err; - return message; } @@ -161,10 +133,6 @@ export class TransactionMessageData { } }; - const err = protoTypes.MsgCloseDeployment.verify(message.value); - - if (err) throw err; - return message; } diff --git a/deploy-web/src/utils/alerts/data.ts b/deploy-web/src/utils/alerts/data.ts deleted file mode 100644 index 2e011efe60..0000000000 --- a/deploy-web/src/utils/alerts/data.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const cooldowns = [ - { id: "1", title: "5 Mins" }, - { id: "2", title: "15 Mins" }, - { id: "3", title: "1 Hour" } -]; - -export const channels = [ - { id: "email", title: "Email" }, - { id: "telegram", title: "Telegram", isComingSoon: true }, - { id: "discord", title: "Discord", isComingSoon: true }, - { id: "sms", title: "Sms", isComingSoon: true }, - { id: "browser", title: "Browser", isComingSoon: true }, - { id: "webhook", title: "Webhook", isComingSoon: true }, - { id: "zapier", title: "Zapier", isComingSoon: true } -]; diff --git a/deploy-web/src/utils/alerts/index.ts b/deploy-web/src/utils/alerts/index.ts deleted file mode 100644 index ff7ba272f9..0000000000 --- a/deploy-web/src/utils/alerts/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./data"; diff --git a/deploy-web/src/utils/customRegistry.ts b/deploy-web/src/utils/customRegistry.ts index a98b1f1b5e..60c22f528d 100644 --- a/deploy-web/src/utils/customRegistry.ts +++ b/deploy-web/src/utils/customRegistry.ts @@ -1,7 +1,7 @@ import { Registry } from "@cosmjs/proto-signing"; import { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx"; import { MsgRevoke } from "cosmjs-types/cosmos/authz/v1beta1/tx"; -import { protoTypes } from "./protoTypes"; +import { protoTypes } from "./proto"; import { TransactionMessageData } from "./TransactionMessageData"; export let customRegistry: Registry; diff --git a/deploy-web/src/utils/deploymentData/helpers.ts b/deploy-web/src/utils/deploymentData/helpers.ts index bc980403af..fa8e678f88 100644 --- a/deploy-web/src/utils/deploymentData/helpers.ts +++ b/deploy-web/src/utils/deploymentData/helpers.ts @@ -1,5 +1,6 @@ import axios from "axios"; -const stableStringify = require("json-stable-stringify"); +import { SDL } from '@akashnetwork/akashjs/build/sdl'; +import { v2Sdl } from '@akashnetwork/akashjs/build/sdl/types'; export class CustomValidationError extends Error { constructor(message) { @@ -29,75 +30,6 @@ const specSuffixes = { Eb: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 }; -// Replicate the HTML escape logic from https://pkg.go.dev/encoding/json#Marshal -function escapeHtml(unsafe) { - return unsafe.replace(//g, "\\u003e").replace(/&/g, "\\u0026"); -} - -// https://github.com/ovrclk/akash/blob/04e7a7667dd94b5a15fa039e4f7df5c9ad93be4f/sdl/sdl.go#L120 -export async function ManifestVersion(manifest) { - var enc = new TextEncoder(); - let jsonStr = JSON.stringify(manifest); - - jsonStr = jsonStr.replaceAll('"quantity":{"val', '"size":{"val'); - jsonStr = jsonStr.replaceAll('"mount":', '"readOnlyTmp":'); - jsonStr = jsonStr.replaceAll('"readOnly":', '"mount":'); - jsonStr = jsonStr.replaceAll('"readOnlyTmp":', '"readOnly":'); - - // console.log(jsonStr); - // console.log(SortJSON(jsonStr)); - - let sortedBytes = enc.encode(SortJSON(jsonStr)); - - // console.log(sortedBytes); - - let sum = await crypto.subtle.digest("SHA-256", sortedBytes); - - let base64 = _arrayBufferToBase64(sum); - - return base64; -} - -// https://github.com/cosmos/cosmos-sdk/blob/9fd866e3820b3510010ae172b682d71594cd8c14/types/utils.go#L29 -export function SortJSON(jsonStr) { - return escapeHtml(stableStringify(JSON.parse(jsonStr))); -} - -function _arrayBufferToBase64(buffer) { - var binary = ""; - var bytes = new Uint8Array(buffer); - var len = bytes.byteLength; - for (var i = 0; i < len; i++) { - binary += String.fromCharCode(bytes[i]); - } - return window.btoa(binary); -} - -export function ParseServiceProtocol(input) { - let result; - - // This is not a case sensitive parse, so make all input - // uppercase - if (input) { - input = input.toUpperCase(); - } - - switch (input) { - case "TCP": - case "": - case undefined: // The empty string (no input) implies TCP - result = "TCP"; - break; - case "UDP": - result = "UDP"; - break; - default: - throw new CustomValidationError("Unsupported Service Protocol " + input); - } - - return result; -} - export async function getCurrentHeight(apiEndpoint) { const response = await axios.get(`${apiEndpoint}/blocks/latest`); const data = response.data; @@ -123,14 +55,32 @@ export function parseSizeStr(str) { } } -export function shouldBeIngress(expose) { - return expose.proto === "TCP" && expose.global && 80 === exposeExternalPort(expose); +type NetworkType = 'beta2' | 'beta3'; + +function isString(value: unknown): value is string { + return typeof value === 'object' && value !== null && value.constructor === String; +} + +export function getSdl(yamlJson: string | v2Sdl, networkType: NetworkType) { + return isString(yamlJson) ? SDL.fromString(yamlJson, networkType) : new SDL(yamlJson, networkType); } -function exposeExternalPort(expose) { - if (expose.externalPort === 0) { - return expose.port; - } +export function DeploymentGroups(yamlJson: string | v2Sdl, networkType: NetworkType) { + const sdl = getSdl(yamlJson, networkType); + return sdl.groups(); +} + +export function Manifest(yamlJson: string | v2Sdl, networkType: NetworkType, asString = false) { + const sdl = getSdl(yamlJson, networkType); + return sdl.manifest(asString); +} + +export async function ManifestVersion(yamlJson: string | v2Sdl, networkType: NetworkType) { + const sdl = getSdl(yamlJson, networkType); + return sdl.manifestVersion(); +} - return expose.externalPort; +export function ManifestYaml(sdlConfig: v2Sdl, networkType: NetworkType) { + const sdl = getSdl(sdlConfig, networkType); + return sdl.manifestSortedJSON(); } diff --git a/deploy-web/src/utils/deploymentData/v1beta2.ts b/deploy-web/src/utils/deploymentData/v1beta2.ts index 8e72144186..4715aa7577 100644 --- a/deploy-web/src/utils/deploymentData/v1beta2.ts +++ b/deploy-web/src/utils/deploymentData/v1beta2.ts @@ -1,230 +1,14 @@ -import { CustomValidationError, ManifestVersion, ParseServiceProtocol, getCurrentHeight, shouldBeIngress, parseSizeStr } from "./helpers"; +import { CustomValidationError, ManifestVersion, getCurrentHeight, Manifest, DeploymentGroups, getSdl, parseSizeStr } from "./helpers"; import { defaultInitialDeposit } from "../constants"; import { stringToBoolean } from "../stringUtils"; +const path = require("path"); const endpointNameValidationRegex = /^[a-z]+[-_\da-z]+$/; const endpointKindIP = "ip"; -const path = require("path"); - -const defaultHTTPOptions = { - MaxBodySize: 1048576, - ReadTimeout: 60000, - SendTimeout: 60000, - NextTries: 3, - NextTimeout: 0, - NextCases: ["error", "timeout"] -}; - -// TODO Enum -const Endpoint_SHARED_HTTP = 0; -const Endpoint_RANDOM_PORT = 1; -const Endpoint_LEASED_IP = 2; - -// https://github.com/ovrclk/akash/blob/98fd6bd9c25014fb819f85a06168a3335dc9633f/x/deployment/types/v1beta2/validation_config.go -// const validationConfig = { -// maxUnitCPU: 256 * 1000, // 256 CPUs -// maxUnitMemory: 512 * unit.Gi, // 512 Gi -// maxUnitStorage: 32 * unit.Ti, // 32 Ti -// maxUnitCount: 50, -// maxUnitPrice: 10000000, // 10akt - -// minUnitCPU: 10, -// minUnitMemory: specSuffixes.Mi, -// minUnitStorage: 5 * specSuffixes.Mi, -// minUnitCount: 1, - -// maxGroupCount: 20, -// maxGroupUnits: 20, - -// maxGroupCPU: 512 * 1000, -// maxGroupMemory: 1024 * specSuffixes.Gi, -// maxGroupStorage: 32 * specSuffixes.Ti -// }; - -function getHttpOptions(options = {}) { - return { - MaxBodySize: options["max_body_size"] || defaultHTTPOptions.MaxBodySize, - ReadTimeout: options["read_timeout"] || defaultHTTPOptions.ReadTimeout, - SendTimeout: options["send_timeout"] || defaultHTTPOptions.SendTimeout, - NextTries: options["next_tries"] || defaultHTTPOptions.NextTries, - NextTimeout: options["next_timeout"] || defaultHTTPOptions.NextTimeout, - NextCases: options["next_cases"] || defaultHTTPOptions.NextCases - }; -} - -// Port of: func (sdl *v2ComputeResources) toResourceUnits() types.ResourceUnits -export function toResourceUnits(computeResources) { - if (!computeResources) return {}; - - let units = {} as any; - if (computeResources.cpu) { - const cpu = - typeof computeResources.cpu.units === "string" && computeResources.cpu.units.endsWith("m") - ? computeResources.cpu.units.slice(0, -1) - : (computeResources.cpu.units * 1000).toString(); - - units.cpu = { - units: { val: cpu }, - attributes: - computeResources.cpu.attributes && - Object.keys(computeResources.cpu.attributes) - .sort() - .map(key => ({ - key: key, - value: computeResources.cpu.attributes[key].toString() - })) - }; - } - if (computeResources.memory) { - units.memory = { - quantity: { val: parseSizeStr(computeResources.memory.size) }, - attributes: - computeResources.memory.attributes && - Object.keys(computeResources.memory.attributes) - .sort() - .map(key => ({ - key: key, - value: computeResources.memory.attributes[key].toString() - })) - }; - } - if (computeResources.storage) { - const storages = computeResources.storage.map ? computeResources.storage : [computeResources.storage]; - units.storage = - storages.map(storage => ({ - name: storage.name || "default", - quantity: { val: parseSizeStr(storage.size) }, - attributes: - storage.attributes && - Object.keys(storage.attributes) - .sort() - .map(key => ({ - key: key, - value: storage.attributes[key].toString() - })) - })) || []; - } - - units.endpoints = null; - - return units; -} - -function computeEndpointSequenceNumbers(yamlJson) { - let ipEndpointNames = {}; - - Object.keys(yamlJson.services).forEach(svcName => { - const svc = yamlJson.services[svcName]; - - svc?.expose?.forEach(expose => { - expose?.to - ?.filter(to => to.global && to.ip?.length > 0) - .map(to => to.ip) - .sort() - .forEach((ip, i) => { - ipEndpointNames[ip] = i + 1; - }); - }); - }); - - return ipEndpointNames; -} - -function DeploymentGroups(yamlJson) { - let groups = {}; - const ipEndpointNames = computeEndpointSequenceNumbers(yamlJson); - - Object.keys(yamlJson.services).forEach(svcName => { - const svc = yamlJson.services[svcName]; - const depl = yamlJson.deployment[svcName]; - - Object.keys(depl).forEach(placementName => { - const svcdepl = depl[placementName]; - const compute = yamlJson.profiles.compute[svcdepl.profile]; - const infra = yamlJson.profiles.placement[placementName]; - const price = infra.pricing[svcdepl.profile]; - - price.amount = price.amount.toString(); // Interpreted as number otherwise - - let group = groups[placementName]; - - if (!group) { - group = { - name: placementName, - requirements: { - attributes: infra.attributes ? Object.keys(infra.attributes).map(key => ({ key: key, value: infra.attributes[key]?.toString() })) : [], - signed_by: { - all_of: infra.signedBy?.allOf || [], - any_of: infra.signedBy?.anyOf || [] - } - }, - resources: [] - }; - - if (group.requirements.attributes) { - group.requirements.attributes = group.requirements.attributes.sort((a, b) => a.key < b.key); - } - - groups[group.name] = group; - } - - const resources = { - resources: toResourceUnits(compute.resources), // Chanded resources => unit - price: price, - count: svcdepl.count - }; - - let endpoints = []; - svc?.expose?.forEach(expose => { - expose?.to - ?.filter(to => to.global) - .forEach(to => { - const proto = ParseServiceProtocol(expose.proto); - - const v = { - port: expose.port, - externalPort: expose.as || 0, - proto: proto, - service: to.service || null, - global: !!to.global, - hosts: expose.accept || null, - HTTPOptions: getHttpOptions(expose["http_options"]), - IP: to.ip || "" - }; - - // Check to see if an IP endpoint is also specified - if (to.ip?.length > 0) { - const seqNo = ipEndpointNames[to.ip]; - (v as any).EndpointSequenceNumber = seqNo || 0; - endpoints.push({ kind: Endpoint_LEASED_IP, sequence_number: seqNo }); - } - - let kind = Endpoint_RANDOM_PORT; - - if (shouldBeIngress(v)) { - kind = Endpoint_SHARED_HTTP; - } - - endpoints.push({ kind: kind, sequence_number: 0 }); // TODO - }); - }); - - resources.resources.endpoints = endpoints; - group.resources.push(resources); - }); - }); - - let names = Object.keys(groups); - - names = names.sort(); - - let result = names.map(name => groups[name]); - // console.log(result); - return result; -} - function validate(yamlJson) { + const sdl = getSdl(yamlJson, "beta2"); + // ENDPOINT VALIDATION if (yamlJson.endpoints) { Object.keys(yamlJson.endpoints).forEach(endpoint => { @@ -274,7 +58,7 @@ function validate(yamlJson) { // LEASE IP VALIDATION svc.expose?.forEach(expose => { - const proto = ParseServiceProtocol(expose.proto); + const proto = sdl.parseServiceProto(expose.proto); expose.to?.forEach(to => { if (to.ip?.length > 0) { @@ -385,164 +169,37 @@ function validate(yamlJson) { } } -function DepositFromFlags(deposit) { - return { - denom: "uakt", - amount: deposit.toString() - }; -} - -// Port of: func (sdl *v2) Manifest() (manifest.Manifest, error -export function Manifest(yamlJson) { - let groups = {}; - - const ipEndpointNames = computeEndpointSequenceNumbers(yamlJson); - - const sortedServicesNames = Object.keys(yamlJson.services).sort(); - sortedServicesNames.forEach(svcName => { - const svc = yamlJson.services[svcName]; - const depl = yamlJson.deployment[svcName]; - - const sortedPlacementNames = Object.keys(depl).sort(); - sortedPlacementNames.forEach(placementName => { - const svcdepl = depl[placementName]; - let group = groups[placementName]; - - if (!group) { - group = { - Name: placementName, - Services: [] - }; - groups[placementName] = group; - } - - const compute = yamlJson.profiles.compute[svcdepl.profile]; - const manifestResources = toResourceUnits(compute.resources); - let manifestExpose = []; - - svc.expose?.forEach(expose => { - const proto = ParseServiceProtocol(expose.proto); - - if (expose.to && expose.to.length > 0) { - expose.to.forEach(to => { - let seqNo = null; - - if (to.global && to.ip?.length > 0) { - const endpointExists = yamlJson.endpoints && yamlJson.endpoints[to.ip]; - - if (!endpointExists) { - throw new CustomValidationError(`Unknown endpoint "${to.ip}". Add to the list of endpoints in the "endpoints" section.`); - } +export function getManifest(yamlJson, asString = false) { + const manifest = Manifest(yamlJson, "beta2", asString); - seqNo = ipEndpointNames[to.ip]; - manifestResources.endpoints = [{ kind: Endpoint_LEASED_IP, sequence_number: seqNo }]; - } - - const _expose = { - Port: expose.port, - ExternalPort: expose.as || 0, - Proto: proto, - Service: to.service || "", - Global: !!to.global, - Hosts: expose.accept || null, - HTTPOptions: getHttpOptions(expose["http_options"]), - IP: to.ip || "", - EndpointSequenceNumber: seqNo || 0 - }; - - manifestExpose = manifestExpose.concat([_expose]); - }); - } else { - const _expose = { - Port: expose.port, - ExternalPort: expose.as || 0, - Proto: proto, - Service: "", - Global: false, - Hosts: expose.accept?.items || null, - HTTPOptions: getHttpOptions(expose["http_options"]), - IP: "" - }; - - manifestExpose = manifestExpose.concat([_expose]); - } - }); - - const msvc: any = { - Name: svcName, - Image: svc.image, - Command: svc.command || null, - Args: svc.args || null, - Env: svc.env || null, - Resources: manifestResources, - Count: svcdepl.count, - Expose: manifestExpose - }; - - if (svc.params) { - msvc.params = { - Storage: [] - }; - - (Object.keys(svc.params?.storage) || []).forEach(name => { - msvc.params.Storage.push({ - name: name, - mount: svc.params.storage[name].mount, - readOnly: svc.params.storage[name].readOnly || false - }); - }); - } - - // stable ordering for the Expose portion - msvc.Expose = - msvc.Expose && - msvc.Expose.sort((a, b) => { - if (a.Service !== b.Service) { - return a.Service < b.Service; - } - if (a.Port !== b.Port) { - return a.Port < b.Port; - } - if (a.Proto !== b.Proto) { - return a.Proto < b.Proto; - } - if (a.Global !== b.Global) { - return a.Global < b.Global; - } - return false; - }); - - group.Services.push(msvc); - }); - }); - - let names = Object.keys(groups); - - names = names.sort(); - - let result = names.map(name => groups[name]); - return result; + return manifest; } -export async function getManifestVersion(yamlJson) { - const mani = Manifest(yamlJson); - const version = await ManifestVersion(mani); +export async function getManifestVersion(yamlJson, asString = false) { + const version = await ManifestVersion(yamlJson, "beta2"); - return version; + if (asString) { + return Buffer.from(version).toString("base64"); + } else { + return version; + } } export async function NewDeploymentData(apiEndpoint, yamlJson, dseq, fromAddress, deposit = defaultInitialDeposit, depositorAddress = null) { // Validate the integrity of the yaml validate(yamlJson); - const groups = DeploymentGroups(yamlJson); - const mani = Manifest(yamlJson); - const ver = await ManifestVersion(mani); + const groups = DeploymentGroups(yamlJson, "beta2"); + const mani = Manifest(yamlJson, "beta2"); + const ver = await ManifestVersion(yamlJson, "beta2"); const id = { owner: fromAddress, dseq: dseq }; - const _deposit = DepositFromFlags(deposit); + const _deposit = { + denom: "uakt", + amount: deposit.toString() + }; if (!id.dseq) { id.dseq = await getCurrentHeight(apiEndpoint); diff --git a/deploy-web/src/utils/deploymentData/v1beta3.ts b/deploy-web/src/utils/deploymentData/v1beta3.ts index dc6ddad941..9d60ff0d4f 100644 --- a/deploy-web/src/utils/deploymentData/v1beta3.ts +++ b/deploy-web/src/utils/deploymentData/v1beta3.ts @@ -1,268 +1,15 @@ -import { CustomValidationError, ManifestVersion, ParseServiceProtocol, getCurrentHeight, shouldBeIngress, parseSizeStr } from "./helpers"; +import { CustomValidationError, DeploymentGroups, Manifest, ManifestVersion, getCurrentHeight, getSdl, parseSizeStr } from "./helpers"; import { defaultInitialDeposit, testnetId } from "../constants"; import { stringToBoolean } from "../stringUtils"; +const path = require("path"); const endpointNameValidationRegex = /^[a-z]+[-_\da-z]+$/; const endpointKindIP = "ip"; -const path = require("path"); - -const defaultHTTPOptions = { - MaxBodySize: 1048576, - ReadTimeout: 60000, - SendTimeout: 60000, - NextTries: 3, - NextTimeout: 0, - NextCases: ["error", "timeout"] -}; - -// TODO Enum -const Endpoint_SHARED_HTTP = 0; -const Endpoint_RANDOM_PORT = 1; -const Endpoint_LEASED_IP = 2; - -// https://github.com/ovrclk/akash/blob/98fd6bd9c25014fb819f85a06168a3335dc9633f/x/deployment/types/v1beta3/validation_config.go -// const validationConfig = { -// maxUnitCPU: 256 * 1000, // 256 CPUs -// maxUnitMemory: 512 * unit.Gi, // 512 Gi -// maxUnitStorage: 32 * unit.Ti, // 32 Ti -// maxUnitCount: 50, -// maxUnitPrice: 10000000, // 10akt - -// minUnitCPU: 10, -// minUnitMemory: specSuffixes.Mi, -// minUnitStorage: 5 * specSuffixes.Mi, -// minUnitCount: 1, - -// maxGroupCount: 20, -// maxGroupUnits: 20, - -// maxGroupCPU: 512 * 1000, -// maxGroupMemory: 1024 * specSuffixes.Gi, -// maxGroupStorage: 32 * specSuffixes.Ti -// }; - -function getHttpOptions(options = {}) { - return { - maxBodySize: options["max_body_size"] || defaultHTTPOptions.MaxBodySize, - readTimeout: options["read_timeout"] || defaultHTTPOptions.ReadTimeout, - sendTimeout: options["send_timeout"] || defaultHTTPOptions.SendTimeout, - nextTries: options["next_tries"] || defaultHTTPOptions.NextTries, - nextTimeout: options["next_timeout"] || defaultHTTPOptions.NextTimeout, - nextCases: options["next_cases"] || defaultHTTPOptions.NextCases - }; -} - -// Port of: func (sdl *v2ComputeResources) toResourceUnits() types.ResourceUnits -export function toResourceUnits(computeResources) { - if (!computeResources) return {}; - const selectedNetworkId = localStorage.getItem("selectedNetworkId"); - - let units = {} as any; - - // CPU - if (computeResources.cpu) { - const cpu = - typeof computeResources.cpu.units === "string" && computeResources.cpu.units.endsWith("m") - ? computeResources.cpu.units.slice(0, -1) - : (computeResources.cpu.units * 1000).toString(); - - units.cpu = { - units: { val: cpu }, - attributes: - computeResources.cpu.attributes && - Object.keys(computeResources.cpu.attributes) - .sort() - .map(key => ({ - key: key, - value: computeResources.cpu.attributes[key].toString() - })) - }; - } - - // MEMORY - if (computeResources.memory) { - units.memory = { - quantity: { val: parseSizeStr(computeResources.memory.size) }, - attributes: - computeResources.memory.attributes && - Object.keys(computeResources.memory.attributes) - .sort() - .map(key => ({ - key: key, - value: computeResources.memory.attributes[key].toString() - })) - }; - } - - // STORAGE - if (computeResources.storage) { - const storages = computeResources.storage.map ? computeResources.storage : [computeResources.storage]; - units.storage = - storages.map(storage => ({ - name: storage.name || "default", - quantity: { val: parseSizeStr(storage.size) }, - attributes: - storage.attributes && - Object.keys(storage.attributes) - .sort() - .map(key => ({ - key: key, - value: storage.attributes[key].toString() - })) - })) || []; - } - - // GPU - if (computeResources.gpu) { - const gpu = computeResources.gpu.units; - - units.gpu = { - units: { val: gpu.toString() }, - attributes: computeResources.gpu.attributes && mapGpuSpecs(computeResources.gpu.attributes.vendor) - }; - } else if (selectedNetworkId === testnetId) { - // TODO Remove once on the mainnet - units.gpu = { - units: { val: "0" } - }; - } - - units.endpoints = null; - - return units; -} - -const mapGpuSpecs = (vendor: { [key: string]: any }) => { - const _attributes = []; - - Object.keys(vendor).forEach(key => { - if (!!vendor[key] && typeof vendor[key] === "object") { - vendor[key].forEach((model: { model: string; ram: string }) => { - _attributes.push({ key: `vendor/${key}/model/${model.model}${model.ram ? "/" + model.ram : ""}`, value: "true" }); - }); - } else { - _attributes.push({ key: `vendor/${key}/model/*`, value: "true" }); - } - }); - - return _attributes.sort((a, b) => a.key.localeCompare(b.key)); -}; - -function computeEndpointSequenceNumbers(yamlJson) { - let ipEndpointNames = {}; - - Object.keys(yamlJson.services).forEach(svcName => { - const svc = yamlJson.services[svcName]; - - svc?.expose?.forEach(expose => { - expose?.to - ?.filter(to => to.global && to.ip?.length > 0) - .map(to => to.ip) - .sort() - .forEach((ip, i) => { - ipEndpointNames[ip] = i + 1; - }); - }); - }); - - return ipEndpointNames; -} - -function DeploymentGroups(yamlJson) { - let groups = {}; - const ipEndpointNames = computeEndpointSequenceNumbers(yamlJson); - - Object.keys(yamlJson.services).forEach(svcName => { - const svc = yamlJson.services[svcName]; - const depl = yamlJson.deployment[svcName]; - - Object.keys(depl).forEach(placementName => { - const svcdepl = depl[placementName]; - const compute = yamlJson.profiles.compute[svcdepl.profile]; - const infra = yamlJson.profiles.placement[placementName]; - const price = infra.pricing[svcdepl.profile]; - - price.amount = price.amount.toString(); // Interpreted as number otherwise - - let group = groups[placementName]; - - if (!group) { - group = { - name: placementName, - requirements: { - attributes: infra.attributes ? Object.keys(infra.attributes).map(key => ({ key: key, value: infra.attributes[key]?.toString() })) : [], - signed_by: { - all_of: infra.signedBy?.allOf || [], - any_of: infra.signedBy?.anyOf || [] - } - }, - resources: [] - }; - - if (group.requirements.attributes) { - group.requirements.attributes = group.requirements.attributes.sort((a, b) => a.key < b.key); - } - - groups[group.name] = group; - } - - const resources = { - resources: toResourceUnits(compute.resources), // Chanded resources => unit - price: price, - count: svcdepl.count - }; - - let endpoints = []; - svc?.expose?.forEach(expose => { - expose?.to - ?.filter(to => to.global) - .forEach(to => { - const proto = ParseServiceProtocol(expose.proto); - - const v = { - port: expose.port, - externalPort: expose.as || 0, - proto: proto, - service: to.service || null, - global: !!to.global, - hosts: expose.accept || null, - HTTPOptions: getHttpOptions(expose["http_options"]), - IP: to.ip || "" - }; - - // Check to see if an IP endpoint is also specified - if (to.ip?.length > 0) { - const seqNo = ipEndpointNames[to.ip]; - (v as any).EndpointSequenceNumber = seqNo || 0; - endpoints.push({ kind: Endpoint_LEASED_IP, sequence_number: seqNo }); - } - - let kind = Endpoint_RANDOM_PORT; - - if (shouldBeIngress(v)) { - kind = Endpoint_SHARED_HTTP; - } - - endpoints.push({ kind: kind, sequence_number: 0 }); // TODO - }); - }); - - resources.resources.endpoints = endpoints; - group.resources.push(resources); - }); - }); - - let names = Object.keys(groups); - - names = names.sort(); - - let result = names.map(name => groups[name]); - // console.log(result); - return result; -} function validate(yamlJson) { + const sdl = getSdl(yamlJson, "beta3"); + // ENDPOINT VALIDATION if (yamlJson.endpoints) { Object.keys(yamlJson.endpoints).forEach(endpoint => { @@ -312,7 +59,7 @@ function validate(yamlJson) { // LEASE IP VALIDATION svc.expose?.forEach(expose => { - const proto = ParseServiceProtocol(expose.proto); + const proto = sdl.parseServiceProto(expose.proto); expose.to?.forEach(to => { if (to.ip?.length > 0) { @@ -448,167 +195,37 @@ function validate(yamlJson) { } } -function DepositFromFlags(deposit) { - return { - denom: "uakt", - amount: deposit.toString() - }; -} - -// Port of: func (sdl *v2) Manifest() (manifest.Manifest, error -export function Manifest(yamlJson) { - let groups = {}; - - const ipEndpointNames = computeEndpointSequenceNumbers(yamlJson); - - const sortedServicesNames = Object.keys(yamlJson.services).sort(); - sortedServicesNames.forEach(svcName => { - const svc = yamlJson.services[svcName]; - const depl = yamlJson.deployment[svcName]; - - const sortedPlacementNames = Object.keys(depl).sort(); - sortedPlacementNames.forEach(placementName => { - const svcdepl = depl[placementName]; - let group = groups[placementName]; - - if (!group) { - group = { - name: placementName, - services: [] - }; - groups[placementName] = group; - } - - const compute = yamlJson.profiles.compute[svcdepl.profile]; - const manifestResources = toResourceUnits(compute.resources); - let manifestExpose = []; - - svc.expose?.forEach(expose => { - const proto = ParseServiceProtocol(expose.proto); - - if (expose.to && expose.to.length > 0) { - expose.to.forEach(to => { - let seqNo = null; - - if (to.global && to.ip?.length > 0) { - const endpointExists = yamlJson.endpoints && yamlJson.endpoints[to.ip]; +export function getManifest(yamlJson) { + const manifest = Manifest(yamlJson, "beta3"); - if (!endpointExists) { - throw new CustomValidationError(`Unknown endpoint "${to.ip}". Add to the list of endpoints in the "endpoints" section.`); - } - - seqNo = ipEndpointNames[to.ip]; - manifestResources.endpoints = [{ kind: Endpoint_LEASED_IP, sequence_number: seqNo }]; - } - - const _expose = { - port: expose.port, - externalPort: expose.as || 0, - proto: proto, - service: to.service || "", - global: !!to.global, - hosts: expose.accept || null, - httpOptions: getHttpOptions(expose["http_options"]), - ip: to.ip || "", - endpointSequenceNumber: seqNo || 0 - }; - - manifestExpose = manifestExpose.concat([_expose]); - }); - } else { - const _expose = { - port: expose.port, - externalPort: expose.as || 0, - proto: proto, - service: "", - global: false, - hosts: expose.accept?.items || null, - httpOptions: getHttpOptions(expose["http_options"]), - ip: "" - }; - - manifestExpose = manifestExpose.concat([_expose]); - } - }); - - const msvc: any = { - name: svcName, - image: svc.image, - command: svc.command || null, - args: svc.args || null, - env: svc.env || null, - resources: manifestResources, - count: svcdepl.count, - expose: manifestExpose - }; - - if (svc.params) { - msvc.params = { - storage: [] - }; - - (Object.keys(svc.params?.storage) || []).forEach(name => { - msvc.params.storage.push({ - name: name, - mount: svc.params.storage[name].mount, - readOnly: svc.params.storage[name].readOnly || false - }); - }); - } else { - msvc.params = null; - } - - // stable ordering for the Expose portion - msvc.expose = - msvc.expose && - msvc.expose.sort((a, b) => { - if (a.service !== b.service) { - return a.service < b.service; - } - if (a.port !== b.port) { - return a.port < b.port; - } - if (a.proto !== b.proto) { - return a.proto < b.proto; - } - if (a.global !== b.global) { - return a.global < b.global; - } - return false; - }); - - group.services.push(msvc); - }); - }); - - let names = Object.keys(groups); - - names = names.sort(); - - let result = names.map(name => groups[name]); - - return result; + return manifest; } -export async function getManifestVersion(yamlJson) { - const mani = Manifest(yamlJson); - const version = await ManifestVersion(mani); +export async function getManifestVersion(yamlJson, asString = false) { + const version = await ManifestVersion(yamlJson, "beta2"); - return version; + if (asString) { + return Buffer.from(version).toString("base64"); + } else { + return version; + } } export async function NewDeploymentData(apiEndpoint, yamlJson, dseq, fromAddress, deposit = defaultInitialDeposit, depositorAddress = null) { // Validate the integrity of the yaml validate(yamlJson); - const groups = DeploymentGroups(yamlJson); - const mani = Manifest(yamlJson); - const ver = await ManifestVersion(mani); + const groups = DeploymentGroups(yamlJson, "beta3"); + const mani = Manifest(yamlJson, "beta3"); + const ver = await ManifestVersion(yamlJson, "beta3"); const id = { owner: fromAddress, dseq: dseq }; - const _deposit = DepositFromFlags(deposit); + const _deposit = { + denom: "uakt", + amount: deposit.toString() + }; if (!id.dseq) { id.dseq = await getCurrentHeight(apiEndpoint); diff --git a/deploy-web/src/utils/init.ts b/deploy-web/src/utils/init.ts index e77ab81591..2521d5f522 100644 --- a/deploy-web/src/utils/init.ts +++ b/deploy-web/src/utils/init.ts @@ -1,7 +1,7 @@ import { setNetworkVersion } from "./constants"; import { registerTypes } from "./customRegistry"; import { initDeploymentData } from "./deploymentData"; -import { initProtoTypes } from "./protoTypes"; +import { initProtoTypes } from "./proto"; import { setMessageTypes } from "./TransactionMessageData"; export const initAppTypes = () => { diff --git a/deploy-web/src/utils/protoTypes/index.ts b/deploy-web/src/utils/proto/index.ts similarity index 100% rename from deploy-web/src/utils/protoTypes/index.ts rename to deploy-web/src/utils/proto/index.ts diff --git a/deploy-web/src/utils/proto/akash/v1beta1.ts b/deploy-web/src/utils/proto/v1beta1.ts similarity index 100% rename from deploy-web/src/utils/proto/akash/v1beta1.ts rename to deploy-web/src/utils/proto/v1beta1.ts diff --git a/deploy-web/src/utils/proto/akash/v1beta2.ts b/deploy-web/src/utils/proto/v1beta2.ts similarity index 83% rename from deploy-web/src/utils/proto/akash/v1beta2.ts rename to deploy-web/src/utils/proto/v1beta2.ts index f183cbaa7e..03b81933ef 100644 --- a/deploy-web/src/utils/proto/akash/v1beta2.ts +++ b/deploy-web/src/utils/proto/v1beta2.ts @@ -1,3 +1,5 @@ +export { ProviderInfo } from "@akashnetwork/akashjs/build/protobuf/akash/provider/v1beta2/provider"; +export { Attribute } from "@akashnetwork/akashjs/build/protobuf/akash/base/v1beta2/attribute"; export { MsgSignProviderAttributes, MsgDeleteProviderAttributes } from "@akashnetwork/akashjs/build/protobuf/akash/audit/v1beta2/audit"; export { MsgCreateCertificate, MsgRevokeCertificate } from "@akashnetwork/akashjs/build/protobuf/akash/cert/v1beta2/cert"; export { MsgCloseGroup, MsgPauseGroup, MsgStartGroup } from "@akashnetwork/akashjs/build/protobuf/akash/deployment/v1beta2/groupmsg"; diff --git a/deploy-web/src/utils/proto/akash/v1beta3.ts b/deploy-web/src/utils/proto/v1beta3.ts similarity index 100% rename from deploy-web/src/utils/proto/akash/v1beta3.ts rename to deploy-web/src/utils/proto/v1beta3.ts diff --git a/deploy-web/src/utils/protoTypes/deccoin-v2.ts b/deploy-web/src/utils/protoTypes/deccoin-v2.ts deleted file mode 100644 index 3255745be4..0000000000 --- a/deploy-web/src/utils/protoTypes/deccoin-v2.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Type, Writer, Reader } from "protobufjs"; - -// TODO Types -export const DecCoin = new Type("DecCoin") as any; -DecCoin.ctor = function (...args) { - // console.log("ctor: ", args); -}; -DecCoin.encode = function (message, writer) { - // console.log("Encode: ", message, writer); - if (!writer) { - writer = Writer.create(); - } - - if (message.denom !== "") { - writer.uint32(10).string(message.denom); - } - if (message.amount !== "") { - // https://github.com/cosmos/cosmos-sdk/issues/10863 - let amount = message.amount; - if (message.amount.includes(".")) { - const parts = amount.split("."); - amount = parts[0] + parts[1].padEnd(18, "0"); - } else { - amount = message.amount.padEnd(message.amount.length + 18, "0"); - } - - writer.uint32(18).string(amount); - } - return writer; -}; - -DecCoin.decode = function (input, length) { - const reader = input instanceof Reader ? input : new Reader(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = { denom: "", amount: "" }; - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.denom = reader.string(); - break; - case 2: - message.amount = reader.string(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; -}; diff --git a/deploy-web/src/utils/protoTypes/deccoin-v3.ts b/deploy-web/src/utils/protoTypes/deccoin-v3.ts deleted file mode 100644 index 3255745be4..0000000000 --- a/deploy-web/src/utils/protoTypes/deccoin-v3.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Type, Writer, Reader } from "protobufjs"; - -// TODO Types -export const DecCoin = new Type("DecCoin") as any; -DecCoin.ctor = function (...args) { - // console.log("ctor: ", args); -}; -DecCoin.encode = function (message, writer) { - // console.log("Encode: ", message, writer); - if (!writer) { - writer = Writer.create(); - } - - if (message.denom !== "") { - writer.uint32(10).string(message.denom); - } - if (message.amount !== "") { - // https://github.com/cosmos/cosmos-sdk/issues/10863 - let amount = message.amount; - if (message.amount.includes(".")) { - const parts = amount.split("."); - amount = parts[0] + parts[1].padEnd(18, "0"); - } else { - amount = message.amount.padEnd(message.amount.length + 18, "0"); - } - - writer.uint32(18).string(amount); - } - return writer; -}; - -DecCoin.decode = function (input, length) { - const reader = input instanceof Reader ? input : new Reader(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = { denom: "", amount: "" }; - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.denom = reader.string(); - break; - case 2: - message.amount = reader.string(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; -}; diff --git a/deploy-web/src/utils/protoTypes/v1beta2.ts b/deploy-web/src/utils/protoTypes/v1beta2.ts deleted file mode 100644 index 467906d74b..0000000000 --- a/deploy-web/src/utils/protoTypes/v1beta2.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { Field, Enum, Type, Root } from "protobufjs"; -import { DecCoin } from "./deccoin-v2"; -export { MsgUpdateProvider } from "../proto/akash/v1beta2"; - -// Deployments -const DeploymentID = new Type("DeploymentID").add(new Field("owner", 1, "string")).add(new Field("dseq", 2, "uint64")); -const Coin = new Type("Coin").add(new Field("denom", 1, "string")).add(new Field("amount", 2, "string")); -const Kind = new Enum("Kind", { SHARED_HTTP: 0, RANDOM_PORT: 1 }); -const Endpoint = new Type("Endpoint").add(new Field("kind", 1, "Kind")).add(Kind).add(new Field("sequence_number", 2, "uint32")); -const Attribute = new Type("Attribute").add(new Field("key", 1, "string")).add(new Field("value", 2, "string")); -const ResourceValue = new Type("ResourceValue").add(new Field("val", 1, "string")); -const CPU = new Type("CPU") - .add(new Field("units", 1, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const Memory = new Type("Memory") - .add(new Field("quantity", 1, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const Storage = new Type("Storage") - .add(new Field("name", 1, "string")) - .add(new Field("quantity", 2, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 3, "Attribute", "repeated")) - .add(Attribute); -const ResourceUnits = new Type("ResourceUnits") - .add(new Field("cpu", 1, "CPU")) - .add(CPU) - .add(new Field("memory", 2, "Memory")) - .add(Memory) - .add(new Field("storage", 3, "Storage", "repeated")) - .add(Storage) - .add(new Field("endpoints", 4, "Endpoint", "repeated")) - .add(Endpoint); - -const Resource = new Type("Resource") - .add(new Field("resources", 1, "ResourceUnits")) // unit - .add(ResourceUnits) - .add(new Field("count", 2, "uint32")) - .add(new Field("price", 3, "DecCoin")) - .add(DecCoin); -const SignedBy = new Type("SignedBy").add(new Field("all_of", 1, "string", "repeated")).add(new Field("any_of", 2, "string", "repeated")); -const PlacementRequirements = new Type("PlacementRequirements") - .add(new Field("signed_by", 1, "SignedBy")) - .add(SignedBy) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const GroupSpec = new Type("GroupSpec") - .add(new Field("name", 1, "string")) - .add(new Field("requirements", 2, "PlacementRequirements")) - .add(PlacementRequirements) - .add(new Field("resources", 3, "Resource", "repeated")) - .add(Resource); - -export const MsgCloseDeployment = new Type("MsgCloseDeployment").add(new Field("id", 1, "DeploymentID")); - -export const MsgCreateDeployment = new Type("MsgCreateDeployment") - .add(new Field("id", 1, "DeploymentID")) - .add(new Field("groups", 2, "GroupSpec", "repeated")) - .add(new Field("version", 3, "bytes")) - .add(new Field("deposit", 4, "Coin")) - .add(Coin) - .add(new Field("depositor", 5, "string")); - -export const MsgUpdateDeployment = new Type("MsgUpdateDeployment") - .add(new Field("id", 1, "DeploymentID")) - .add(DeploymentID) - .add(new Field("version", 3, "bytes")); - -export const MsgDepositDeployment = new Type("MsgDepositDeployment") - .add(new Field("id", 1, "DeploymentID")) - .add(DeploymentID) - .add(new Field("amount", 2, "Coin")) - .add(Coin) - .add(new Field("depositor", 3, "string")); - -// Certificates - -const CertificateID = new Type("CertificateID").add(new Field("owner", 1, "string")).add(new Field("serial", 2, "string")); - -export const MsgRevokeCertificate = new Type("MsgRevokeCertificate").add(new Field("id", 1, "CertificateID")).add(CertificateID); - -export const MsgCreateCertificate = new Type("MsgCreateCertificate") - .add(new Field("owner", 1, "string")) - .add(new Field("cert", 2, "bytes")) - .add(new Field("pubkey", 3, "bytes")); - -// Leases - -export const BidID = new Type("BidID") - .add(new Field("owner", 1, "string")) - .add(new Field("dseq", 2, "uint64")) - .add(new Field("gseq", 3, "uint32")) - .add(new Field("oseq", 4, "uint32")) - .add(new Field("provider", 5, "string")); - -export const MsgCreateLease = new Type("MsgCreateLease").add(new Field("bid_id", 1, "BidID")).add(BidID); - -const Authorization = new Type("Authorization").add(new Field("spend_limit", 1, "Coin")); - -const AnyGrantDeposit = new Type("AnyGrantDeposit").add(new Field("type_url", 1, "string")).add(new Field("value", 2, "Authorization")).add(Authorization); - -const Timestamp = new Type("Timestamp").add(new Field("seconds", 1, "uint64")).add(new Field("nanos", 2, "uint32")); -const Grant = new Type("Grant") - .add(new Field("authorization", 1, "AnyGrantDeposit")) - .add(AnyGrantDeposit) - .add(new Field("expiration", 2, "Timestamp")) - .add(Timestamp); - -export const MsgGrant = new Type("MsgGrant") - .add(new Field("granter", 1, "string")) - .add(new Field("grantee", 2, "string")) - .add(new Field("grant", 3, "Grant")) - .add(Grant); - -let root = new Root().add(DeploymentID); -root.add(MsgCloseDeployment); -root.add(MsgDepositDeployment); -root.add(MsgCreateDeployment); -root.add(GroupSpec); -root.add(MsgUpdateDeployment); -root.add(MsgGrant); diff --git a/deploy-web/src/utils/protoTypes/v1beta3.ts b/deploy-web/src/utils/protoTypes/v1beta3.ts deleted file mode 100644 index b3988ed88f..0000000000 --- a/deploy-web/src/utils/protoTypes/v1beta3.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Field, Enum, Type, Root } from "protobufjs"; -import { DecCoin } from "./deccoin-v3"; -export { MsgUpdateProvider } from "../proto/akash/v1beta3"; - -// Deployments -const DeploymentID = new Type("DeploymentID").add(new Field("owner", 1, "string")).add(new Field("dseq", 2, "uint64")); -const Coin = new Type("Coin").add(new Field("denom", 1, "string")).add(new Field("amount", 2, "string")); -const Kind = new Enum("Kind", { SHARED_HTTP: 0, RANDOM_PORT: 1 }); -const Endpoint = new Type("Endpoint").add(new Field("kind", 1, "Kind")).add(Kind).add(new Field("sequence_number", 2, "uint32")); -const Attribute = new Type("Attribute").add(new Field("key", 1, "string")).add(new Field("value", 2, "string")); -const ResourceValue = new Type("ResourceValue").add(new Field("val", 1, "string")); -const CPU = new Type("CPU") - .add(new Field("units", 1, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const GPU = new Type("GPU") - .add(new Field("units", 1, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const Memory = new Type("Memory") - .add(new Field("quantity", 1, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const Storage = new Type("Storage") - .add(new Field("name", 1, "string")) - .add(new Field("quantity", 2, "ResourceValue")) - .add(ResourceValue) - .add(new Field("attributes", 3, "Attribute", "repeated")) - .add(Attribute); -const ResourceUnits = new Type("ResourceUnits") - .add(new Field("cpu", 1, "CPU")) - .add(CPU) - .add(new Field("memory", 2, "Memory")) - .add(Memory) - .add(new Field("storage", 3, "Storage", "repeated")) - .add(Storage) - .add(new Field("gpu", 4, "GPU")) - .add(GPU) - .add(new Field("endpoints", 5, "Endpoint", "repeated")) - .add(Endpoint); - -const Resource = new Type("Resource") - .add(new Field("resources", 1, "ResourceUnits")) // unit - .add(ResourceUnits) - .add(new Field("count", 2, "uint32")) - .add(new Field("price", 3, "DecCoin")) - .add(DecCoin); -const SignedBy = new Type("SignedBy").add(new Field("all_of", 1, "string", "repeated")).add(new Field("any_of", 2, "string", "repeated")); -const PlacementRequirements = new Type("PlacementRequirements") - .add(new Field("signed_by", 1, "SignedBy")) - .add(SignedBy) - .add(new Field("attributes", 2, "Attribute", "repeated")) - .add(Attribute); -const GroupSpec = new Type("GroupSpec") - .add(new Field("name", 1, "string")) - .add(new Field("requirements", 2, "PlacementRequirements")) - .add(PlacementRequirements) - .add(new Field("resources", 3, "Resource", "repeated")) - .add(Resource); - -export const MsgCloseDeployment = new Type("MsgCloseDeployment").add(new Field("id", 1, "DeploymentID")); - -export const MsgCreateDeployment = new Type("MsgCreateDeployment") - .add(new Field("id", 1, "DeploymentID")) - .add(new Field("groups", 2, "GroupSpec", "repeated")) - .add(new Field("version", 3, "bytes")) - .add(new Field("deposit", 4, "Coin")) - .add(Coin) - .add(new Field("depositor", 5, "string")); - -export const MsgUpdateDeployment = new Type("MsgUpdateDeployment") - .add(new Field("id", 1, "DeploymentID")) - .add(DeploymentID) - .add(new Field("version", 3, "bytes")); - -export const MsgDepositDeployment = new Type("MsgDepositDeployment") - .add(new Field("id", 1, "DeploymentID")) - .add(DeploymentID) - .add(new Field("amount", 2, "Coin")) - .add(Coin) - .add(new Field("depositor", 3, "string")); - -// Certificates - -const CertificateID = new Type("CertificateID").add(new Field("owner", 1, "string")).add(new Field("serial", 2, "string")); - -export const MsgRevokeCertificate = new Type("MsgRevokeCertificate").add(new Field("id", 1, "CertificateID")).add(CertificateID); - -export const MsgCreateCertificate = new Type("MsgCreateCertificate") - .add(new Field("owner", 1, "string")) - .add(new Field("cert", 2, "bytes")) - .add(new Field("pubkey", 3, "bytes")); - -// Leases - -export const BidID = new Type("BidID") - .add(new Field("owner", 1, "string")) - .add(new Field("dseq", 2, "uint64")) - .add(new Field("gseq", 3, "uint32")) - .add(new Field("oseq", 4, "uint32")) - .add(new Field("provider", 5, "string")); - -export const MsgCreateLease = new Type("MsgCreateLease").add(new Field("bid_id", 1, "BidID")).add(BidID); - -const Authorization = new Type("Authorization").add(new Field("spend_limit", 1, "Coin")); - -const AnyGrantDeposit = new Type("AnyGrantDeposit").add(new Field("type_url", 1, "string")).add(new Field("value", 2, "Authorization")).add(Authorization); - -const Timestamp = new Type("Timestamp").add(new Field("seconds", 1, "uint64")).add(new Field("nanos", 2, "uint32")); -const Grant = new Type("Grant") - .add(new Field("authorization", 1, "AnyGrantDeposit")) - .add(AnyGrantDeposit) - .add(new Field("expiration", 2, "Timestamp")) - .add(Timestamp); - -export const MsgGrant = new Type("MsgGrant") - .add(new Field("granter", 1, "string")) - .add(new Field("grantee", 2, "string")) - .add(new Field("grant", 3, "Grant")) - .add(Grant); - -let root = new Root().add(DeploymentID); -root.add(MsgCloseDeployment); -root.add(MsgDepositDeployment); -root.add(MsgCreateDeployment); -root.add(GroupSpec); -root.add(MsgUpdateDeployment); -root.add(MsgGrant); diff --git a/deploy-web/src/utils/sdl/deploymentData/helpers.ts b/deploy-web/src/utils/sdl/deploymentData/helpers.ts deleted file mode 100644 index d1a371dd7b..0000000000 --- a/deploy-web/src/utils/sdl/deploymentData/helpers.ts +++ /dev/null @@ -1,69 +0,0 @@ -export class CustomValidationError extends Error { - constructor(message) { - super(message); - this.name = "CustomValidationError"; - } -} - -const specSuffixes = { - Ki: 1024, - Mi: 1024 * 1024, - Gi: 1024 * 1024 * 1024, - Ti: 1024 * 1024 * 1024 * 1024, - Pi: 1024 * 1024 * 1024 * 1024 * 1024, - Ei: 1024 * 1024 * 1024 * 1024 * 1024 * 1024, - K: 1000, - M: 1000 * 1000, - G: 1000 * 1000 * 1000, - T: 1000 * 1000 * 1000 * 1000, - P: 1000 * 1000 * 1000 * 1000 * 1000, - E: 1000 * 1000 * 1000 * 1000 * 1000 * 1000, - Kb: 1000, - Mb: 1000 * 1000, - Gb: 1000 * 1000 * 1000, - Tb: 1000 * 1000 * 1000 * 1000, - Pb: 1000 * 1000 * 1000 * 1000 * 1000, - Eb: 1000 * 1000 * 1000 * 1000 * 1000 * 1000 -}; - -export function ParseServiceProtocol(input) { - let result; - - // This is not a case sensitive parse, so make all input - // uppercase - if (input) { - input = input.toUpperCase(); - } - - switch (input) { - case "TCP": - case "": - case undefined: // The empty string (no input) implies TCP - result = "TCP"; - break; - case "UDP": - result = "UDP"; - break; - default: - throw new Error("ErrUnsupportedServiceProtocol"); - } - - return result; -} - -export function parseSizeStr(str) { - try { - const suffix = Object.keys(specSuffixes).find(s => str.toString().toLowerCase().endsWith(s.toLowerCase())); - - if (suffix) { - const suffixPos = str.length - suffix.length; - const numberStr = str.substring(0, suffixPos); - return (parseFloat(numberStr) * specSuffixes[suffix]).toString(); - } else { - return parseFloat(str); - } - } catch (err) { - console.error(err); - throw new Error("Error while parsing size: " + str); - } -} diff --git a/deploy-web/src/utils/sdl/deploymentData/v1betat2.ts b/deploy-web/src/utils/sdl/deploymentData/v1betat2.ts deleted file mode 100644 index d4f0e8076b..0000000000 --- a/deploy-web/src/utils/sdl/deploymentData/v1betat2.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { CustomValidationError, ParseServiceProtocol, parseSizeStr } from "./helpers"; -import { stringToBoolean } from "../../stringUtils"; - -const endpointNameValidationRegex = /^[a-z]+[-_\da-z]+$/; -const endpointKindIP = "ip"; - -const path = require("path"); - -export const validateSdl = (yamlJson: any) => { - // ENDPOINT VALIDATION - if (yamlJson.endpoints) { - Object.keys(yamlJson.endpoints).forEach(endpoint => { - const _endpoint = yamlJson.endpoints[endpoint]; - if (!endpointNameValidationRegex.test(endpoint)) { - throw new CustomValidationError(`Endpoint named "${endpoint}" is not a valid name.`); - } - - if (!_endpoint.kind) { - throw new CustomValidationError(`Endpoint named "${endpoint}" has no kind.`); - } - - if (_endpoint.kind !== endpointKindIP) { - throw new CustomValidationError(`Endpoint named "${endpoint}" has an unknown kind "${_endpoint.kind}".`); - } - }); - } - - const endpointsUsed = {}; - const portsUsed = {}; - Object.keys(yamlJson.services).forEach(svcName => { - const svc = yamlJson.services[svcName]; - const depl = yamlJson.deployment[svcName]; - - if (!depl) { - throw new CustomValidationError(`Service "${svcName}" is not defined in the "deployment" section.`); - } - - Object.keys(depl).forEach(placementName => { - const svcdepl = depl[placementName]; - const compute = yamlJson.profiles.compute[svcdepl.profile]; - const infra = yamlJson.profiles.placement[placementName]; - - if (!infra) { - throw new CustomValidationError(`The placement "${placementName}" is not defined in the "placement" section.`); - } - - const price = infra.pricing[svcdepl.profile]; - - if (!price) { - throw new CustomValidationError(`The pricing for the "${svcdepl.profile}" profile is not defined in the "${placementName}" "placement" definition.`); - } - - if (!compute) { - throw new CustomValidationError(`The compute requirements for the "${svcdepl.profile}" profile are not defined in the "compute" section.`); - } - - // LEASE IP VALIDATION - svc.expose?.forEach(expose => { - const proto = ParseServiceProtocol(expose.proto); - - expose.to?.forEach(to => { - if (to.ip?.length > 0) { - if (!to.global) { - throw new CustomValidationError(`Error on "${svcName}", if an IP is declared, the directive must be declared as global.`); - } - - const endpointExists = yamlJson.endpoints && yamlJson.endpoints[to.ip]; - if (!endpointExists) { - throw new CustomValidationError(`Unknown endpoint "${to.ip}" in service "${svcName}". Add to the list of endpoints in the "endpoints" section.`); - } - - endpointsUsed[to.ip] = {}; - - // Endpoint exists. Now check for port collisions across a single endpoint, port, & protocol - const portKey = `${to.ip}-${expose.as}-${proto}`; - const otherServiceName = portsUsed[portKey]; - if (otherServiceName) { - throw new CustomValidationError( - `IP endpoint ${to.ip} port: ${expose.port} protocol: ${proto} specified by service ${svcName} already in use by ${otherServiceName}` - ); - } - } - }); - }); - - // STORAGE VALIDATION - const storages = compute.resources.storage.map ? compute.resources.storage : [compute.resources.storage]; - const volumes = {}; - const attr = {}; - const mounts = {}; - - storages?.forEach(storage => { - const name = storage.name || "default"; - volumes[name] = { - name, - quantity: { val: parseSizeStr(storage.size) }, - attributes: - storage.attributes && - Object.keys(storage.attributes) - .sort() - .map(key => { - const value = storage.attributes[key].toString(); - // add the storage attributes - attr[key] = value; - - return { - key, - value - }; - }) - }; - }); - - if (svc.params) { - (Object.keys(svc.params?.storage || {}) || []).forEach(name => { - const params = svc.params.storage[name]; - if (!volumes[name]) { - throw new CustomValidationError(`Service "${svcName}" references to no-existing compute volume names "${name}".`); - } - - if (!path.isAbsolute(params.mount)) { - throw new CustomValidationError(`Invalid value for "service.${svcName}.params.${name}.mount" parameter. expected absolute path.`); - } - - // merge the service params attributes - attr["mount"] = params.mount; - attr["readOnly"] = params.readOnly || false; - const mount = attr["mount"]; - const vlname = mounts[mount]; - - if (vlname) { - if (!mount) { - throw new CustomValidationError("Multiple root ephemeral storages are not allowed"); - } - - throw new CustomValidationError(`Mount ${mount} already in use by volume ${vlname}.`); - } - - mounts[mount] = name; - }); - } - - (Object.keys(volumes) || []).forEach(volume => { - volumes[volume].attributes?.forEach(nd => { - attr[nd.key] = nd.value; - }); - - const persistent = stringToBoolean(attr["persistent"]); - - if (persistent && !attr["mount"]) { - throw new CustomValidationError( - `compute.storage.${volume} has persistent=true which requires service.${svcName}.params.storage.${volume} to have mount.` - ); - } - }); - }); - }); - - // ENDPOINT DUPLICATE VALIDATION - if (yamlJson.endpoints) { - Object.keys(yamlJson.endpoints).forEach(endpoint => { - const isInUse = endpointsUsed[endpoint]; - if (!isInUse) { - throw new CustomValidationError(`Endpoint ${endpoint} declared but never used.`); - } - }); - } -}; diff --git a/deploy-web/src/utils/sdl/sdlImport.ts b/deploy-web/src/utils/sdl/sdlImport.ts index 0276006cc3..007236200d 100644 --- a/deploy-web/src/utils/sdl/sdlImport.ts +++ b/deploy-web/src/utils/sdl/sdlImport.ts @@ -1,8 +1,8 @@ import { Expose, ImportService } from "@src/types"; import { nanoid } from "nanoid"; import { capitalizeFirstLetter } from "../stringUtils"; -import { CustomValidationError } from "./deploymentData/helpers"; import yaml from "js-yaml"; +import { CustomValidationError } from "../deploymentData"; export const importSimpleSdl = yamlStr => { try { diff --git a/indexer/src/providers/providerStatusProvider.ts b/indexer/src/providers/providerStatusProvider.ts index ce0b53b5d1..696fb38013 100644 --- a/indexer/src/providers/providerStatusProvider.ts +++ b/indexer/src/providers/providerStatusProvider.ts @@ -49,6 +49,7 @@ export async function syncProvidersInfo() { error: null, lastCheckDate: checkDate, cosmosSdkVersion: versionResponse.data.akash.cosmosSdkVersion, + akashVersion: versionResponse.data.akash.version, deploymentCount: response.data.manifest.deployments, leaseCount: response.data.cluster.leases, activeCPU: activeResources.cpu,