From d1da0e5ed2a77296d38b394bd257d15c6fa502e6 Mon Sep 17 00:00:00 2001 From: Emanuele Cesena Date: Sat, 6 Apr 2024 13:09:46 -0700 Subject: [PATCH] manage: on chain data --- anchor/tests/devnet.spec.ts | 36 +++--- web/src/app/manage/Manage.tsx | 124 ++++++++++++--------- web/src/app/products/product-page.tsx | 3 +- web/src/app/products/products-overview.tsx | 43 +++++-- 4 files changed, 122 insertions(+), 84 deletions(-) diff --git a/anchor/tests/devnet.spec.ts b/anchor/tests/devnet.spec.ts index e48e2739..84a7db17 100644 --- a/anchor/tests/devnet.spec.ts +++ b/anchor/tests/devnet.spec.ts @@ -82,6 +82,8 @@ describe("glam_devnet", () => { extension: "", launchDate: "2024-04-01", lifecycle: "active", + uri: "", + imageUri: "", }; const [fundPDA, fundBump] = PublicKey.findProgramAddressSync( @@ -195,6 +197,7 @@ describe("glam_devnet", () => { beforeAll(async () => {}, 15_000); + /* // Subscribe to the fund it("Manager tests subscribe USDC to fund", async () => { console.log("managerUsdcAta", managerUsdcAta); @@ -239,6 +242,7 @@ describe("glam_devnet", () => { ); // expect(managerShares.amount).toEqual(shares.supply); }); + */ /* it("Manager redeems 100% of fund", async () => { @@ -496,8 +500,22 @@ describe("glam_devnet", () => { TESTS TO CREATE - do NOT rerun */ + /* + it("Close fund", async () => { + await program.methods + .close() + .accounts({ + fund: 'CrtYP7DWrUGzLfNBWEvnYoBVuGni2pPpiAzYa2ZesJnm', + manager: manager.publicKey + }) + .rpc(); + + // The account should no longer exist, returning null. + const closedAccount = await program.account.fund.fetchNullable(fundPDA); + expect(closedAccount).toBeNull(); + }); + */ -/* // This is the test used to initialize the 1st devnet fund, do NOT rerun it("Initialize fund", async () => { try { @@ -539,7 +557,6 @@ describe("glam_devnet", () => { expect(fund.symbol).toEqual(fundSymbol); expect(fund.isActive).toEqual(true); }); -*/ /* it("Update fund", async () => { @@ -691,19 +708,4 @@ describe("glam_devnet", () => { }, 10_000); */ - /* - it("Close fund", async () => { - await program.methods - .close() - .accounts({ - fund: '2exrMpmVboCb57t94KHZWKEv7nrcoa5rQSawE19atsrt', - manager: manager.publicKey - }) - .rpc(); - - // The account should no longer exist, returning null. - const closedAccount = await program.account.fund.fetchNullable(fundPDA); - expect(closedAccount).toBeNull(); - }); - */ }); diff --git a/web/src/app/manage/Manage.tsx b/web/src/app/manage/Manage.tsx index 1aed57a9..9c3882a7 100644 --- a/web/src/app/manage/Manage.tsx +++ b/web/src/app/manage/Manage.tsx @@ -4,57 +4,69 @@ import { Add } from "@carbon/icons-react"; import { Link } from "react-router-dom"; import { formatNumber } from "../utils/format-number"; import { relative } from "path"; - -/* -GLAMsYF1Uo1LG855FVGHS853FyJ4aYkWf6B4E1sVzprc -GLaMc99QpnP1VKNwwFjNgUk4vhrGKu2JanCKzYRmKAgY -GLam9tx5LoYZHWEb2kKz3GqJW8TJJ4Vd2Q5vp1T2vo1c -GLAM7aqKnLbo65cRvyBk7WGuh9WTzWAxJZ7sUXdaf8rx - -fAbioarvxMkYAsBAwg5Tmd5cipU8ZHxdmK47jqZWtpv - -2X24TzxetDQcKob24wTEBq7gk7Q2KsfWQCvSyf1EfbhD -*/ +import { useGlamProgram } from "../glam/glam-data-access"; +import { useWallet } from "@solana/wallet-adapter-react"; export const Manage = () => { - const mockApiData = [ - { - id: "AdXkDnJpFKqZeoUygLvm5dp2b5JGVPz3rEWfGCtB5Kc2", - symbol: "iBTC", - name: "iShares Bitcoin Trust", - aum: 15941890385, - nav: 39.72, - backgroundImage: - 'url("https://api.glam.systems/image/EMAbk6kYhQbvtpqWyfvDPVJBvD5isMZvQT5aM4TyCAeG.png")' - }, - { - id: "AdXkDnJpFKqZeoUygLvm5dp2b5JGVPz3rEWfGCtB5Kc2", - symbol: "iETH", - name: "iShares Ethereum Trust", - aum: 15941890385, - nav: 39.72, - backgroundImage: - 'url("https://api.glam.systems/image/yurUzfjdrUH2ujsWwQkFsv8eQJiJwgbHQFUZtf5yqoV.png")' - }, - { - id: "AdXkDnJpFKqZeoUygLvm5dp2b5JGVPz3rEWfGCtB5Kc2", - symbol: "iSOL", - name: "iShares Solana Trust", - aum: 15941890385, - nav: 39.72, - backgroundImage: - 'url("https://api.glam.systems/image/fAbioarvxMkYAsBAwg5Tmd5cipU8ZHxdmK47jqZWtpv.png")' - }, - { - id: "AdXkDnJpFKqZeoUygLvm5dp2b5JGVPz3rEWfGCtB5Kc2", - symbol: "iBONK", - name: "iShares Bonk Trust", - aum: 15941890385, - nav: 39.72, - backgroundImage: - 'url("https://api.glam.systems/image/GLam9tx5LoYZHWEb2kKz3GqJW8TJJ4Vd2Q5vp1T2vo1c.png")' - } - ]; + // const mockApiData = [ + // { + // id: "CWb949XA3vrdiEp2BFtjr9MbUonHke8CVdTb8Cr7Hctd", + // symbol: "RHW", + // name: "Renaissance Hackathon Winners", + // aum: 75_000, + // nav: 175.75, + // backgroundImage: + // 'url("https://api.glam.systems/image/4hDzLKRYr8zAnmXLLsmmazkp3Hg8AvHFSiqUTHFktNoF.png")' + // }, + // { + // id: "6ZBb3LRddLtBq6DeNtSaUrMipieaFJgTETgTBoiAGBCC", + // symbol: "CAF", + // name: "Colosseum Accelerator Fund", + // aum: 600_000_000, + // nav: 600.00, + // backgroundImage: + // 'url("https://api.glam.systems/image/5NsVEVGdYqNSneWBhogA7yLDB9dYTAEyERnSj6wK68V3.png")' + // }, + // { + // id: "6a2Jb6fQoH8TZF1qTawrriMoEiqQf2w6KMyj4pPFA3ju", + // symbol: "OMMG", + // name: "Orca Market Making Group", + // aum: 15_941_890, + // nav: 139.72, + // backgroundImage: + // 'url("https://api.glam.systems/image/3qs8hDSDKDAPuQfJrXnv9DDdGm4Ki3E1kTETAQRJR4dJ.png")' + // }, + // { + // id: "Asytc9KxdgWVQJAp4KrYzu1B21R7AdQfhXx6bBHHnSm4", + // symbol: "PDA", + // name: "Pyth DAO Treasury", + // aum: 101_118_482, + // nav: 182.3, + // backgroundImage: + // 'url("https://api.glam.systems/image/3hTZD8KfhTKY18C64tYAbjvTYQXHtggEXGNrFFTmDbgA.png")' + // } + // ]; + + const { accounts } = useGlamProgram(); + const { publicKey } = useWallet(); + let data = (accounts.data || []) + .filter((d) => (d.account.manager.toString() == (publicKey || "").toString())) + .map((d) => { + const fund = d.account; + const id = d.publicKey.toString(); + return { + id, + symbol: fund.symbol, + name: fund.name, + aum: 0, + nav: 0, + backgroundImage: + `url("https://api.glam.systems/image/${fund.shareClasses[0]}.png")` + }; + }); + // if (!data.length) { + // data = mockApiData; + // } // when clicking on a tile, navigate to the relevant product page return ( @@ -65,7 +77,7 @@ export const Manage = () => { narrow className="w-[80vw] h-full mt-[100px] max-h-[67vh] items-center overflow-y-auto hide-scrollbar" > - {mockApiData.map((position) => ( + {data.map((position) => ( {

{position.symbol}

{position.name} + { position.aum && (

AUM

{formatNumber(position.aum)}
-
-

NAV

- {formatNumber(position.nav)} -
+ ) || ""} + { position.nav && ( +
+

NAV

+ {formatNumber(position.nav)} +
+ ) || ""}
( + s.charAt(0).toUpperCase() + s.slice(1) +); + +/* Sort funds by inception data (last created first) + and by symbol if funds have the same inception date */ +const sortFunds = (a: any, b: any) => { + if (a.inception == b.inception) { + return (a.symbol <= b.symbol) ? -1 : 1; + } + return (a.inception < b.inception) ? 1 : -1; +} + export default function ProductsOverview() { const { accounts } = useGlamProgram(); const navigate = useNavigate(); - let rows: any[] = []; - if (accounts.data) { - rows = accounts.data.map((account) => { + let rows = (accounts.data || []).map((account) => { const fund = account.account; const imageKey = fund.shareClasses[0].toBase58() || "1111111111111111111111111111111111"; @@ -37,13 +48,14 @@ export default function ProductsOverview() { fees_management: fund.shareClassesMetadata[0].feeManagement / 10_000.0, fees_performance: fund.shareClassesMetadata[0].feePerformance / 10_000.0, - inception: ( + inception: new Date(Date.parse( fund.shareClassesMetadata[0].launchDate - ), - status: fund.shareClassesMetadata[0].lifecycle.toUpperCase() + )), + status: capitalize(fund.shareClassesMetadata[0].lifecycle), + shareClassAsset: fund.shareClassesMetadata[0].shareClassAsset, + policyDistribution: capitalize(fund.shareClassesMetadata[0].policyDistribution), }; - }); - } + }).sort(sortFunds); const headers = [ { @@ -66,13 +78,21 @@ export default function ProductsOverview() { key: "aum", header: "AUM" },*/ - { + /*{ key: "share_classes_len", header: "Share Classes" }, { key: "assets_len", header: "Assets" + },*/ + { + key: "shareClassAsset", + header: "Share Class Asset" + }, + { + key: "policyDistribution", + header: "Policy Distribution" }, { key: "fees_management", @@ -133,7 +153,7 @@ export default function ProductsOverview() { if (cell.info.header === "inception") { return ( - {(cell.value)} + {cell.value.toISOString().split("T")[0]} ); } else if (cell.info.header === "aum") { @@ -163,6 +183,7 @@ export default function ProductsOverview() { ))} + {/* console.log("change")} itemsPerPageText={null} - /> + />*/} )}