From 15be1b9ebaf392e3d7f0fd836519725db43a1c88 Mon Sep 17 00:00:00 2001 From: crustydev Date: Thu, 6 Apr 2023 11:47:17 +0100 Subject: [PATCH 1/5] Move SunriseStakeConfig to Config.ts and define SunriseTokenConfig --- packages/client/src/blaze.ts | 2 +- packages/client/src/index.ts | 2 +- packages/client/src/lock.ts | 2 +- packages/client/src/marinade.ts | 2 +- packages/client/src/types/Config.ts | 23 +++++++++++++++++++++++ packages/client/src/util.ts | 15 +-------------- 6 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 packages/client/src/types/Config.ts diff --git a/packages/client/src/blaze.ts b/packages/client/src/blaze.ts index df341874..0d0be49f 100644 --- a/packages/client/src/blaze.ts +++ b/packages/client/src/blaze.ts @@ -10,10 +10,10 @@ import type BN from "bn.js"; import { findBSolTokenAccountAuthority, findGSolMintAuthority, - type SunriseStakeConfig, } from "./util"; import { STAKE_POOL_PROGRAM_ID } from "./constants"; import { type AnchorProvider, type Program, utils } from "@coral-xyz/anchor"; +import { type SunriseStakeConfig } from "./types/Config"; import { type SunriseStake } from "./types/sunrise_stake"; import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { type BlazeState } from "./types/Solblaze"; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 56c77b02..6678514a 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -24,7 +24,6 @@ import { PROGRAM_ID, proportionalBN, setUpAnchor, - type SunriseStakeConfig, ZERO, ZERO_BALANCE, toSol, @@ -38,6 +37,7 @@ import { type MarinadeState, } from "@sunrisestake/marinade-ts-sdk"; import BN from "bn.js"; +import { type SunriseStakeConfig } from "./types/Config"; import { type Balance, type Details, diff --git a/packages/client/src/lock.ts b/packages/client/src/lock.ts index f92055d2..9aca3d27 100644 --- a/packages/client/src/lock.ts +++ b/packages/client/src/lock.ts @@ -5,7 +5,6 @@ import { findLockAccount, findLockTokenAccount, getTokenAccountNullable, - type SunriseStakeConfig, } from "./util"; import { ComputeBudgetProgram, @@ -15,6 +14,7 @@ import { type Transaction, type TransactionInstruction, } from "@solana/web3.js"; +import { type SunriseStakeConfig } from "./types/Config"; import { type LockAccount } from "./types/LockAccount"; import * as anchor from "@coral-xyz/anchor"; import { diff --git a/packages/client/src/marinade.ts b/packages/client/src/marinade.ts index 6078f2af..57a40712 100644 --- a/packages/client/src/marinade.ts +++ b/packages/client/src/marinade.ts @@ -15,7 +15,6 @@ import { findMSolTokenAccountAuthority, findOrderUnstakeTicketAccount, getValidatorIndex, - type SunriseStakeConfig, } from "./util"; import { type Marinade, @@ -23,6 +22,7 @@ import { MarinadeUtils, } from "@sunrisestake/marinade-ts-sdk"; import { type Program, utils } from "@coral-xyz/anchor"; +import { type SunriseStakeConfig } from "./types/Config"; import { type BlazeState } from "./types/Solblaze"; import { type SunriseStake } from "./types/sunrise_stake"; import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; diff --git a/packages/client/src/types/Config.ts b/packages/client/src/types/Config.ts new file mode 100644 index 00000000..db99df2e --- /dev/null +++ b/packages/client/src/types/Config.ts @@ -0,0 +1,23 @@ +import { type PublicKey } from "@solana/web3.js"; +import { type Options } from "../util"; + +export interface SunriseStakeConfig { + stateAddress: PublicKey; + gsolMint: PublicKey; + treasury: PublicKey; + updateAuthority: PublicKey; + programId: PublicKey; + liqPoolProportion: number; + liqPoolMinProportion: number; + options: Options; + impactNFTStateAddress: PublicKey | undefined; // a state can exist without an impact nft state +} + +export interface SunriseTokenConfig { + gsolMintAuthority: [PublicKey, number]; + msolTokenAccount: PublicKey; + msolTokenAccountAuthority: [PublicKey, number]; + bsolTokenAccount: PublicKey; + bsolTokenAccountAuthority: [PublicKey, number]; + liqPoolTokenAccount: PublicKey; +} diff --git a/packages/client/src/util.ts b/packages/client/src/util.ts index f50ce626..98b1018f 100644 --- a/packages/client/src/util.ts +++ b/packages/client/src/util.ts @@ -14,6 +14,7 @@ import { Provider, type Wallet, } from "@sunrisestake/marinade-ts-sdk"; +import { type SunriseStakeConfig } from "./types/Config"; import { type Details } from "./types/Details"; import { type EnvironmentConfig, MAX_NUM_PRECISION } from "./constants"; import { @@ -51,20 +52,6 @@ export const enum ProgramDerivedAddressSeed { IMPACT_NFT_MINT_ACCOUNT = "impact_nft_mint_account", } -export interface SunriseStakeConfig { - stateAddress: PublicKey; - gsolMint: PublicKey; - treasury: PublicKey; - updateAuthority: PublicKey; - programId: PublicKey; - liqPoolProportion: number; - - liqPoolMinProportion: number; - - options: Options; - impactNFTStateAddress: PublicKey | undefined; // a state can exist without an impact nft state -} - // Return the type of an element in an array // type A = ArrayElement; // string // type B = ArrayElement; // string From e6299a371a4709ca2223cdc17b59e715bf9efa59 Mon Sep 17 00:00:00 2001 From: crustydev Date: Thu, 6 Apr 2023 11:54:04 +0100 Subject: [PATCH 2/5] Add Marinade addresses to EnvironmentConfig --- packages/client/src/constants.ts | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/client/src/constants.ts b/packages/client/src/constants.ts index 5f503572..0fdb4ac4 100644 --- a/packages/client/src/constants.ts +++ b/packages/client/src/constants.ts @@ -21,6 +21,12 @@ interface BlazeConfig { bsolMint: PublicKey; } +interface MarinadeConfig { + stateAddress: PublicKey; + msolMintAddress: PublicKey; + lpMintAddress: PublicKey; +} + export interface EnvironmentConfig { state: PublicKey; holdingAccount: PublicKey; @@ -30,6 +36,7 @@ export interface EnvironmentConfig { impactNFT: { state: PublicKey | undefined; // if undefined, impact nft is disabled }; + marinade: MarinadeConfig; } export const Environment: Record< WalletAdapterNetwork | "localnet", @@ -51,6 +58,17 @@ export const Environment: Record< impactNFT: { state: new PublicKey("6RzCneyeEqnjiWxrzqfBwHDEpTrbcSkBFFUrtMZnNjpc"), }, + marinade: { + stateAddress: new PublicKey( + "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC" + ), + msolMintAddress: new PublicKey( + "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" + ), + lpMintAddress: new PublicKey( + "LPmSozJJ8Jh69ut2WP3XmVohTjL4ipR18yiCzxrUmVj" + ), + }, }, // TODO placeholders testnet: { @@ -67,6 +85,17 @@ export const Environment: Record< impactNFT: { state: PublicKey.default, // TODO }, + marinade: { + stateAddress: new PublicKey( + "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC" + ), + msolMintAddress: new PublicKey( + "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" + ), + lpMintAddress: new PublicKey( + "LPmSozJJ8Jh69ut2WP3XmVohTjL4ipR18yiCzxrUmVj" + ), + }, }, devnet: { state: new PublicKey("Jpp29FzyV7rXdVRWFaiE9tBcVCaEMvj16gk87rC3S4z"), @@ -84,6 +113,17 @@ export const Environment: Record< impactNFT: { state: new PublicKey("6iyfwPbbLeYAoUcQkECCPwftFuw3j5VEcXF7xcQeAdX6"), }, + marinade: { + stateAddress: new PublicKey( + "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC" + ), + msolMintAddress: new PublicKey( + "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" + ), + lpMintAddress: new PublicKey( + "LPmSozJJ8Jh69ut2WP3XmVohTjL4ipR18yiCzxrUmVj" + ), + }, }, localnet: { state: new PublicKey("28SkW4iD7UJc9zkxcq6yNb1MFX2hxqdJjxjZs67Jwr2b"), @@ -101,6 +141,17 @@ export const Environment: Record< impactNFT: { state: PublicKey.default, // TODO }, + marinade: { + stateAddress: new PublicKey( + "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC" + ), + msolMintAddress: new PublicKey( + "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" + ), + lpMintAddress: new PublicKey( + "LPmSozJJ8Jh69ut2WP3XmVohTjL4ipR18yiCzxrUmVj" + ), + }, }, }; From 249c7e3f0ce673775448296e4da46a8fde092b26 Mon Sep 17 00:00:00 2001 From: crustydev Date: Thu, 6 Apr 2023 12:56:38 +0100 Subject: [PATCH 3/5] Refactor client to use tokenConfig --- packages/client/src/index.ts | 283 +++++++++++++++----------------- packages/tests/sunrise-stake.ts | 2 +- packages/tests/util.ts | 6 +- 3 files changed, 133 insertions(+), 158 deletions(-) diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 6678514a..37714154 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -37,7 +37,10 @@ import { type MarinadeState, } from "@sunrisestake/marinade-ts-sdk"; import BN from "bn.js"; -import { type SunriseStakeConfig } from "./types/Config"; +import { + type SunriseStakeConfig, + type SunriseTokenConfig, +} from "./types/Config"; import { type Balance, type Details, @@ -99,6 +102,7 @@ export { toSol, findImpactNFTMintAuthority, ZERO_BALANCE } from "./util"; export class SunriseStakeClient { readonly program: Program; config: SunriseStakeConfig | undefined; + tokenConfig: SunriseTokenConfig | undefined; // TODO make private once all functions are moved in here marinade: Marinade | undefined; @@ -108,15 +112,7 @@ export class SunriseStakeClient { readonly staker: PublicKey; stakerGSolTokenAccount: PublicKey | undefined; - msolTokenAccountAuthority: PublicKey | undefined; - msolTokenAccount: PublicKey | undefined; - - bsolTokenAccountAuthority: PublicKey | undefined; - bsolTokenAccount: PublicKey | undefined; - blazeState: BlazeState | undefined; - - liqPoolTokenAccount: PublicKey | undefined; lockClient: LockClient | undefined; readonly env: EnvironmentConfig; @@ -148,10 +144,14 @@ export class SunriseStakeClient { this.env.state ); - const stakePoolInfo = await getStakePoolAccount( - this.provider.connection, - this.env.blaze.pool - ); + this.stakerGSolTokenAccount = PublicKey.findProgramAddressSync( + [ + this.staker.toBuffer(), + TOKEN_PROGRAM_ID.toBuffer(), + sunriseStakeState.gsolMint.toBuffer(), + ], + ASSOCIATED_TOKEN_PROGRAM_ID + )[0]; this.config = { gsolMint: sunriseStakeState.gsolMint, @@ -164,54 +164,87 @@ export class SunriseStakeClient { impactNFTStateAddress: this.env.impactNFT.state, options: this.options, }; + this.tokenConfig = await this.getTokenConfig(this.config); - this.stakerGSolTokenAccount = PublicKey.findProgramAddressSync( - [ - this.staker.toBuffer(), - TOKEN_PROGRAM_ID.toBuffer(), - sunriseStakeState.gsolMint.toBuffer(), - ], - ASSOCIATED_TOKEN_PROGRAM_ID - )[0]; - const [gsolMintAuthority] = findGSolMintAuthority(this.config); - this.msolTokenAccountAuthority = findMSolTokenAccountAuthority( - this.config - )[0]; - this.bsolTokenAccountAuthority = findBSolTokenAccountAuthority( - this.config - )[0]; + [this.marinade, this.marinadeState] = await this.makeMarinade(); + + this.blazeState = await this.makeBlaze(); + + this.lockClient = await LockClient.build( + this.config, + this.program, + this.staker + ); + } + + private async getTokenConfig( + config: SunriseStakeConfig + ): Promise { + const gsolMintAuthority = findGSolMintAuthority(config); + + const msolTokenAccountAuthority = findMSolTokenAccountAuthority(config); + const msolTokenAccount = await utils.token.associatedAddress({ + mint: this.env.marinade.msolMintAddress, + owner: msolTokenAccountAuthority[0], + }); + + const liqPoolTokenAccount = await utils.token.associatedAddress({ + mint: this.env.marinade.lpMintAddress, + owner: msolTokenAccountAuthority[0], + }); + + const bsolTokenAccountAuthority = findBSolTokenAccountAuthority(config); + const bsolTokenAccount = await utils.token.associatedAddress({ + mint: this.env.blaze.bsolMint, + owner: bsolTokenAccountAuthority[0], + }); + + return { + gsolMintAuthority, + msolTokenAccount, + msolTokenAccountAuthority, + liqPoolTokenAccount, + bsolTokenAccount, + bsolTokenAccountAuthority, + }; + } + + private async makeMarinade(): Promise<[Marinade, MarinadeState]> { + if (!this.config || !this.tokenConfig) throw new Error("Init not called"); const marinadeConfig = new MarinadeConfig({ connection: this.provider.connection, publicKey: this.provider.publicKey, proxyStateAddress: this.env.state, - proxySolMintAuthority: gsolMintAuthority, + proxySolMintAuthority: this.tokenConfig.gsolMintAuthority[0], proxySolMintAddress: this.config.gsolMint, - msolTokenAccountAuthority: this.msolTokenAccountAuthority, + msolTokenAccountAuthority: this.tokenConfig.msolTokenAccountAuthority[0], proxyTreasury: this.config.treasury, }); - this.marinade = new Marinade(marinadeConfig); - this.marinadeState = await this.marinade.getMarinadeState(); - this.msolTokenAccount = await utils.token.associatedAddress({ - mint: this.marinadeState.mSolMintAddress, - owner: this.msolTokenAccountAuthority, - }); - this.liqPoolTokenAccount = await utils.token.associatedAddress({ - mint: this.marinadeState.lpMint.address, - owner: this.msolTokenAccountAuthority, - }); + + const marinade = new Marinade(marinadeConfig); + const marinadeState = await marinade.getMarinadeState(); + + return [marinade, marinadeState]; + } + + // TODO + private async makeBlaze(): Promise { + const stakePoolInfo = await getStakePoolAccount( + this.provider.connection, + this.env.blaze.pool + ); const [withdrawAuthority] = PublicKey.findProgramAddressSync( [this.env.blaze.pool.toBuffer(), Buffer.from("withdraw")], STAKE_POOL_PROGRAM_ID ); - const [depositAuthority] = PublicKey.findProgramAddressSync( [this.env.blaze.pool.toBuffer(), Buffer.from("deposit")], STAKE_POOL_PROGRAM_ID ); - this.blazeState = { + return { pool: this.env.blaze.pool, bsolMint: stakePoolInfo.poolMint, validatorList: stakePoolInfo.validatorList, @@ -221,17 +254,6 @@ export class SunriseStakeClient { withdrawAuthority, depositAuthority, }; - - this.bsolTokenAccount = await utils.token.associatedAddress({ - mint: stakePoolInfo.poolMint, - owner: this.bsolTokenAccountAuthority, - }); - - this.lockClient = await LockClient.build( - this.config, - this.program, - this.staker - ); } public async sendAndConfirmTransaction( @@ -473,7 +495,6 @@ export class SunriseStakeClient { !this.marinadeState || !this.marinade || !this.config || - !this.msolTokenAccount || !this.stakerGSolTokenAccount || !this.blazeState ) @@ -504,8 +525,7 @@ export class SunriseStakeClient { !this.marinadeState || !this.marinade || !this.config || - !this.msolTokenAccount || - !this.bsolTokenAccount || + !this.tokenConfig || !this.stakerGSolTokenAccount || !this.blazeState ) @@ -573,13 +593,13 @@ export class SunriseStakeClient { liqPoolSolLegPda: await this.marinadeState.solLeg(), liqPoolMsolLeg: this.marinadeState.mSolLeg, liqPoolMsolLegAuthority: await this.marinadeState.mSolLegAuthority(), - liqPoolTokenAccount: this.liqPoolTokenAccount, + liqPoolTokenAccount: this.tokenConfig.liqPoolTokenAccount, reservePda: await this.marinadeState.reserveAddress(), treasuryMsolAccount: this.marinadeState.treasuryMsolAccount, - getMsolFrom: this.msolTokenAccount, - getMsolFromAuthority: this.msolTokenAccountAuthority, - getBsolFrom: this.bsolTokenAccount, - getBsolFromAuthority: this.bsolTokenAccountAuthority, + getMsolFrom: this.tokenConfig.msolTokenAccount, + getMsolFromAuthority: this.tokenConfig.msolTokenAccountAuthority[0], + getBsolFrom: this.tokenConfig.bsolTokenAccount, + getBsolFromAuthority: this.tokenConfig.bsolTokenAccountAuthority[0], epochReportAccount: epochReportAccountAddress, systemProgram: SystemProgram.programId, tokenProgram: TOKEN_PROGRAM_ID, @@ -602,7 +622,6 @@ export class SunriseStakeClient { !this.marinadeState || !this.marinade || !this.config || - !this.msolTokenAccount || !this.stakerGSolTokenAccount ) throw new Error("init not called"); @@ -686,12 +705,12 @@ export class SunriseStakeClient { !this.marinadeState || !this.marinade || !this.config || - !this.msolTokenAccount + !this.tokenConfig ) throw new Error("init not called"); const { transaction, newTicketAccount, proxyTicketAccount } = - await this.marinade.orderUnstake(lamports, this.msolTokenAccount); + await this.marinade.orderUnstake(lamports, this.tokenConfig.msolTokenAccount); Boolean(this.config?.options.verbose) && logKeys(transaction); @@ -744,7 +763,7 @@ export class SunriseStakeClient { public async claimUnstakeTicket( ticketAccount: TicketAccount ): Promise { - if (!this.marinade || !this.marinadeState) + if (!this.marinade || !this.marinadeState || !this.tokenConfig) throw new Error("init not called"); const reservePda = await this.marinadeState.reserveAddress(); @@ -760,7 +779,7 @@ export class SunriseStakeClient { reservePda, marinadeTicketAccount: ticketAccount.marinadeTicketAccount, sunriseTicketAccount: ticketAccount.address, - msolAuthority: this.msolTokenAccountAuthority, + msolAuthority: this.tokenConfig.msolTokenAccountAuthority[0], transferSolTo: this.staker, systemProgram: SystemProgram.programId, clock: SYSVAR_CLOCK_PUBKEY, @@ -781,8 +800,7 @@ export class SunriseStakeClient { if ( !this.blazeState || !this.config || - !this.stakerGSolTokenAccount || - !this.bsolTokenAccount + !this.stakerGSolTokenAccount ) throw new Error("init not called"); @@ -806,8 +824,7 @@ export class SunriseStakeClient { if ( !this.blazeState || !this.config || - !this.stakerGSolTokenAccount || - !this.bsolTokenAccount + !this.stakerGSolTokenAccount ) throw new Error("init not called"); @@ -832,9 +849,7 @@ export class SunriseStakeClient { !this.blazeState || !this.marinade || !this.config || - !this.msolTokenAccount || - !this.msolTokenAccountAuthority || - !this.liqPoolTokenAccount + !this.tokenConfig ) { throw new Error("init not called"); } @@ -857,12 +872,12 @@ export class SunriseStakeClient { liqPoolMint: this.marinadeState.lpMint.address, liqPoolSolLegPda, liqPoolMsolLeg: this.marinadeState.mSolLeg, - liqPoolTokenAccount: this.liqPoolTokenAccount, + liqPoolTokenAccount: this.tokenConfig.liqPoolTokenAccount, treasuryMsolAccount: this.marinadeState.treasuryMsolAccount, - getMsolFrom: this.msolTokenAccount, - getMsolFromAuthority: this.msolTokenAccountAuthority, - getBsolFrom: this.bsolTokenAccount, - getBsolFromAuthority: this.bsolTokenAccountAuthority, + getMsolFrom: this.tokenConfig.msolTokenAccount, + getMsolFromAuthority: this.tokenConfig.msolTokenAccountAuthority[0], + getBsolFrom: this.tokenConfig.bsolTokenAccount, + getBsolFromAuthority: this.tokenConfig.bsolTokenAccountAuthority[0], epochReportAccount: epochReportAccountAddress, treasury: this.config.treasury, systemProgram: SystemProgram.programId, @@ -893,9 +908,7 @@ export class SunriseStakeClient { !this.blazeState || !this.marinade || !this.config || - !this.msolTokenAccount || - !this.msolTokenAccountAuthority || - !this.liqPoolTokenAccount + !this.tokenConfig ) { throw new Error("init not called"); } @@ -920,12 +933,12 @@ export class SunriseStakeClient { liqPoolMint: this.marinadeState.lpMint.address, liqPoolSolLegPda, liqPoolMsolLeg: this.marinadeState.mSolLeg, - liqPoolTokenAccount: this.liqPoolTokenAccount, + liqPoolTokenAccount: this.tokenConfig.liqPoolTokenAccount, treasuryMsolAccount: this.marinadeState.treasuryMsolAccount, - getMsolFrom: this.msolTokenAccount, - getMsolFromAuthority: this.msolTokenAccountAuthority, - getBsolFrom: this.bsolTokenAccount, - getBsolFromAuthority: this.bsolTokenAccountAuthority, + getMsolFrom: this.tokenConfig.msolTokenAccount, + getMsolFromAuthority: this.tokenConfig.msolTokenAccountAuthority[0], + getBsolFrom: this.tokenConfig.bsolTokenAccount, + getBsolFromAuthority: this.tokenConfig.bsolTokenAccountAuthority[0], epochReportAccount, treasury: this.config.treasury, systemProgram: SystemProgram.programId, @@ -1052,7 +1065,7 @@ export class SunriseStakeClient { if ( !this.marinadeState || !this.stakerGSolTokenAccount || - !this.msolTokenAccount || + !this.tokenConfig || !this.config ) throw new Error("init not called"); @@ -1202,8 +1215,8 @@ export class SunriseStakeClient { programId: this.config.programId.toBase58(), stateAddress: this.config.stateAddress.toBase58(), treasury: this.config.treasury.toBase58(), - msolTokenAccount: this.msolTokenAccount.toBase58(), - msolTokenAccountAuthority: this.msolTokenAccountAuthority?.toBase58(), + msolTokenAccount: this.tokenConfig.msolTokenAccount.toBase58(), + msolTokenAccountAuthority: this.tokenConfig.msolTokenAccountAuthority[0].toBase58(), }, marinadeFinanceProgramId: this.marinadeState.marinadeFinanceProgramId.toBase58(), @@ -1282,29 +1295,13 @@ export class SunriseStakeClient { const marinadeState = await new Marinade(marinadeConfig).getMarinadeState(); - const [, gsolMintAuthorityBump] = findGSolMintAuthority(config); + const tokenAccounts = await this.getTokenConfig(config); const [msolAuthority, msolAuthorityBump] = - findMSolTokenAccountAuthority(config); - const msolAssociatedTokenAccountAddress = - await utils.token.associatedAddress({ - mint: marinadeState.mSolMintAddress, - owner: msolAuthority, - }); - // use the same token authority PDA for the msol token account - // and the liquidity pool token account for convenience - const liqPoolAssociatedTokenAccountAddress = - await utils.token.associatedAddress({ - mint: marinadeState.lpMint.address, - owner: msolAuthority, - }); - + tokenAccounts.msolTokenAccountAuthority; const [bsolAuthority, bsolAuthorityBump] = - findBSolTokenAccountAuthority(config); - const bsolTokenAccountAddress = await utils.token.associatedAddress({ - mint: this.env.blaze.bsolMint, - owner: bsolAuthority, - }); + tokenAccounts.bsolTokenAccountAuthority; + const gsolMintAuthorityBump = tokenAccounts.gsolMintAuthority[1]; type Accounts = Parameters< ReturnType["accounts"] @@ -1317,11 +1314,11 @@ export class SunriseStakeClient { msolMint: marinadeState.mSolMintAddress, bsolMint: this.env.blaze.bsolMint, msolTokenAccountAuthority: msolAuthority, - msolTokenAccount: msolAssociatedTokenAccountAddress, + msolTokenAccount: tokenAccounts.msolTokenAccount, liqPoolMint: marinadeState.lpMint.address, - liqPoolTokenAccount: liqPoolAssociatedTokenAccountAddress, + liqPoolTokenAccount: tokenAccounts.liqPoolTokenAccount, bsolTokenAccountAuthority: bsolAuthority, - bsolTokenAccount: bsolTokenAccountAddress, + bsolTokenAccount: tokenAccounts.bsolTokenAccount, systemProgram: SystemProgram.programId, tokenProgram: TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, @@ -1350,7 +1347,7 @@ export class SunriseStakeClient { epochReport, bpDetails, }: Omit): BN { - if (!this.marinadeState || !this.msolTokenAccount) + if (!this.marinadeState) throw new Error("init not called"); // deposited in Stake Pool @@ -1448,8 +1445,14 @@ export class SunriseStakeClient { } public async balance(): Promise { - if (!this.marinadeState || !this.stakerGSolTokenAccount || !this.config) + if ( + !this.config || + !this.tokenConfig || + !this.marinadeState || + !this.stakerGSolTokenAccount + ) throw new Error("init not called"); + const gsolBalancePromise = this.provider.connection .getTokenAccountBalance(this.stakerGSolTokenAccount) .catch((e) => { @@ -1460,57 +1463,29 @@ export class SunriseStakeClient { throw e; }); - const gsolSupplyPromise = this.provider.connection.getTokenSupply( - this.config.gsolMint - ); - - const msolTokenAccountAuthority = findMSolTokenAccountAuthority( - this.config - )[0]; - const msolAssociatedTokenAccountAddress = - await utils.token.associatedAddress({ - mint: this.marinadeState.mSolMintAddress, - owner: msolTokenAccountAuthority, - }); + const gsolSupplyPromise = this.provider.connection.getTokenSupply( + this.config.gsolMint + ); + const msolLamportsBalancePromise = this.provider.connection.getTokenAccountBalance( - msolAssociatedTokenAccountAddress - ); - - const bsolTokenAccountAuthority = findBSolTokenAccountAuthority( - this.config - )[0]; - const bsolAssociatedTokenAccountAddress = - await utils.token.associatedAddress({ - mint: this.env.blaze.bsolMint, - owner: bsolTokenAccountAuthority, - }); + this.tokenConfig.msolTokenAccount + ); const bsolLamportsBalancePromise = this.provider.connection.getTokenAccountBalance( - bsolAssociatedTokenAccountAddress - ); - - // use the same token authority PDA for the msol token account - // and the liquidity pool token account for convenience - const liqPoolAssociatedTokenAccountAddress = - await utils.token.associatedAddress({ - mint: this.marinadeState.lpMint.address, - owner: msolTokenAccountAuthority, - }); - + this.tokenConfig.bsolTokenAccount + ); const liqPoolBalancePromise = this.provider.connection.getTokenAccountBalance( - liqPoolAssociatedTokenAccountAddress - ); - + this.tokenConfig.liqPoolTokenAccount + ); const treasuryBalancePromise = this.provider.connection.getBalance( this.config.treasury ); - const holdingAccountBalancePromise = this.provider.connection.getBalance( this.env.holdingAccount ); - + const [ gsolBalance, gsolSupply, @@ -1528,7 +1503,7 @@ export class SunriseStakeClient { bsolLamportsBalancePromise, holdingAccountBalancePromise, ]); - + return { gsolBalance: gsolBalance.value, gsolSupply: gsolSupply.value, diff --git a/packages/tests/sunrise-stake.ts b/packages/tests/sunrise-stake.ts index dfbd758b..30d1f211 100644 --- a/packages/tests/sunrise-stake.ts +++ b/packages/tests/sunrise-stake.ts @@ -676,7 +676,7 @@ describe("sunrise-stake", () => { const liqPoolBalance = await client.provider.connection.getTokenAccountBalance( - client.liqPoolTokenAccount! + client.tokenConfig!.liqPoolTokenAccount ); await client.sendAndConfirmTransaction( diff --git a/packages/tests/util.ts b/packages/tests/util.ts index d62ef9c3..c6bff9e9 100644 --- a/packages/tests/util.ts +++ b/packages/tests/util.ts @@ -98,7 +98,7 @@ export const expectMSolTokenBalance = async ( tolerance = 0 // Allow for a tolerance as the msol calculation is inaccurate. The test uses the price which has limited precision ) => { const msolBalance = await client.provider.connection.getTokenAccountBalance( - client.msolTokenAccount! + client.tokenConfig!.msolTokenAccount ); log("mSOL balance", msolBalance.value.amount); expectAmount(new BN(msolBalance.value.amount), expectedAmount, tolerance); @@ -110,7 +110,7 @@ export const expectBSolTokenBalance = async ( tolerance = 0 ) => { const bsolBalance = await client.provider.connection.getTokenAccountBalance( - client.bsolTokenAccount! + client.tokenConfig!.bsolTokenAccount ); expectAmount(new BN(bsolBalance.value.amount), expectedAmount, tolerance); }; @@ -122,7 +122,7 @@ export const expectLiqPoolTokenBalance = async ( ) => { const liqPoolBalance = await client.provider.connection.getTokenAccountBalance( - client.liqPoolTokenAccount! + client.tokenConfig!.liqPoolTokenAccount ); log("LiqPool balance", liqPoolBalance.value.amount); log("Expected amount", expectedAmount); From d4bf5469ca080ef2b3f2d162feaeb57e5f88bcbc Mon Sep 17 00:00:00 2001 From: crustydev Date: Thu, 6 Apr 2023 13:34:38 +0100 Subject: [PATCH 4/5] Split details() --- packages/client/src/constants.ts | 4 + packages/client/src/index.ts | 163 ++++++++++++++++++------------- 2 files changed, 100 insertions(+), 67 deletions(-) diff --git a/packages/client/src/constants.ts b/packages/client/src/constants.ts index 0fdb4ac4..764a9893 100644 --- a/packages/client/src/constants.ts +++ b/packages/client/src/constants.ts @@ -16,6 +16,10 @@ export const IMPACT_NFT_PROGRAM_ID = new PublicKey( "SUNFT6ErsQvMcDzMcGyndq2P31wYCFs6G6WEcoyGkGc" ); +export const MARINADE_PROGRAM_ID = new PublicKey( + "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD" +); + interface BlazeConfig { pool: PublicKey; bsolMint: PublicKey; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 37714154..c93da375 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -10,6 +10,7 @@ import { SYSVAR_CLOCK_PUBKEY, Transaction, type TransactionInstruction, + type EpochInfo, } from "@solana/web3.js"; import { confirm, @@ -65,6 +66,7 @@ import { NETWORK_FEE, SOLBLAZE_ENABLED, STAKE_POOL_PROGRAM_ID, + MARINADE_PROGRAM_ID, } from "./constants"; import { deposit, @@ -1061,64 +1063,67 @@ export class SunriseStakeClient { }; } - public async details(): Promise
{ - if ( - !this.marinadeState || - !this.stakerGSolTokenAccount || - !this.tokenConfig || - !this.config - ) - throw new Error("init not called"); - - const currentEpochPromise = this.provider.connection.getEpochInfo(); + private async getEpochDetails(): Promise<{ + currentEpoch: EpochInfo; + epochReport: EpochReportAccount; + }> { + if (!this.config) throw new Error("Init not called"); - const lpMintInfoPromise = this.marinadeState.lpMint.mintInfo(); - const lpMsolBalancePromise = - this.provider.connection.getTokenAccountBalance( - this.marinadeState.mSolLeg - ); + const currentEpoch = await this.provider.connection.getEpochInfo(); + const { account: epochReport } = await getEpochReportAccount( + this.config, + this.program + ); - const solLeg = await this.marinadeState.solLeg(); - const solLegBalancePromise = this.provider.connection.getBalance(solLeg); + return { + currentEpoch, + epochReport: epochReport ?? EMPTY_EPOCH_REPORT, + }; + } - const balancesPromise = this.balance(); + private async getMpDetails(): Promise { + // TODO: Return undefined. Don't error + if (!this.marinadeState) throw new Error("Marinade not initialized"); - const lockAccountPromise = await this.getLockAccount(); + const balance = await this.balance(); - const impactNFTPromise = await getImpactNFT( - this.config, - this.staker, - this.provider + const solValueOfMSol = this.computeLamportsFromMSol( + new BN(balance.msolBalance.amount), + this.marinadeState ); - const [ - currentEpoch, - lpMintInfo, - lpSolLegBalance, - lpMsolBalance, - balances, - lockAccountDetails, - impactNFT, - ] = await Promise.all([ - currentEpochPromise, - lpMintInfoPromise, - solLegBalancePromise, - lpMsolBalancePromise, - balancesPromise, - lockAccountPromise, - impactNFTPromise, - ]); + return { + msolPrice: this.marinadeState.mSolPrice, + msolValue: solValueOfMSol, + stakeDelta: this.marinadeState.stakeDelta().toNumber(), + }; + } - const availableLiqPoolSolLegBalance = new BN(lpSolLegBalance).sub( - this.marinadeState.state.rentExemptForTokenAcc + private async getLpDetails(balance: Balance): Promise { + // TODO: Return undefined. Don't error + if (!this.marinadeState) throw new Error("Marinade not initialized"); + + const lpMintInfo = await this.marinadeState.lpMint.mintInfo(); + + const lpMsolBalance = await this.provider.connection.getTokenAccountBalance( + this.marinadeState.mSolLeg ); + const lpMsolShare = proportionalBN( - new BN(balances.liqPoolBalance.amount), + new BN(balance.liqPoolBalance.amount), new BN(lpMsolBalance.value.amount), new BN(lpMintInfo.supply.toString()) ); + + const solLeg = await this.marinadeState.solLeg(); + const lpSolLegBalance = await this.provider.connection.getBalance(solLeg); + + const availableLiqPoolSolLegBalance = new BN(lpSolLegBalance).sub( + this.marinadeState.state.rentExemptForTokenAcc + ); + const lpSolShare = proportionalBN( - new BN(balances.liqPoolBalance.amount), + new BN(balance.liqPoolBalance.amount), availableLiqPoolSolLegBalance, new BN(lpMintInfo.supply.toString()) ); @@ -1129,18 +1134,7 @@ export class SunriseStakeClient { const lpSolValue = lpSolShare.add(solValueOlpMSolShare); - const solValueOfMSol = this.computeLamportsFromMSol( - new BN(balances.msolBalance.amount), - this.marinadeState - ); - - const mpDetails = { - msolPrice: this.marinadeState.mSolPrice, - msolValue: solValueOfMSol, - stakeDelta: this.marinadeState.stakeDelta().toNumber(), - }; - - const lpDetails = { + return { mintAddress: this.marinadeState.lpMint.address.toBase58(), supply: lpMintInfo.supply, mintAuthority: lpMintInfo.mintAuthority?.toBase58(), @@ -1150,22 +1144,27 @@ export class SunriseStakeClient { lpSolValue, // total SOL value of the LP tokens held by the sunrise instance msolLeg: this.marinadeState.mSolLeg.toBase58(), }; + } - const { account: epochReport } = await getEpochReportAccount( - this.config, - this.program - ); + private async getBpDetails(): Promise { + if (!this.config || !this.tokenConfig) throw new Error("Init not called"); const stakePoolInfo = await getStakePoolAccount( this.provider.connection, this.env.blaze.pool ); + + const bsolLamportsBalance = + await this.provider.connection.getTokenAccountBalance( + this.tokenConfig.bsolTokenAccount + ); + const [bsolPrice, bsolValue] = this.computeLamportsFromBSol( - new BN(balances.bsolBalance.amount), + new BN(bsolLamportsBalance.value.amount), stakePoolInfo ); - const bpDetails = { + return { pool: this.env.blaze.pool.toString(), bsolPrice, bsolValue, @@ -1174,6 +1173,10 @@ export class SunriseStakeClient { denominator: stakePoolInfo.solWithdrawalFee.denominator, }, }; + } + + private async getLockDetails(): Promise { + const lockAccountDetails = await this.getLockAccount(); const lockDetails: Details["lockDetails"] = lockAccountDetails.lockAccount && @@ -1192,6 +1195,18 @@ export class SunriseStakeClient { } : undefined; + return lockDetails; + } + + private async getImpactNFTDetails(): Promise { + if (!this.config) throw new Error("Init not called"); + + const impactNFT = await getImpactNFT( + this.config, + this.staker, + this.provider + ); + const nftSummary = this.config.impactNFTStateAddress ? { stateAddress: this.config.impactNFTStateAddress, @@ -1204,11 +1219,26 @@ export class SunriseStakeClient { ? nftSummary : undefined; + return impactNFTDetails; + } + + public async details(): Promise
{ + if (!this.config || !this.tokenConfig || !this.stakerGSolTokenAccount) + throw new Error("Init not called"); + + const epochDetails = await this.getEpochDetails(); + const balances = await this.balance(); + const mpDetails = await this.getMpDetails(); + const lpDetails = await this.getLpDetails(balances); + const bpDetails = await this.getBpDetails(); + const lockDetails = await this.getLockDetails(); + const impactNFTDetails = await this.getImpactNFTDetails(); + const detailsWithoutYield: Omit = { staker: this.staker.toBase58(), + currentEpoch: epochDetails.currentEpoch, + epochReport: epochDetails.epochReport, balances, - currentEpoch, - epochReport: epochReport ?? EMPTY_EPOCH_REPORT, stakerGSolTokenAccount: this.stakerGSolTokenAccount.toBase58(), sunriseStakeConfig: { gsolMint: this.config.gsolMint.toBase58(), @@ -1218,9 +1248,8 @@ export class SunriseStakeClient { msolTokenAccount: this.tokenConfig.msolTokenAccount.toBase58(), msolTokenAccountAuthority: this.tokenConfig.msolTokenAccountAuthority[0].toBase58(), }, - marinadeFinanceProgramId: - this.marinadeState.marinadeFinanceProgramId.toBase58(), - marinadeStateAddress: this.marinadeState.marinadeStateAddress.toBase58(), + marinadeFinanceProgramId: MARINADE_PROGRAM_ID.toBase58(), + marinadeStateAddress: this.env.marinade.stateAddress.toBase58(), mpDetails, lpDetails, bpDetails, From b848c4b46345960f386c4dcfc9aa719a3fcb0352 Mon Sep 17 00:00:00 2001 From: crustydev Date: Thu, 6 Apr 2023 13:48:39 +0100 Subject: [PATCH 5/5] Yarn lint --- packages/client/src/blaze.ts | 5 +-- packages/client/src/index.ts | 59 +++++++++++++++++------------------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/packages/client/src/blaze.ts b/packages/client/src/blaze.ts index 0d0be49f..54d31cb0 100644 --- a/packages/client/src/blaze.ts +++ b/packages/client/src/blaze.ts @@ -7,10 +7,7 @@ import { type Transaction, } from "@solana/web3.js"; import type BN from "bn.js"; -import { - findBSolTokenAccountAuthority, - findGSolMintAuthority, -} from "./util"; +import { findBSolTokenAccountAuthority, findGSolMintAuthority } from "./util"; import { STAKE_POOL_PROGRAM_ID } from "./constants"; import { type AnchorProvider, type Program, utils } from "@coral-xyz/anchor"; import { type SunriseStakeConfig } from "./types/Config"; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index c93da375..8cd6596b 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -38,9 +38,9 @@ import { type MarinadeState, } from "@sunrisestake/marinade-ts-sdk"; import BN from "bn.js"; -import { - type SunriseStakeConfig, - type SunriseTokenConfig, +import { + type SunriseStakeConfig, + type SunriseTokenConfig, } from "./types/Config"; import { type Balance, @@ -712,7 +712,10 @@ export class SunriseStakeClient { throw new Error("init not called"); const { transaction, newTicketAccount, proxyTicketAccount } = - await this.marinade.orderUnstake(lamports, this.tokenConfig.msolTokenAccount); + await this.marinade.orderUnstake( + lamports, + this.tokenConfig.msolTokenAccount + ); Boolean(this.config?.options.verbose) && logKeys(transaction); @@ -799,11 +802,7 @@ export class SunriseStakeClient { } public async withdrawFromBlaze(amount: BN): Promise { - if ( - !this.blazeState || - !this.config || - !this.stakerGSolTokenAccount - ) + if (!this.blazeState || !this.config || !this.stakerGSolTokenAccount) throw new Error("init not called"); const withdrawIx = await blazeWithdrawSol( @@ -823,11 +822,7 @@ export class SunriseStakeClient { newStakeAccount: PublicKey, amount: BN ): Promise { - if ( - !this.blazeState || - !this.config || - !this.stakerGSolTokenAccount - ) + if (!this.blazeState || !this.config || !this.stakerGSolTokenAccount) throw new Error("init not called"); const withdrawStakeIx = await blazeWithdrawStake( @@ -1195,7 +1190,7 @@ export class SunriseStakeClient { } : undefined; - return lockDetails; + return lockDetails; } private async getImpactNFTDetails(): Promise { @@ -1246,7 +1241,8 @@ export class SunriseStakeClient { stateAddress: this.config.stateAddress.toBase58(), treasury: this.config.treasury.toBase58(), msolTokenAccount: this.tokenConfig.msolTokenAccount.toBase58(), - msolTokenAccountAuthority: this.tokenConfig.msolTokenAccountAuthority[0].toBase58(), + msolTokenAccountAuthority: + this.tokenConfig.msolTokenAccountAuthority[0].toBase58(), }, marinadeFinanceProgramId: MARINADE_PROGRAM_ID.toBase58(), marinadeStateAddress: this.env.marinade.stateAddress.toBase58(), @@ -1376,8 +1372,7 @@ export class SunriseStakeClient { epochReport, bpDetails, }: Omit): BN { - if (!this.marinadeState) - throw new Error("init not called"); + if (!this.marinadeState) throw new Error("init not called"); // deposited in Stake Pool const solValueOfMSol = mpDetails.msolValue; @@ -1477,11 +1472,11 @@ export class SunriseStakeClient { if ( !this.config || !this.tokenConfig || - !this.marinadeState || + !this.marinadeState || !this.stakerGSolTokenAccount ) throw new Error("init not called"); - + const gsolBalancePromise = this.provider.connection .getTokenAccountBalance(this.stakerGSolTokenAccount) .catch((e) => { @@ -1492,29 +1487,29 @@ export class SunriseStakeClient { throw e; }); - const gsolSupplyPromise = this.provider.connection.getTokenSupply( - this.config.gsolMint - ); - + const gsolSupplyPromise = this.provider.connection.getTokenSupply( + this.config.gsolMint + ); + const msolLamportsBalancePromise = this.provider.connection.getTokenAccountBalance( - this.tokenConfig.msolTokenAccount - ); + this.tokenConfig.msolTokenAccount + ); const bsolLamportsBalancePromise = this.provider.connection.getTokenAccountBalance( - this.tokenConfig.bsolTokenAccount - ); + this.tokenConfig.bsolTokenAccount + ); const liqPoolBalancePromise = this.provider.connection.getTokenAccountBalance( - this.tokenConfig.liqPoolTokenAccount - ); + this.tokenConfig.liqPoolTokenAccount + ); const treasuryBalancePromise = this.provider.connection.getBalance( this.config.treasury ); const holdingAccountBalancePromise = this.provider.connection.getBalance( this.env.holdingAccount ); - + const [ gsolBalance, gsolSupply, @@ -1532,7 +1527,7 @@ export class SunriseStakeClient { bsolLamportsBalancePromise, holdingAccountBalancePromise, ]); - + return { gsolBalance: gsolBalance.value, gsolSupply: gsolSupply.value,