diff --git a/anchor/programs/glam/src/instructions/investor.rs b/anchor/programs/glam/src/instructions/investor.rs index 96028d7a..d6a9e318 100644 --- a/anchor/programs/glam/src/instructions/investor.rs +++ b/anchor/programs/glam/src/instructions/investor.rs @@ -16,56 +16,9 @@ use crate::state::*; fn log_decimal(amount: u64, minus_decimals: i32) -> f64 { amount as f64 * 10f64.powf(minus_decimals as f64) } -fn log_price(price: Price) -> f64 { +fn _log_price(price: Price) -> f64 { price.price as f64 * 10f64.powf(price.expo as f64) } -#[cfg(feature = "mainnet")] -fn check_pricing_account(asset: &str, pricing_account: &str) -> bool { - match asset { - // usdc - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" => { - pricing_account == "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD" - } - // sol - "So11111111111111111111111111111111111111112" => { - pricing_account == "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG" - } - // btc - "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh" => { - pricing_account == "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU" - } - // eth - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" => { - pricing_account == "JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB" - } - _ => false, - } -} -#[cfg(feature = "devnet")] -fn check_pricing_account(asset: &str, pricing_account: &str) -> bool { - match asset { - // usdc - "8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2" => { - pricing_account == "5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7" - } - // sol - "So11111111111111111111111111111111111111112" => { - pricing_account == "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix" - } - // btc - "3BZPwbcqB5kKScF3TEXxwNfx5ipV13kbRVDvfVp5c6fv" => { - pricing_account == "HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J" - } - "Ff5JqsAYUD4vAfQUtfRprT4nXu9e28tTBZTDFMnJNdvd" => { - pricing_account == "EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw" - } - _ => false, - } -} -#[cfg(not(any(feature = "mainnet", feature = "devnet")))] -fn check_pricing_account(_asset: &str, _pricing_account: &str) -> bool { - true -} #[derive(Accounts)] pub struct Subscribe<'info> { @@ -240,13 +193,6 @@ pub fn subscribe_handler<'c: 'info, 'info>( */ if i == asset_idx { - require!( - check_pricing_account( - &ctx.accounts.asset.key().to_string(), - &pricing_account.to_account_info().key().to_string(), - ), - InvestorError::InvalidPricingOracle - ); subscribe_asset_price = asset_price; subscribe_asset_expo = asset_expo; } diff --git a/anchor/programs/glam/src/state/assets.rs b/anchor/programs/glam/src/state/assets.rs index f60b07d8..42af9944 100644 --- a/anchor/programs/glam/src/state/assets.rs +++ b/anchor/programs/glam/src/state/assets.rs @@ -19,6 +19,7 @@ impl<'a> AssetInfo<'a> { } } +#[cfg(not(feature = "mainnet"))] static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { // wSOL "So11111111111111111111111111111111111111112" => @@ -29,7 +30,35 @@ static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { staking_state: "", }, // USDC - // "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" => + "8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2" => + AssetInfo { + decimals: 6, + is_stable_coin: true, + pyth_account: "5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7", + staking_state: "", + }, + // BTC (Drift) + "3BZPwbcqB5kKScF3TEXxwNfx5ipV13kbRVDvfVp5c6fv" => + AssetInfo { + decimals: 8, + is_stable_coin: false, + pyth_account: "HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J", + staking_state: "", + }, + // Marinade staked SOL (mSOL) + "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" => + AssetInfo { + decimals: 9, + is_stable_coin: false, + pyth_account: "E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9", + staking_state: "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC", + }, + + // + // LOCALNET + // + + // USDC "AwRP1kuJbykXeF4hcLzfMDMY2ZTGN3cx8ErCWxVYekef" => AssetInfo { decimals: 6, @@ -37,7 +66,43 @@ static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { pyth_account: "5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7", staking_state: "", }, - // USDT (TODO) + // BTC + "7Pz5yQdyQm64WtzxvpQZi3nD1q5mbxj4Hhcjy2kmZ7Zd" => + AssetInfo { + decimals: 8, + is_stable_coin: false, + pyth_account: "HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J", + staking_state: "", + }, + // ETH + "GRxagtBNxzjwxkKdEgW7P1oqU57Amai6ha5F3UBJzU1m" => + AssetInfo { + decimals: 8, + is_stable_coin: false, + pyth_account: "EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw", + staking_state: "", + }, +}; + +#[cfg(feature = "mainnet")] +static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { + // wSOL + "So11111111111111111111111111111111111111112" => + AssetInfo { + decimals: 9, + is_stable_coin: false, + pyth_account: "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG", + staking_state: "", + }, + // USDC + "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" => + AssetInfo { + decimals: 6, + is_stable_coin: true, + pyth_account: "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", + staking_state: "", + }, + // USDT "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" => AssetInfo { decimals: 6, @@ -45,7 +110,7 @@ static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { pyth_account: "3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL", staking_state: "", }, - // PYUSD (TODO) + // PYUSD "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo" => AssetInfo { decimals: 6, @@ -54,15 +119,14 @@ static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { staking_state: "", }, // BTC (Portal) - // "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh" => - "7Pz5yQdyQm64WtzxvpQZi3nD1q5mbxj4Hhcjy2kmZ7Zd" => + "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh" => AssetInfo { decimals: 8, is_stable_coin: false, - pyth_account: "HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J", + pyth_account: "Eavb8FKNoYPbHnSS8kMi4tnUh8qK8bqxTjCojer4pZrr", staking_state: "", }, - // tBTC (TODO) + // tBTC "6DNSN2BJsaPFdFFc1zP37kkeNe4Usc1Sqkzr9C9vPWcU" => AssetInfo { decimals: 8, @@ -71,12 +135,11 @@ static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { staking_state: "", }, // ETH (Portal) - // "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" => - "GRxagtBNxzjwxkKdEgW7P1oqU57Amai6ha5F3UBJzU1m" => + "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" => AssetInfo { decimals: 8, is_stable_coin: false, - pyth_account: "EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw", + pyth_account: "JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB", staking_state: "", }, // PYTH @@ -104,86 +167,3 @@ static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { staking_state: "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC", }, }; - -// static ASSETS: phf::Map<&'static str, AssetInfo> = phf_map! { -// // wSOL -// "So11111111111111111111111111111111111111112" => -// AssetInfo { -// decimals: 9, -// is_stable_coin: false, -// pyth_account: "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG", -// staking_state: "", -// }, -// // USDC -// "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" => -// AssetInfo { -// decimals: 6, -// is_stable_coin: true, -// pyth_account: "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", -// staking_state: "", -// }, -// // USDT -// "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" => -// AssetInfo { -// decimals: 6, -// is_stable_coin: true, -// pyth_account: "3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL", -// staking_state: "", -// }, -// // PYUSD -// "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo" => -// AssetInfo { -// decimals: 6, -// is_stable_coin: true, -// pyth_account: "", -// staking_state: "", -// }, -// // BTC (Portal) -// "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh" => -// AssetInfo { -// decimals: 8, -// is_stable_coin: false, -// pyth_account: "Eavb8FKNoYPbHnSS8kMi4tnUh8qK8bqxTjCojer4pZrr", -// staking_state: "", -// }, -// // tBTC -// "6DNSN2BJsaPFdFFc1zP37kkeNe4Usc1Sqkzr9C9vPWcU" => -// AssetInfo { -// decimals: 8, -// is_stable_coin: false, -// pyth_account: "6qCHPXxQiCiM3dEE4W6fpZk17uSZW9WBpD7cyN8Tg2Ac", -// staking_state: "", -// }, -// // ETH (Portal) -// "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" => -// AssetInfo { -// decimals: 8, -// is_stable_coin: false, -// pyth_account: "JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB", -// staking_state: "", -// }, -// // PYTH -// "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3" => -// AssetInfo { -// decimals: 6, -// is_stable_coin: false, -// pyth_account: "nrYkQQQur7z8rYTST3G9GqATviK5SxTDkrqd21MW6Ue", -// staking_state: "", -// }, -// // BONK -// "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" => -// AssetInfo { -// decimals: 5, -// is_stable_coin: false, -// pyth_account: "8ihFLu5FimgTQ1Unh4dVyEHUGodJ5gJQCrQf4KUVB9bN", -// staking_state: "", -// }, -// // Marinade staked SOL (mSOL) -// "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" => -// AssetInfo { -// decimals: 9, -// is_stable_coin: false, -// pyth_account: "E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9", -// staking_state: "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC", -// }, -// }; diff --git a/anchor/src/client/base.ts b/anchor/src/client/base.ts index ed3fe0de..8eab5054 100644 --- a/anchor/src/client/base.ts +++ b/anchor/src/client/base.ts @@ -8,7 +8,6 @@ import { import { BlockhashWithExpiryBlockHeight, ComputeBudgetProgram, - ConfirmOptions, Connection, Keypair, PublicKey, @@ -23,8 +22,9 @@ import { } from "@solana/spl-token"; import { Glam, GlamIDL, GlamProgram, getGlamProgramId } from "../glamExports"; -import { GlamClientConfig } from "../clientConfig"; +import { ClusterOrCustom, GlamClientConfig } from "../clientConfig"; import { FundModel, FundOpenfundsModel } from "../models"; +import { AssetMeta, ASSETS_DEVNET, ASSETS_MAINNET } from "./assets"; type FundAccount = IdlAccounts["fundAccount"]; type FundMetadataAccount = IdlAccounts["fundMetadataAccount"]; @@ -32,13 +32,15 @@ type FundMetadataAccount = IdlAccounts["fundMetadataAccount"]; export const JUPITER_API_DEFAULT = "https://quote-api.jup.ag/v6"; export class BaseClient { + cluster: ClusterOrCustom; provider: anchor.Provider; program: GlamProgram; programId: PublicKey; jupiterApi: string; public constructor(config?: GlamClientConfig) { - this.programId = getGlamProgramId(config?.cluster || "devnet"); + this.cluster = config?.cluster || "devnet"; + this.programId = getGlamProgramId(this.cluster); if (config?.provider) { this.provider = config.provider; this.program = new Program( @@ -66,6 +68,18 @@ export class BaseClient { this.jupiterApi = config?.jupiterApi || JUPITER_API_DEFAULT; } + isMainnet(): boolean { + return this.cluster === "mainnet-beta"; + } + + getAssetMeta(asset: string): AssetMeta { + return ( + (this.isMainnet() + ? ASSETS_MAINNET.get(asset) + : ASSETS_DEVNET.get(asset)) || new AssetMeta() + ); + } + latestBlockhash?: BlockhashWithExpiryBlockHeight; async getLatestBlockhash(): Promise { if (this.latestBlockhash !== undefined) { diff --git a/anchor/src/client/investor.ts b/anchor/src/client/investor.ts index dcf98d97..b5b26f51 100644 --- a/anchor/src/client/investor.ts +++ b/anchor/src/client/investor.ts @@ -23,92 +23,6 @@ import { import { BaseClient } from "./base"; -class Asset { - pricingAccount: PublicKey = new PublicKey(""); - programId?: PublicKey; -} - -const ASSETS_DEVNET: Map = new Map([ - // wSOL - [ - "So11111111111111111111111111111111111111112", - { - pricingAccount: new PublicKey( - "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix" // pyth - ) - } - ], - // USDC - [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - { - pricingAccount: new PublicKey( - "5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7" // pyth - ) - } - ], - // BTC - [ - "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", - { - pricingAccount: new PublicKey( - "HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J" // pyth - ) - } - ], - // ETH - [ - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - { - pricingAccount: new PublicKey( - "EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw" // pyth - ) - } - ], - // mSOL - [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - { - pricingAccount: new PublicKey( - "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC" // state - ) - } - ], - - // - // LOCALNET - // - - // USDC - [ - "AwRP1kuJbykXeF4hcLzfMDMY2ZTGN3cx8ErCWxVYekef", - { - pricingAccount: new PublicKey( - "5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7" // pyth - ) - } - ], - // BTC - [ - "7Pz5yQdyQm64WtzxvpQZi3nD1q5mbxj4Hhcjy2kmZ7Zd", - { - pricingAccount: new PublicKey( - "HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J" // pyth - ), - programId: TOKEN_2022_PROGRAM_ID - } - ], - // ETH - [ - "GRxagtBNxzjwxkKdEgW7P1oqU57Amai6ha5F3UBJzU1m", - { - pricingAccount: new PublicKey( - "EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw" // pyth - ) - } - ] -]); - export class InvestorClient { public constructor(readonly base: BaseClient) {} @@ -152,7 +66,7 @@ export class InvestorClient { ): Promise { const shareClass = this.base.getShareClassPDA(fund, shareClassId); const signerShareAta = this.base.getShareClassAta(signer, shareClass); - const assetMeta = ASSETS_DEVNET.get(asset.toBase58()); + const assetMeta = this.base.getAssetMeta(asset.toBase58()); const treasuryAta = this.base.getTreasuryAta( fund, asset, @@ -167,7 +81,7 @@ export class InvestorClient { const fundModel = await this.base.fetchFund(fund); const remainingAccounts = (fundModel.assets || []).flatMap((asset) => { - const assetMeta = ASSETS_DEVNET.get(asset.toBase58()) || new Asset(); + const assetMeta = this.base.getAssetMeta(asset.toBase58()); const treasuryAta = this.base.getTreasuryAta( fund, asset, diff --git a/anchor/src/clientConfig.ts b/anchor/src/clientConfig.ts index 131cb5be..a03d6b91 100644 --- a/anchor/src/clientConfig.ts +++ b/anchor/src/clientConfig.ts @@ -4,6 +4,7 @@ import { Cluster } from "@solana/web3.js"; export type ClusterOrCustom = Cluster | "custom"; export type GlamClientConfig = { + mainnet?: boolean; provider?: Provider; cluster?: ClusterOrCustom; jupiterApi?: string; diff --git a/api/src/main.ts b/api/src/main.ts index c16932ae..b74df649 100644 --- a/api/src/main.ts +++ b/api/src/main.ts @@ -47,6 +47,7 @@ const mainnetProvider = new AnchorProvider(mainnetConnection, null, { commitment: "confirmed" }); const mainnetClient = new GlamClient({ + cluster: "mainnet-beta", provider: mainnetProvider, jupiterApi: JUPITER_API });