Skip to content

Commit

Permalink
product: sync return of nav and aum
Browse files Browse the repository at this point in the history
  • Loading branch information
0x0ece committed Apr 6, 2024
1 parent 2e338f4 commit aaaf958
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 76 deletions.
33 changes: 17 additions & 16 deletions anchor/tests/devnet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ describe("glam_devnet", () => {

const fundName = "Glam Investment Fund BTC-SOL";
const fundSymbol = "GBS";
let shareClassMetadata = {
name: fundName,
symbol: fundSymbol,
shareClassAsset: "USDC",
shareClassAssetId: usdc,
isin: "XS1082172823",
status: "open",
feeManagement: 15000, // 10_000 * 0.015,
feePerformance: 100000, // 10_000 * 0.1,
policyDistribution: "accumulating",
extension: "",
launchDate: "2024-04-01",
lifecycle: "active",
};

const [fundPDA, fundBump] = PublicKey.findProgramAddressSync(
[
anchor.utils.bytes.utf8.encode("fund"),
Expand All @@ -88,22 +103,8 @@ describe("glam_devnet", () => {
[anchor.utils.bytes.utf8.encode("share-0"), fundPDA.toBuffer()],
program.programId
);
const shareClassMetadata = {
name: fundName,
symbol: fundSymbol,
uri: `https://api.glam.systems/metadata/${sharePDA.toBase58()}`,
shareClassAsset: "USDC",
shareClassAssetId: usdc,
isin: "XS1082172823",
status: "open",
feeManagement: 15000, // 1_000_000 * 0.015,
feePerformance: 100000, // 1_000_000 * 0.1,
policyDistribution: "accumulating",
extension: "",
launchDate: "2024-04-01",
lifecycle: "active",
imageUri: `https://api.glam.systems/image/${sharePDA.toBase58()}.png`
};
shareClassMetadata.uri = `https://api.glam.systems/metadata/${sharePDA.toBase58()}`;
shareClassMetadata.imageUri = `https://api.glam.systems/image/${sharePDA.toBase58()}.png`;

// treasury
const treasuryUsdcAta = getAssociatedTokenAddressSync(
Expand Down
54 changes: 27 additions & 27 deletions anchor/tests/glam_crud.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,33 +117,33 @@ describe("glam_crud", () => {
expect(fund.isActive).toEqual(true);
});

it("Update fund", async () => {
const newFundName = "Updated fund name";
await program.methods
.update(newFundName, null, null, false)
.accounts({
fund: fundPDA,
manager: manager.publicKey
})
.rpc({ commitment });
const fund = await program.account.fund.fetch(fundPDA);
expect(fund.name).toEqual(newFundName);
expect(fund.isActive).toEqual(false);
});

it("Close fund", async () => {
await program.methods
.close()
.accounts({
fund: fundPDA,
manager: manager.publicKey
})
.rpc();

// The account should no longer exist, returning null.
const closedAccount = await program.account.fund.fetchNullable(fundPDA);
expect(closedAccount).toBeNull();
});
// it("Update fund", async () => {
// const newFundName = "Updated fund name";
// await program.methods
// .update(newFundName, null, null, false)
// .accounts({
// fund: fundPDA,
// manager: manager.publicKey
// })
// .rpc({ commitment });
// const fund = await program.account.fund.fetch(fundPDA);
// expect(fund.name).toEqual(newFundName);
// expect(fund.isActive).toEqual(false);
// });

// it("Close fund", async () => {
// await program.methods
// .close()
// .accounts({
// fund: fundPDA,
// manager: manager.publicKey
// })
// .rpc();

// // The account should no longer exist, returning null.
// const closedAccount = await program.account.fund.fetchNullable(fundPDA);
// expect(closedAccount).toBeNull();
// });

/*
it('Before any fund - create test assets', async () => {
Expand Down
10 changes: 9 additions & 1 deletion web/src/app/cluster/cluster-ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,23 @@ export function ExplorerLink({
path,
label,
className,
explorer,
}: {
path: string;
label: string;
className?: string;
explorer?: string;
}) {
const { getExplorerUrl } = useCluster();
let href = getExplorerUrl(path);
if (explorer == "solana.fm") {
href = href
.replace("explorer.solana.com", "solana.fm")
.replace("cluster=devnet", "cluster=devnet-alpha");
}
return (
<a
href={getExplorerUrl(path)}
href={href}
target="_blank"
rel="noopener noreferrer"
className={className ? className : `link font-mono`}
Expand Down
188 changes: 182 additions & 6 deletions web/src/app/glam/glam-data-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ import {
AccountMeta,
PublicKey
} from "@solana/web3.js";
import {
getDriftStateAccountPublicKey,
getUserAccountPublicKey,
getUserStatsAccountPublicKey,
getDriftSignerPublicKey,
} from "@drift-labs/sdk";
import { GlamIDL, getGlamProgramId } from "@glam/anchor";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { useMutation, useQuery } from "@tanstack/react-query";
Expand Down Expand Up @@ -174,6 +180,13 @@ export function useGlamProgramAccount({ fundKey }: { fundKey: PublicKey }) {
"HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J"
);

const DRIFT_PROGRAM_ID = new PublicKey(
"dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH"
);
const spotMarketAccountUsdc = new PublicKey("GXWqPpjQpdz7KZw9p7f5PX2eGxHAhvpNXiviFkAB8zXg");
const driftSpotSol = new PublicKey("3x85u7SWkmmr7YQGYhtjARgxwegTLJgkSLRprfXod6rh");
const driftSpotUsdc = new PublicKey("6gMq3mRCKf8aP3ttTyYhuijVZ2LGi14oDsBbkgubfLB3");

const account = useQuery({
queryKey: ["glam", "fetch", { fundKey }],
queryFn: () => program.account.fund.fetch(fundKey)
Expand Down Expand Up @@ -392,18 +405,167 @@ export function useGlamProgramAccount({ fundKey }: { fundKey: PublicKey }) {
}
});

/* Drift */

const driftDeposit = useMutation({
mutationKey: ["glam", "driftDeposit", { fundKey }],
mutationFn: async (mutationData: any) => {
const { fund, asset, amount } = mutationData;
const signer = wallet.publicKey;
if (!signer) {
throw Error("Wallet not connected");
}

const treasuryPDA = fund.treasury;
const treasuryUsdcAta = getAssociatedTokenAddressSync(
usdc,
treasuryPDA,
true,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);

const userAccountPublicKey = await getUserAccountPublicKey(
DRIFT_PROGRAM_ID,
treasuryPDA,
0
);
const userStatsAccountPublicKey = await getUserStatsAccountPublicKey(
DRIFT_PROGRAM_ID,
treasuryPDA
);
const statePublicKey = await getDriftStateAccountPublicKey(
DRIFT_PROGRAM_ID,
);

let remainingAccountsDeposit = [
{ pubkey: pricingSol, isSigner: false, isWritable: false },
{ pubkey: pricingUsdc, isSigner: false, isWritable: false },
{ pubkey: driftSpotSol, isSigner: false, isWritable: true },
{ pubkey: driftSpotUsdc, isSigner: false, isWritable: true },
];

return program.methods
.driftDeposit(amount)
.accounts({
fund: fundKey,
treasury: treasuryPDA,
treasuryAta: treasuryUsdcAta,
driftAta: spotMarketAccountUsdc,
userStats: userStatsAccountPublicKey,
user: userAccountPublicKey,
state: statePublicKey,
manager: signer,
driftProgram: DRIFT_PROGRAM_ID,
tokenProgram: TOKEN_PROGRAM_ID,
})
.remainingAccounts(remainingAccountsDeposit)
.rpc();
},
onSuccess: (tx) => {
console.log(tx);
transactionToast(tx);
return accounts.refetch();
},
onError: (e) => {
console.error("Failed to deposit: ", e);
return toast.error("Failed to deposit");
}
});

const driftWithdraw = useMutation({
mutationKey: ["glam", "driftWithdraw", { fundKey }],
mutationFn: async (mutationData: any) => {
const { fund, asset, amount } = mutationData;
const signer = wallet.publicKey;
if (!signer) {
throw Error("Wallet not connected");
}

const treasuryPDA = fund.treasury;
const treasuryAta = getAssociatedTokenAddressSync(
asset,
treasuryPDA,
true,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);

// treasury
const treasuryUsdcAta = getAssociatedTokenAddressSync(
usdc,
treasuryPDA,
true,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);

const userAccountPublicKey = await getUserAccountPublicKey(
DRIFT_PROGRAM_ID,
treasuryPDA,
0
);
const userStatsAccountPublicKey = await getUserStatsAccountPublicKey(
DRIFT_PROGRAM_ID,
treasuryPDA
);
const statePublicKey = await getDriftStateAccountPublicKey(
DRIFT_PROGRAM_ID,
);
const signerPublicKey = await getDriftSignerPublicKey(
DRIFT_PROGRAM_ID,
);

let remainingAccountsWithdraw = [
{ pubkey: pricingUsdc, isSigner: false, isWritable: false },
{ pubkey: pricingSol, isSigner: false, isWritable: false },
{ pubkey: driftSpotUsdc, isSigner: false, isWritable: true },
{ pubkey: driftSpotSol, isSigner: false, isWritable: true },
];

return program.methods
.driftWithdraw(amount)
.accounts({
fund: fundKey,
treasury: treasuryPDA,
treasuryAta: treasuryUsdcAta,
driftAta: spotMarketAccountUsdc,
userStats: userStatsAccountPublicKey,
user: userAccountPublicKey,
state: statePublicKey,
manager: signer,
driftSigner: signerPublicKey,
driftProgram: DRIFT_PROGRAM_ID,
tokenProgram: TOKEN_PROGRAM_ID,
})
.remainingAccounts(remainingAccountsWithdraw)
.rpc();
},
onSuccess: (tx) => {
console.log(tx);
transactionToast(tx);
return accounts.refetch();
},
onError: (e) => {
console.error("Failed to withdraw: ", e);
return toast.error("Failed to withdraw");
}
});

return {
account,
subscribe,
redeem
redeem,
driftDeposit,
driftWithdraw,
};
}

export function getTotalShares(shareClassAddress: PublicKey) {
const { connection } = useConnection();
const { data } = useQuery({
queryKey: ["get-total-shares", shareClassAddress],
queryFn: async () => {
const connection = new Connection(clusterApiUrl("devnet"));
try {
const mintInfo = await getMint(
connection,
Expand All @@ -415,18 +577,18 @@ export function getTotalShares(shareClassAddress: PublicKey) {
} catch (e) {
console.error(e);
}
return 1.0;
return 0.0;
}
});

return data;
}

export function getAum(treasuryAddress: string) {
export function getAum(treasuryAddress: string, shareClassAddress: PublicKey) {
const { connection } = useConnection();
const { data } = useQuery({
queryKey: ["get-aum-in-treasury", treasuryAddress],
queryFn: async () => {
const connection = new Connection(clusterApiUrl("devnet"));
try {
const filters: GetProgramAccountsFilter[] = [
{
Expand All @@ -446,6 +608,20 @@ export function getAum(treasuryAddress: string) {
console.log(
`Found ${accounts.length} token account(s) in treasury ${treasuryAddress}`
);

let totalShares = 0.0;
try {
const mintInfo = await getMint(
connection,
shareClassAddress,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
totalShares = Number(mintInfo.supply) / 1e9;
} catch (e) {
console.error(e);
}

let aum = 0.0;
const response = await fetch("https://api.glam.systems/prices");
const { btc, usdc, sol } = await response.json();
Expand Down Expand Up @@ -474,7 +650,7 @@ export function getAum(treasuryAddress: string) {
console.log(`Unknown mint address: ${mintAddress}`);
}
});
return aum;
return { aum, totalShares };
} catch (e) {
console.error(e);
}
Expand Down
Loading

0 comments on commit aaaf958

Please sign in to comment.