@agentgrant.cash/cli 1.4.3 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/cli/commands/agent.d.ts +8 -0
  2. package/dist/cli/commands/auth.d.ts +20 -0
  3. package/dist/cli/commands/meta.d.ts +2 -0
  4. package/dist/cli/commands/money.d.ts +2 -0
  5. package/dist/cli/commands/onboard.d.ts +2 -0
  6. package/dist/cli/commands/portfolio.d.ts +14 -0
  7. package/dist/cli/index.d.ts +2 -0
  8. package/dist/cli/money-helpers.d.ts +100 -0
  9. package/dist/cli/perfolio-commands/account.d.ts +35 -0
  10. package/dist/cli/perfolio-commands/borrow.d.ts +2 -0
  11. package/dist/cli/perfolio-commands/discover.d.ts +2 -0
  12. package/dist/cli/perfolio-commands/earn.d.ts +9 -0
  13. package/dist/cli/perfolio-commands/hyperliquid.d.ts +32 -0
  14. package/dist/cli/perfolio-commands/loans.d.ts +8 -0
  15. package/dist/cli/perfolio-commands/market.d.ts +11 -0
  16. package/dist/cli/perfolio-commands/polymarket.d.ts +29 -0
  17. package/dist/cli/perfolio-commands/session.d.ts +2 -0
  18. package/dist/cli/perfolio-commands/spending.d.ts +14 -0
  19. package/dist/cli/perfolio-commands/trade.d.ts +2 -0
  20. package/dist/cli/perfolio-commands/tx.d.ts +2 -0
  21. package/dist/lib/agent-client.d.ts +78 -0
  22. package/dist/lib/amounts.d.ts +14 -0
  23. package/dist/lib/assets.d.ts +12 -0
  24. package/dist/lib/auth-session.d.ts +57 -0
  25. package/dist/lib/client.d.ts +295 -0
  26. package/dist/lib/config.d.ts +13 -0
  27. package/dist/lib/context.d.ts +21 -0
  28. package/dist/lib/currency.d.ts +70 -0
  29. package/dist/lib/device.d.ts +78 -0
  30. package/dist/lib/dotenv.d.ts +12 -0
  31. package/dist/lib/errors.d.ts +33 -0
  32. package/dist/lib/format.d.ts +5 -0
  33. package/dist/lib/index.d.ts +22 -0
  34. package/dist/lib/kyc-status.d.ts +10 -0
  35. package/dist/lib/money-client.d.ts +66 -0
  36. package/dist/lib/money-input.d.ts +97 -0
  37. package/dist/lib/output.d.ts +22 -0
  38. package/dist/lib/polygon-balance.d.ts +43 -0
  39. package/dist/lib/portfolio-format.d.ts +79 -0
  40. package/dist/lib/relay.d.ts +8 -0
  41. package/dist/lib/sign.d.ts +11 -0
  42. package/dist/lib/tx-wait.d.ts +19 -0
  43. package/dist/lib/types.d.ts +377 -0
  44. package/dist/lib/verify.d.ts +21 -0
  45. package/package.json +7 -1
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Money INPUT resolution — the safety-critical counterpart to currency.ts
3
+ * (which handles money OUTPUT/display).
4
+ *
5
+ * The backend operates entirely in USD (the "cash" stablecoin ≈ 1 USD, and all
6
+ * trade/borrow/withdraw amounts are USD-denominated decimal strings). But a user
7
+ * thinks in their own currency: an INR user who says "buy ₹50 of gold" means ₹50,
8
+ * NOT $50. Sending the raw number through would overspend by the FX rate (~83×).
9
+ *
10
+ * This module resolves a user-entered amount into a USD decimal string for the
11
+ * backend, with two rules:
12
+ * 1. A bare number is interpreted in the currency the user is *viewing*
13
+ * (their display currency) — local if they view local, else USD.
14
+ * 2. An explicit currency on the amount ("$10", "100 EUR", "₹50") always wins.
15
+ *
16
+ * Hard safety property: if the amount is in a non-USD currency and we cannot get
17
+ * an authoritative FX rate, we THROW rather than guess — a wrong-currency money
18
+ * transaction is never acceptable.
19
+ */
20
+ import { type DisplayPrefs } from './currency.js';
21
+ export interface ParsedMoney {
22
+ amount: number;
23
+ /** Explicit ISO currency the user attached to the amount, if any. */
24
+ currency?: string;
25
+ }
26
+ /**
27
+ * Parse a money input that may carry an explicit currency:
28
+ * "50" "$50" "₹50" "€10.5" "50 INR" "50inr" "usd 10" "$1,234.56"
29
+ * Returns the numeric amount and the explicit currency (uppercased) if present.
30
+ * Throws on anything that isn't a positive number.
31
+ */
32
+ export declare function parseMoneyInput(raw: string): ParsedMoney;
33
+ /** The currency a bare (unitless) amount is assumed to be in — matches what the user sees. */
34
+ export declare function defaultInputCurrency(prefs: DisplayPrefs): string;
35
+ /**
36
+ * Per-transaction USD ceiling — a fat-finger guard, NOT a product limit. Combined
37
+ * with the display-currency default (a bare "100" can mean a large local amount),
38
+ * an un-bounded input is a real over-spend risk, so anything above this is refused
39
+ * with a recoverable error rather than quietly accepted.
40
+ */
41
+ export declare const MAX_CASH_USD = 10000000;
42
+ /**
43
+ * Reject amounts that resolved to dust (rounds to $0 → opaque SWAP_QUOTE_FAILED
44
+ * downstream) or to an implausibly large value (fat-finger). `describe` renders
45
+ * the user's own amount for the message.
46
+ */
47
+ export declare function assertUsdInBounds(usd: number, describe: () => string): void;
48
+ export interface MoneyResolution {
49
+ /** Amount in USD for the backend. */
50
+ usd: number;
51
+ /** USD as a decimal string, rounded to the token's decimals and validated. */
52
+ usdString: string;
53
+ /** The original amount the user typed. */
54
+ sourceAmount: number;
55
+ /** The currency the amount was interpreted in (ISO). */
56
+ sourceCurrency: string;
57
+ /** Local-units-per-USD used for the conversion (1 for USD). */
58
+ rate: number;
59
+ /** True when a non-USD → USD conversion was applied. */
60
+ converted: boolean;
61
+ }
62
+ /**
63
+ * Resolve a user-entered cash amount into a USD decimal string for the backend.
64
+ *
65
+ * `fetchRate(currency)` must return local-units-per-USD for that currency. For any
66
+ * non-USD source currency we ALWAYS fetch an authoritative rate (we never trust a
67
+ * possibly-stale `prefs.rate`, which falls back to 1 when FX is unavailable — and a
68
+ * rate of 1 would silently treat ₹50 as $50). If the rate can't be obtained, we throw.
69
+ */
70
+ export declare function resolveCashToUsd(raw: string, prefs: DisplayPrefs, decimals: number, fetchRate: (currency: string) => Promise<number>): Promise<MoneyResolution>;
71
+ /**
72
+ * Human description of a resolved cash amount — shows the source amount and its
73
+ * USD equivalent when a conversion happened, so the user can see exactly what
74
+ * will be transacted (e.g. "₹50.00 (≈ $0.60)").
75
+ */
76
+ export declare function describeCashResolution(m: MoneyResolution): string;
77
+ export interface CashTargetResolution extends MoneyResolution {
78
+ /** Asset quantity to sell to realize ~the cash target, as a decimal string. */
79
+ quantity: string;
80
+ quantityNum: number;
81
+ /** Live USD unit price used to size the sale. */
82
+ unitPriceUsd: number;
83
+ }
84
+ /**
85
+ * Resolve a cash-denominated SELL target into a quantity of the asset to sell.
86
+ *
87
+ * "Sell ₹100 of gold" means: realize ~₹100 of cash by selling gold. Swaps are
88
+ * exact-input (you specify how much to sell), so we size the sale from the live
89
+ * USD unit price: `quantity = targetUSD / unitPriceUsd`. The result is therefore
90
+ * an approximation of the cash proceeds (slippage/fees move the exact figure) —
91
+ * hence "~₹100 worth", which is what the user means.
92
+ *
93
+ * `unitPriceUsd` is the live USD price per asset unit (gold price/oz for XAUT,
94
+ * BTC price for WBTC, ETH price for WETH, 1 for stables). If it isn't available
95
+ * (≤ 0) we throw rather than guess — a mis-sized money sale is never acceptable.
96
+ */
97
+ export declare function resolveCashTargetToAssetQty(raw: string, prefs: DisplayPrefs, decimals: number, fetchRate: (currency: string) => Promise<number>, unitPriceUsd: number): Promise<CashTargetResolution>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * One output model for both engines. Pretty for humans; a single JSON object per
3
+ * command for agents. JSON mode auto-engages when stdout is not a TTY (an agent
4
+ * captured it) or with `--json`, matching the agent CLI's LLM-friendly contract:
5
+ * success → {"ok":true, ...data}
6
+ * failure → {"ok":false, error:{code, message, recoverable}}
7
+ */
8
+ export interface OutCtx {
9
+ json: boolean;
10
+ }
11
+ export declare function isJsonMode(flag: boolean | undefined): boolean;
12
+ export declare function emit(ctx: OutCtx, data: Record<string, unknown>, human: () => string): void;
13
+ /** Print a failure in the active mode and return the process exit code. */
14
+ export declare function printError(json: boolean, err: unknown): number;
15
+ export declare const ui: {
16
+ title: (s: string) => string;
17
+ dim: (s: string) => string;
18
+ green: (s: string) => string;
19
+ amber: (s: string) => string;
20
+ red: (s: string) => string;
21
+ label: (s: string) => string;
22
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Read a deposit wallet's prediction-balance (pUSD) on Polygon — client-side,
3
+ * with no backend change and no web3 dependency.
4
+ *
5
+ * The prediction balance lives as pUSD (Polymarket USD: a standard ERC-20 on
6
+ * Polygon, 6 decimals, USDC-backed) in the user's Polymarket deposit wallet.
7
+ * The Perfolio backend only exposes the wallet ADDRESS, not its balance, and we
8
+ * are not allowed to change the backend — so we read the balance directly from a
9
+ * public Polygon RPC with a single `eth_call` to `balanceOf`, encoded/decoded by
10
+ * hand (no viem). The CLI ships only `commander` + `picocolors`; this keeps it
11
+ * that way.
12
+ *
13
+ * Everything here is best-effort: a balance read must NEVER break a command, so
14
+ * `fetchPusdBalanceUsd` returns `null` on any failure rather than throwing.
15
+ */
16
+ /** pUSD (Polymarket USD) — ERC-20 on Polygon mainnet, 6 decimals. */
17
+ export declare const PUSD_ADDRESS = "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB";
18
+ export declare const PUSD_DECIMALS = 6;
19
+ /**
20
+ * ABI-encode `balanceOf(address)` calldata: the 4-byte selector followed by the
21
+ * address left-padded to a 32-byte word. Throws on a malformed address so the
22
+ * caller (which swallows failures) reports "unavailable" rather than querying junk.
23
+ */
24
+ export declare function encodeBalanceOf(address: string): string;
25
+ /** Decode a 32-byte hex word (an eth_call uint256 result) to a bigint. `0x`/empty → 0n. */
26
+ export declare function decodeUint(hex: unknown): bigint;
27
+ /** Convert a base-unit bigint to a decimal number given the token's decimals. */
28
+ export declare function baseUnitsToNumber(units: bigint, decimals: number): number;
29
+ interface FetchOpts {
30
+ rpcUrl?: string;
31
+ fetchImpl?: typeof fetch;
32
+ }
33
+ /**
34
+ * Read the pUSD balance (in USD; 1 pUSD ≈ $1) for a Polygon address via an
35
+ * `eth_call` to `balanceOf`. Returns the USD amount, or `null` on ANY failure —
36
+ * a balance read must never throw or break the command that called it.
37
+ *
38
+ * Endpoint selection: an explicit `opts.rpcUrl` or `PERFOLIO_POLYGON_RPC` pins a
39
+ * single endpoint; otherwise we try the public defaults in order and return the
40
+ * first that answers (so one endpoint going dark doesn't kill the feature).
41
+ */
42
+ export declare function fetchPusdBalanceUsd(address: string, opts?: FetchOpts): Promise<number | null>;
43
+ export {};
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Friendly multi-asset portfolio rendering for the MONEY (investment) side —
3
+ * ported from the standalone Perfolio CLI so the merged Grant Cash CLI shows the
4
+ * same rich breakdown.
5
+ *
6
+ * Consumes the `GET /api/portfolio/summary?view=full` shape. When the optional
7
+ * `multiAsset` block is present it renders every spot asset (gold, cash, bitcoin,
8
+ * ethereum, …) plus the Hyperliquid perps bucket and its per-category breakdown.
9
+ * When it is absent (gold-only response) it degrades to a gold + cash summary so
10
+ * the command never shows raw JSON.
11
+ *
12
+ * All money is rendered through `formatMoney`, which applies the user's display
13
+ * currency. Callers pass USD values straight through — never pre-convert.
14
+ */
15
+ import { type DisplayPrefs } from "./currency.js";
16
+ import type { PortfolioSummary } from "./types.js";
17
+ /**
18
+ * Money pools the backend's portfolio summary does NOT know about (prediction
19
+ * balance + open bets, earn/vault positions), read client-side and folded into
20
+ * the net-worth picture. Kept as a type so the extras pipeline is a drop-in
21
+ * later; the merged CLI does not yet gather these.
22
+ */
23
+ export interface PortfolioExtras {
24
+ predictionAvailableUsd?: number;
25
+ predictionPositionsUsd?: number;
26
+ predictionPnlUsd?: number;
27
+ earn?: Array<{
28
+ label: string;
29
+ valueUsd: number;
30
+ earnedUsd?: number | null;
31
+ apy?: number | null;
32
+ }>;
33
+ }
34
+ export declare function formatPortfolioView(summary: PortfolioSummary, prefs?: DisplayPrefs, extras?: PortfolioExtras): string;
35
+ /**
36
+ * The single, honest net worth (USD) including ALL pools: holdings (or gold+cash),
37
+ * perps equity, earning, and predictions — minus debt.
38
+ *
39
+ * The backend exposes `multiAsset.totalUsd` / `multiAsset.netWorthUsd` /
40
+ * `current.netWorthUsd`, but ALL of them EXCLUDE predictions and earn — which
41
+ * caused a real ~$190 under-report. This is the one number a programmatic consumer
42
+ * should trust, and it's emitted as `netWorthUsd` in `portfolio --json`.
43
+ */
44
+ export declare function computeNetWorthUsd(summary: PortfolioSummary, extras: PortfolioExtras): number;
45
+ /**
46
+ * Spending (agent) side — status-aware funds, ported from the standalone Agent
47
+ * CLI's `balance` rendering. The agent backend's `GET /balance` (api-key auth)
48
+ * returns one of: `not_set_up` (nothing to spend yet), `credit_exhausted`
49
+ * (sign-up credit used up), or `active` — and an active user carries either live
50
+ * on-chain USDC/USDT or a chain-agnostic sign-up credit total (minor units, 1e6).
51
+ */
52
+ export interface AgentBalance {
53
+ status?: string;
54
+ address?: string;
55
+ USDC?: string | number;
56
+ USDT?: string | number;
57
+ grantMinor?: string | number;
58
+ totalMinor?: string | number;
59
+ }
60
+ /**
61
+ * The chain-agnostic spendable from `GET /credit` (dual-auth — the CLI's api-key
62
+ * can read it). Splits the single spendable into the sign-up "free credit"
63
+ * (grant) and the funds the user added (wallet). `walletMinor` is absent for a
64
+ * grant-only user. Mirrors the app's credit split (agent-mode-ui CreditCard).
65
+ */
66
+ export interface CreditBalance {
67
+ grantMinor?: string | number;
68
+ walletMinor?: string | number;
69
+ totalMinor?: string | number;
70
+ }
71
+ /**
72
+ * Render the agent (spending) funds block as indented lines (no section title).
73
+ *
74
+ * When the chain-agnostic `credit` read (GET /credit) is supplied, we render the
75
+ * full split — total spendable, the sign-up free credit, and (if the user has
76
+ * funded a wallet) the funds they added — for parity with the app. Without it we
77
+ * fall back to the `/balance` status shape (USDC/USDT or sign-up-credit total).
78
+ */
79
+ export declare function formatAgentFunds(bal: AgentBalance, credit?: CreditBalance | null): string;
@@ -0,0 +1,8 @@
1
+ export declare function newSid(): string;
2
+ interface PollOpts {
3
+ fetchImpl?: typeof fetch;
4
+ intervalMs?: number;
5
+ timeoutMs?: number;
6
+ }
7
+ export declare function pollRelay<T = unknown>(widgetBase: string, sid: string, opts?: PollOpts): Promise<T | null>;
8
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Browser-sign poll helper for user-signed operations (withdrawal, gift).
3
+ *
4
+ * The CLI prepares the operation and hands the payload to the sign relay
5
+ * (via PerfolioClient.signStart), opens the browser, then polls here until the
6
+ * user signs + executes in the browser. Poll is public (the sid is the secret).
7
+ */
8
+ import type { SignPoll } from './types.js';
9
+ export declare function pollSign(api: string, sid: string, f?: typeof fetch): Promise<SignPoll>;
10
+ /** Poll until the browser signs (complete), the user cancels (denied), or it expires. */
11
+ export declare function waitForSign(api: string, sid: string, intervalMs: number, timeoutMs: number, f?: typeof fetch): Promise<SignPoll>;
@@ -0,0 +1,19 @@
1
+ import type { MoneyClient } from "./money-client.js";
2
+ import type { TxStatus } from "./types.js";
3
+ export interface WaitResult {
4
+ status: TxStatus | "timeout";
5
+ txHash?: string;
6
+ receipt?: unknown;
7
+ }
8
+ /**
9
+ * After a session-key write (buy/sell), never trust "submitted". Poll the
10
+ * authoritative per-tx status endpoint for THIS exact txHash until it reaches
11
+ * success/failed or we time out. MEE/cross-chain settlement can take a while, so
12
+ * the timeout is generous. Ported from the standalone Perfolio CLI so the merged
13
+ * CLI reports honestly — never a premature "✓ done".
14
+ */
15
+ export declare function waitForTx(money: MoneyClient, txHash: string | undefined, opts?: {
16
+ timeoutMs?: number;
17
+ intervalMs?: number;
18
+ initialDelayMs?: number;
19
+ }): Promise<WaitResult>;
@@ -0,0 +1,377 @@
1
+ /**
2
+ * Shared types for the merged Grant Cash CLI.
3
+ *
4
+ * One identity, one credential (unified auth): `grant login` runs a single
5
+ * perfolio device flow and stores the perfolio-signed access JWT (`accessJwt`)
6
+ * plus the opaque `pfr_` refresh token. That ONE JWT is sent as
7
+ * `Authorization: Bearer <accessJwt>` to BOTH backends — the MONEY side
8
+ * (Perfolio — gold, portfolio, cash) and the AGENT side (Agent-mode — pay-per-use
9
+ * services). The retired `grant_live_` X-API-Key path is gone.
10
+ */
11
+ /** The single perfolio credential — minted by the login handshake. */
12
+ export interface MoneyCredentials {
13
+ /** perfolio-signed access JWT — the Bearer sent to BOTH backends (TTL ~15min). */
14
+ accessJwt?: string;
15
+ /** opaque `pfr_` refresh token (Redis, revocable) — re-issues the access JWT. */
16
+ refreshToken?: string;
17
+ /** access-token expiry, ms epoch */
18
+ expiresAt?: number;
19
+ email?: string;
20
+ walletAddress?: string;
21
+ /** server device id — lets logout revoke this exact device */
22
+ deviceId?: string;
23
+ }
24
+ /** The credentials file written to ~/.grant-cash/credentials.json. */
25
+ export interface Credentials {
26
+ money?: MoneyCredentials;
27
+ }
28
+ /** Resolved backend base URLs (env-overridable — see config.ts). */
29
+ export interface BaseUrls {
30
+ /** Perfolio API (money side) */
31
+ api: string;
32
+ /** Perfolio fiat microservice (money side) */
33
+ fiat: string;
34
+ /** Perfolio web app (hosts the /connect browser screen) */
35
+ app: string;
36
+ /** Agent-mode backend (agent side) */
37
+ agent: string;
38
+ }
39
+ export interface NetWorthChange {
40
+ amount: number;
41
+ percentage: number;
42
+ }
43
+ export type HoldingClass = "gold" | "stable" | "btc" | "eth" | "other";
44
+ /** A single spot holding in the multi-asset view. */
45
+ export interface MultiAssetHolding {
46
+ symbol: string;
47
+ class: HoldingClass;
48
+ label: string;
49
+ balance: number;
50
+ valueUsd: number;
51
+ allocationPct: number;
52
+ }
53
+ export interface PerpsCategoryRollup {
54
+ category: "crypto" | "stock" | "commodity" | "fx" | "index" | "other";
55
+ label: string;
56
+ valueUsd: number;
57
+ unrealizedPnlUsd: number;
58
+ positions: number;
59
+ }
60
+ export interface PerpsBucket {
61
+ equityUsd: number;
62
+ unrealizedPnlUsd: number;
63
+ marginUsedUsd: number;
64
+ allocationPct: number;
65
+ byCategory: PerpsCategoryRollup[];
66
+ }
67
+ /** Additive block returned only when `?view=full` is requested. */
68
+ export interface MultiAssetView {
69
+ holdings: MultiAssetHolding[];
70
+ perps: PerpsBucket | null;
71
+ totalUsd: number;
72
+ netWorthUsd: number;
73
+ generatedAt: string;
74
+ }
75
+ /** Shape of GET /api/portfolio/summary (with optional multi-asset block). */
76
+ export interface PortfolioSummary {
77
+ current: {
78
+ netWorthUsd: number;
79
+ goldValueUsd: number;
80
+ usdtBalance: number;
81
+ totalCollateralUsd: number;
82
+ totalDebtUsd: number;
83
+ };
84
+ changes?: {
85
+ "24h": NetWorthChange | null;
86
+ "7d": NetWorthChange | null;
87
+ "30d": NetWorthChange | null;
88
+ };
89
+ multiAsset?: MultiAssetView | null;
90
+ }
91
+ /**
92
+ * Backend transaction lifecycle (money side). Terminal states are `success` and
93
+ * `failed`; everything else is in-flight. Mirrors perfolio-backend-api TxStatus.
94
+ */
95
+ export type TxStatus = "submitted" | "processing" | "executing" | "success" | "failed";
96
+ /** What a write endpoint (/tx/swap, …) returns at submit time. */
97
+ export interface TxResult {
98
+ txHash?: string;
99
+ status?: TxStatus;
100
+ }
101
+ /** Shape of GET /api/tx/status/:txHash. */
102
+ export interface TxStatusResult {
103
+ txHash: string;
104
+ type?: string;
105
+ status: TxStatus;
106
+ receipt?: unknown;
107
+ createdAt?: string;
108
+ updatedAt?: string;
109
+ }
110
+ /** A standard Perfolio API envelope: { success, data?, error?, code? }. */
111
+ export interface ApiResponse<T = unknown> {
112
+ success?: boolean;
113
+ data?: T;
114
+ /**
115
+ * Backend error field. Most endpoints send a flat string, but some (kyc /
116
+ * beneficiaries / fiat) nest the whole thing as `{ code, message, recoverable }`.
117
+ * Typed as a union so the client normalizes both shapes instead of stringifying
118
+ * an object into "[object Object]".
119
+ */
120
+ error?: string | {
121
+ code?: string;
122
+ message?: string;
123
+ recoverable?: boolean;
124
+ };
125
+ message?: string;
126
+ code?: string;
127
+ recoverable?: boolean;
128
+ details?: Record<string, unknown>;
129
+ }
130
+ export type AssetClass = "gold" | "btc" | "eth" | "stable" | "other";
131
+ /** Asset DTO as returned by GET /api/assets. */
132
+ export interface AssetDto {
133
+ symbol: string;
134
+ name: string;
135
+ decimals: number;
136
+ class: AssetClass;
137
+ chain: string;
138
+ logoUrl: string | null;
139
+ address: string;
140
+ explorerUrl: string | null;
141
+ }
142
+ /** Market DTO as returned by GET /api/markets. */
143
+ export interface MarketDto {
144
+ pair: string;
145
+ collateral: string;
146
+ loan: string;
147
+ protocol: string;
148
+ chain: string;
149
+ lltvPercent: number;
150
+ safeMaxLtvPercent: number;
151
+ tier: "canonical" | "conservative" | "aggressive";
152
+ marketIdOnchain: string;
153
+ }
154
+ /** One earn vault. Live fields (apy/tvl/etc) are null when the Morpho API is unavailable. */
155
+ export interface VaultDto {
156
+ asset: string | null;
157
+ assetDecimals: number | null;
158
+ vaultAddress: string;
159
+ name: string;
160
+ symbol: string;
161
+ version: string;
162
+ curator: string;
163
+ shareDecimals: number;
164
+ chainId: number;
165
+ netApy: number | null;
166
+ apy: number | null;
167
+ tvlUsd: number | null;
168
+ sharePrice: number | null;
169
+ liquidityUsd: number | null;
170
+ performanceFee: number | null;
171
+ }
172
+ /** The user's position in an asset's canonical earn vault. */
173
+ export interface EarnPositionDto {
174
+ asset: string;
175
+ vaultAddress: string;
176
+ vaultName: string;
177
+ curator: string;
178
+ shares: string;
179
+ shareDecimals: number;
180
+ assets: string;
181
+ assetsFormatted: string;
182
+ assetDecimals: number;
183
+ netApy: number | null;
184
+ apy: number | null;
185
+ sharePrice: number | null;
186
+ tvlUsd: number | null;
187
+ liquidityUsd: number | null;
188
+ performanceFee: number | null;
189
+ principalWei: string | null;
190
+ principalFormatted: string | null;
191
+ earnedWei: string | null;
192
+ earnedFormatted: string | null;
193
+ earnedPct: number | null;
194
+ }
195
+ /** One outcome of a prediction market; price is the implied probability (0..1). */
196
+ export interface PolymarketOutcome {
197
+ label: string;
198
+ price: number;
199
+ }
200
+ /** A market as returned by GET /api/polymarket/markets. */
201
+ export interface PolymarketMarket {
202
+ id: string;
203
+ question: string;
204
+ slug: string;
205
+ outcomes: PolymarketOutcome[];
206
+ volume24h: number;
207
+ totalVolume: number;
208
+ endDate: string | null;
209
+ }
210
+ /** GET /api/polymarket/markets envelope payload. */
211
+ export interface PolymarketMarketsResult {
212
+ markets: PolymarketMarket[];
213
+ count: number;
214
+ }
215
+ /** Full detail (GET /api/polymarket/markets/:id) — adds outcome token ids + meta. */
216
+ export interface PolymarketMarketDetail {
217
+ id: string;
218
+ question: string;
219
+ slug: string;
220
+ description: string | null;
221
+ outcomes: Array<PolymarketOutcome & {
222
+ tokenId: string;
223
+ }>;
224
+ volume24h: number;
225
+ totalVolume: number;
226
+ liquidity: number;
227
+ endDate: string | null;
228
+ active: boolean;
229
+ closed: boolean;
230
+ category: string | null;
231
+ }
232
+ /** One open prediction position (GET /api/polymarket/positions). */
233
+ export interface PolymarketPosition {
234
+ market: string;
235
+ outcome: string;
236
+ shares: number;
237
+ avgPrice: number;
238
+ currentPrice: number;
239
+ initialValue: number;
240
+ value: number;
241
+ pnl: number;
242
+ pnlPercent: number;
243
+ redeemable: boolean;
244
+ endDate: string | null;
245
+ conditionId: string | null;
246
+ slug: string;
247
+ }
248
+ /** GET /api/polymarket/positions — positions + portfolio totals. */
249
+ export interface PolymarketPositionsResult {
250
+ positions: PolymarketPosition[];
251
+ count: number;
252
+ investedUsd: number;
253
+ valueUsd: number;
254
+ pnlUsd: number;
255
+ pnlPercent: number;
256
+ /**
257
+ * Spendable pUSD cash in the deposit wallet (deposited-but-unbet funds),
258
+ * read on-chain server-side — the same value the predictions screen shows.
259
+ * Optional: older backends don't return it, so callers fall back to a direct
260
+ * on-chain read of the deposit wallet.
261
+ */
262
+ cashUsd?: number;
263
+ }
264
+ /** One prediction trade/activity event (GET /api/polymarket/activity). */
265
+ export interface PolymarketActivity {
266
+ type: string;
267
+ side: string | null;
268
+ market: string;
269
+ outcome: string;
270
+ shares: number;
271
+ price: number;
272
+ amountUsd: number;
273
+ timestamp: number;
274
+ txHash: string | null;
275
+ conditionId: string | null;
276
+ slug: string;
277
+ }
278
+ /** GET /api/polymarket/activity envelope payload. */
279
+ export interface PolymarketActivityResult {
280
+ activity: PolymarketActivity[];
281
+ count: number;
282
+ }
283
+ /** GET /api/polymarket/trading-status — betting (write) path readiness. */
284
+ export interface PolymarketTradingStatus {
285
+ enabled: boolean;
286
+ configured: boolean;
287
+ missing: string[];
288
+ }
289
+ /** POST /api/polymarket/bet|sell result at submit time. */
290
+ export interface PolymarketBetResult {
291
+ orderId: string;
292
+ status: string;
293
+ side: "yes" | "no";
294
+ shares: number;
295
+ price: number;
296
+ }
297
+ /** A prepared MEE quote awaiting a user signature (from /tx/prepare, /gift/prepare-send). */
298
+ export interface PrepareResult {
299
+ quoteId: string;
300
+ payloadToSign: string;
301
+ operation?: string;
302
+ preview?: unknown;
303
+ }
304
+ /** A self-describing sign task handed to the browser-sign relay. */
305
+ export interface SignTaskInput {
306
+ type: string;
307
+ signMode: "personal" | "typed";
308
+ signatureFormat: "hex" | "rsv";
309
+ payload: unknown;
310
+ executePath: string;
311
+ executeBody: Record<string, unknown>;
312
+ preview?: unknown;
313
+ }
314
+ /** Response of POST /api/hl/setup. */
315
+ export interface HlSetup {
316
+ agentAddress: string;
317
+ approvalAction: {
318
+ type: string;
319
+ signatureChainId: string;
320
+ nonce: number;
321
+ [k: string]: unknown;
322
+ };
323
+ approvalTypedData: unknown;
324
+ alreadyExists: boolean;
325
+ isApproved: boolean;
326
+ hlBalance?: string;
327
+ needsDeposit?: boolean;
328
+ minDeposit?: number;
329
+ }
330
+ /** Response of POST /api/cli/sign/start. */
331
+ export interface SignStart {
332
+ sid: string;
333
+ approveUrl: string;
334
+ pollInterval: number;
335
+ expiresIn: number;
336
+ }
337
+ /** Poll result of the browser-sign relay. */
338
+ export type SignPoll = {
339
+ status: "pending" | "denied" | "expired";
340
+ } | {
341
+ status: "complete";
342
+ result: {
343
+ txHash?: string;
344
+ status?: TxStatus;
345
+ };
346
+ };
347
+ /** Friendly term ↔ resolved asset. */
348
+ export interface ResolvedAsset {
349
+ friendly: string;
350
+ symbol: string;
351
+ decimals: number;
352
+ class: AssetClass;
353
+ }
354
+ /** Bank-transfer details for a fiat deposit account (mirrors ms-fiat-payments AccountData.bankDetails). */
355
+ export interface BankDetails {
356
+ bankName?: string;
357
+ bankCountry?: string;
358
+ beneficiaryName?: string;
359
+ accountHolderName?: string;
360
+ accountNumber?: string;
361
+ iban?: string;
362
+ swift?: string;
363
+ swiftCode?: string;
364
+ bankAddress?: string;
365
+ }
366
+ /** A provider (Roma) account from GET /accounts. Fiat accounts carry bankDetails; crypto accounts do not. */
367
+ export interface FiatAccount {
368
+ id?: string;
369
+ providerAccountId?: string;
370
+ type?: string;
371
+ currency: string;
372
+ status?: string;
373
+ ownerType?: string;
374
+ bankDetails?: BankDetails;
375
+ balance?: number;
376
+ availableBalance?: number;
377
+ }
@@ -0,0 +1,21 @@
1
+ import type { PerfolioClient } from './client.js';
2
+ import type { TxStatus } from './types.js';
3
+ export interface WaitResult {
4
+ status: TxStatus | 'timeout';
5
+ txHash?: string;
6
+ receipt?: unknown;
7
+ }
8
+ /**
9
+ * After a session-key write, never trust "submitted". Poll the authoritative
10
+ * per-tx status endpoint (which re-checks the MEE explorer for non-terminal
11
+ * states) for THIS exact txHash until it reaches success/failed or we time out.
12
+ *
13
+ * Correlating by txHash is essential: reading "the latest history row" can
14
+ * confirm a different transaction. MEE/cross-chain settlement can take a while,
15
+ * so the timeout is generous.
16
+ */
17
+ export declare function waitForTx(client: PerfolioClient, txHash: string | undefined, opts?: {
18
+ timeoutMs?: number;
19
+ intervalMs?: number;
20
+ initialDelayMs?: number;
21
+ }): Promise<WaitResult>;