Skip to content

Commit 35c40e3

Browse files
refactor(types): extract portfolio-Solana slice into portfolio.ts
Moves SolanaBalance, SolanaPortfolioSlice, SolanaStakingPositionSlice, SolanaMarginfiPositionSlice, and SolanaKaminoPositionSlice out of index.ts into portfolio.ts, byte-identical and source-order preserved. index.ts's remaining SolanaPortfolioSlice references (PortfolioSummary, MultiWalletPortfolioSummary) now come via import type from "./portfolio.js". Part of #717.
1 parent ffdee0e commit 35c40e3

2 files changed

Lines changed: 134 additions & 134 deletions

File tree

src/types/index.ts

Lines changed: 1 addition & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type {
77
StakingPosition,
88
TokenAmount,
99
} from "./positions.js";
10-
import type { PortfolioCoverage } from "./portfolio.js";
10+
import type { PortfolioCoverage, SolanaPortfolioSlice } from "./portfolio.js";
1111

1212
export * from "./chains.js";
1313

@@ -37,139 +37,6 @@ export interface TronBalance {
3737
priceMissing?: boolean;
3838
}
3939

40-
/**
41-
* Solana balance shape — a parallel to TronBalance for SOL + SPL tokens.
42-
* `token` is a base58 SPL mint address (~32-44 chars), or "native" for SOL.
43-
* SPL balances come from Associated Token Accounts but we surface them by
44-
* mint; the ATA is an implementation detail the caller shouldn't care about.
45-
*/
46-
export interface SolanaBalance {
47-
chain: "solana";
48-
/** Base58 SPL mint address, or "native" for SOL. */
49-
token: string;
50-
symbol: string;
51-
decimals: number;
52-
amount: string;
53-
formatted: string;
54-
valueUsd?: number;
55-
priceUsd?: number;
56-
priceMissing?: boolean;
57-
}
58-
59-
/**
60-
* Solana slice of a portfolio summary. Parallel to TronPortfolioSlice.
61-
* Phase 1 did not enumerate native validator staking; Phase 3 adds
62-
* MarginFi lending.
63-
*/
64-
export interface SolanaPortfolioSlice {
65-
/** Base58 Solana address the balances were resolved for. */
66-
address: string;
67-
native: SolanaBalance[];
68-
spl: SolanaBalance[];
69-
walletBalancesUsd: number;
70-
/**
71-
* MarginFi lending positions (Phase 3). Present only when the wallet has
72-
* at least one MarginfiAccount with non-zero balances — probed via the
73-
* deterministic PDA at accountIndex 0..3. An empty/missing field means
74-
* no MarginFi position, not "reader errored" (errored case is surfaced
75-
* through PortfolioCoverage.marginfi).
76-
*/
77-
marginfi?: SolanaMarginfiPositionSlice[];
78-
/** MarginFi aggregate net USD (sum of netValueUsd across positions). */
79-
marginfiNetUsd?: number;
80-
/**
81-
* Kamino lending positions on the main market. Present when the wallet
82-
* has Kamino userMetadata + obligation with non-zero deposits or borrows.
83-
* Empty/missing means no position; errored case surfaces through
84-
* PortfolioCoverage.kamino.
85-
*/
86-
kamino?: SolanaKaminoPositionSlice[];
87-
/** Kamino aggregate net USD (sum of netValueUsd across positions). */
88-
kaminoNetUsd?: number;
89-
/**
90-
* Solana staking positions — Marinade mSOL, Jito jitoSOL, native stake
91-
* accounts. Present when any of the three sections is non-empty for
92-
* this wallet. Missing means nothing found (errored case surfaces
93-
* through PortfolioCoverage.solanaStaking).
94-
*/
95-
staking?: SolanaStakingPositionSlice;
96-
/** Solana staking aggregate net USD (SOL-equivalent × SOL price). */
97-
stakingNetUsd?: number;
98-
}
99-
100-
/**
101-
* Thin projection of the three staking readers' output
102-
* (`src/modules/positions/solana-staking.ts`). Kept in sync with
103-
* `SolanaStakingPositions` but stripped down — the portfolio JSON doesn't
104-
* need the per-reader wrapper metadata (wallet duplication, protocol
105-
* tags on subtotals).
106-
*/
107-
export interface SolanaStakingPositionSlice {
108-
chain: "solana";
109-
/** mSOL balance + SOL-equivalent via Marinade's on-chain mSolPrice. */
110-
marinade: {
111-
mSolBalance: number;
112-
solEquivalent: number;
113-
exchangeRate: number;
114-
};
115-
/** jitoSOL balance + SOL-equivalent via stake-pool's totalLamports/supply. */
116-
jito: {
117-
jitoSolBalance: number;
118-
solEquivalent: number;
119-
exchangeRate: number;
120-
};
121-
/** One entry per native stake account (SPL stake-program) with activation status. */
122-
nativeStakes: Array<{
123-
stakePubkey: string;
124-
validator?: string;
125-
stakeSol: number;
126-
status: "activating" | "active" | "deactivating" | "inactive";
127-
activationEpoch?: number;
128-
deactivationEpoch?: number;
129-
}>;
130-
/** Sum of SOL-equivalents across Marinade + Jito + native stakes. */
131-
totalSolEquivalent: number;
132-
}
133-
134-
/**
135-
* Thin projection of the full `MarginfiPosition` type exposed by
136-
* `src/modules/positions/marginfi.ts`. Kept here so the portfolio types
137-
* module doesn't pull in the reader module's internals, matching how
138-
* CompoundLendingPosition / MorphoLendingPosition are projections of their
139-
* reader modules.
140-
*/
141-
export interface SolanaMarginfiPositionSlice {
142-
protocol: "marginfi";
143-
chain: "solana";
144-
marginfiAccount: string;
145-
supplied: Array<{ symbol: string; amount: string; valueUsd: number }>;
146-
borrowed: Array<{ symbol: string; amount: string; valueUsd: number }>;
147-
totalSuppliedUsd: number;
148-
totalBorrowedUsd: number;
149-
netValueUsd: number;
150-
healthFactor: number;
151-
warnings: string[];
152-
}
153-
154-
/**
155-
* Thin projection of the full `KaminoPosition` type exposed by
156-
* `src/modules/positions/kamino.ts`. Same shape as MarginFi's slice; the
157-
* `obligation` field is Kamino's per-(wallet, market, kind) state account
158-
* (analogous to `marginfiAccount`).
159-
*/
160-
export interface SolanaKaminoPositionSlice {
161-
protocol: "kamino";
162-
chain: "solana";
163-
obligation: string;
164-
supplied: Array<{ symbol: string; amount: string; valueUsd: number }>;
165-
borrowed: Array<{ symbol: string; amount: string; valueUsd: number }>;
166-
totalSuppliedUsd: number;
167-
totalBorrowedUsd: number;
168-
netValueUsd: number;
169-
healthFactor: number;
170-
warnings: string[];
171-
}
172-
17340
/**
17441
* TRON slice of a portfolio summary. Contains the TRON-specific address the
17542
* balances were fetched for (base58, which can't fit into the `wallet:

src/types/portfolio.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,136 @@ export interface UnpricedAsset {
9494
/** Human-readable balance (already-decimals-applied), e.g. "705.141". */
9595
amount: string;
9696
}
97+
98+
/**
99+
* Solana balance shape — a parallel to TronBalance for SOL + SPL tokens.
100+
* `token` is a base58 SPL mint address (~32-44 chars), or "native" for SOL.
101+
* SPL balances come from Associated Token Accounts but we surface them by
102+
* mint; the ATA is an implementation detail the caller shouldn't care about.
103+
*/
104+
export interface SolanaBalance {
105+
chain: "solana";
106+
/** Base58 SPL mint address, or "native" for SOL. */
107+
token: string;
108+
symbol: string;
109+
decimals: number;
110+
amount: string;
111+
formatted: string;
112+
valueUsd?: number;
113+
priceUsd?: number;
114+
priceMissing?: boolean;
115+
}
116+
117+
/**
118+
* Solana slice of a portfolio summary. Parallel to TronPortfolioSlice.
119+
* Phase 1 did not enumerate native validator staking; Phase 3 adds
120+
* MarginFi lending.
121+
*/
122+
export interface SolanaPortfolioSlice {
123+
/** Base58 Solana address the balances were resolved for. */
124+
address: string;
125+
native: SolanaBalance[];
126+
spl: SolanaBalance[];
127+
walletBalancesUsd: number;
128+
/**
129+
* MarginFi lending positions (Phase 3). Present only when the wallet has
130+
* at least one MarginfiAccount with non-zero balances — probed via the
131+
* deterministic PDA at accountIndex 0..3. An empty/missing field means
132+
* no MarginFi position, not "reader errored" (errored case is surfaced
133+
* through PortfolioCoverage.marginfi).
134+
*/
135+
marginfi?: SolanaMarginfiPositionSlice[];
136+
/** MarginFi aggregate net USD (sum of netValueUsd across positions). */
137+
marginfiNetUsd?: number;
138+
/**
139+
* Kamino lending positions on the main market. Present when the wallet
140+
* has Kamino userMetadata + obligation with non-zero deposits or borrows.
141+
* Empty/missing means no position; errored case surfaces through
142+
* PortfolioCoverage.kamino.
143+
*/
144+
kamino?: SolanaKaminoPositionSlice[];
145+
/** Kamino aggregate net USD (sum of netValueUsd across positions). */
146+
kaminoNetUsd?: number;
147+
/**
148+
* Solana staking positions — Marinade mSOL, Jito jitoSOL, native stake
149+
* accounts. Present when any of the three sections is non-empty for
150+
* this wallet. Missing means nothing found (errored case surfaces
151+
* through PortfolioCoverage.solanaStaking).
152+
*/
153+
staking?: SolanaStakingPositionSlice;
154+
/** Solana staking aggregate net USD (SOL-equivalent × SOL price). */
155+
stakingNetUsd?: number;
156+
}
157+
158+
/**
159+
* Thin projection of the three staking readers' output
160+
* (`src/modules/positions/solana-staking.ts`). Kept in sync with
161+
* `SolanaStakingPositions` but stripped down — the portfolio JSON doesn't
162+
* need the per-reader wrapper metadata (wallet duplication, protocol
163+
* tags on subtotals).
164+
*/
165+
export interface SolanaStakingPositionSlice {
166+
chain: "solana";
167+
/** mSOL balance + SOL-equivalent via Marinade's on-chain mSolPrice. */
168+
marinade: {
169+
mSolBalance: number;
170+
solEquivalent: number;
171+
exchangeRate: number;
172+
};
173+
/** jitoSOL balance + SOL-equivalent via stake-pool's totalLamports/supply. */
174+
jito: {
175+
jitoSolBalance: number;
176+
solEquivalent: number;
177+
exchangeRate: number;
178+
};
179+
/** One entry per native stake account (SPL stake-program) with activation status. */
180+
nativeStakes: Array<{
181+
stakePubkey: string;
182+
validator?: string;
183+
stakeSol: number;
184+
status: "activating" | "active" | "deactivating" | "inactive";
185+
activationEpoch?: number;
186+
deactivationEpoch?: number;
187+
}>;
188+
/** Sum of SOL-equivalents across Marinade + Jito + native stakes. */
189+
totalSolEquivalent: number;
190+
}
191+
192+
/**
193+
* Thin projection of the full `MarginfiPosition` type exposed by
194+
* `src/modules/positions/marginfi.ts`. Kept here so the portfolio types
195+
* module doesn't pull in the reader module's internals, matching how
196+
* CompoundLendingPosition / MorphoLendingPosition are projections of their
197+
* reader modules.
198+
*/
199+
export interface SolanaMarginfiPositionSlice {
200+
protocol: "marginfi";
201+
chain: "solana";
202+
marginfiAccount: string;
203+
supplied: Array<{ symbol: string; amount: string; valueUsd: number }>;
204+
borrowed: Array<{ symbol: string; amount: string; valueUsd: number }>;
205+
totalSuppliedUsd: number;
206+
totalBorrowedUsd: number;
207+
netValueUsd: number;
208+
healthFactor: number;
209+
warnings: string[];
210+
}
211+
212+
/**
213+
* Thin projection of the full `KaminoPosition` type exposed by
214+
* `src/modules/positions/kamino.ts`. Same shape as MarginFi's slice; the
215+
* `obligation` field is Kamino's per-(wallet, market, kind) state account
216+
* (analogous to `marginfiAccount`).
217+
*/
218+
export interface SolanaKaminoPositionSlice {
219+
protocol: "kamino";
220+
chain: "solana";
221+
obligation: string;
222+
supplied: Array<{ symbol: string; amount: string; valueUsd: number }>;
223+
borrowed: Array<{ symbol: string; amount: string; valueUsd: number }>;
224+
totalSuppliedUsd: number;
225+
totalBorrowedUsd: number;
226+
netValueUsd: number;
227+
healthFactor: number;
228+
warnings: string[];
229+
}

0 commit comments

Comments
 (0)