@elizaos/plugin-wallet 2.0.0-beta.1
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.
- package/LICENSE +21 -0
- package/README.md +64 -0
- package/auto-enable.ts +76 -0
- package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
- package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
- package/dist/aerodrome-CfnESC32.mjs +890 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/index.d.mts +34727 -0
- package/dist/index.mjs +21590 -0
- package/dist/lib/server-wallet-trade.d.mts +34 -0
- package/dist/lib/server-wallet-trade.mjs +306 -0
- package/dist/meteora-BPX39hZo.mjs +22640 -0
- package/dist/orca-Bybp1HXO.mjs +249 -0
- package/dist/pancakeswp-CkEXlXti.mjs +604 -0
- package/dist/plugin-ZO_MTyd0.mjs +529 -0
- package/dist/raydium-rfaM9yEf.mjs +539 -0
- package/dist/sdk/index.d.mts +32492 -0
- package/dist/sdk/index.mjs +6415 -0
- package/dist/types-D5252NZk.mjs +487 -0
- package/dist/uniswap-CReXgXVN.mjs +573 -0
- package/dist/wallet-action.d.mts +6 -0
- package/dist/wallet-action.mjs +820 -0
- package/package.json +152 -0
- package/src/actions/failure-codes.ts +79 -0
- package/src/actions/index.ts +1 -0
- package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
- package/src/analytics/birdeye/birdeye-task.ts +175 -0
- package/src/analytics/birdeye/birdeye.ts +813 -0
- package/src/analytics/birdeye/constants.ts +74 -0
- package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
- package/src/analytics/birdeye/providers/market.ts +227 -0
- package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
- package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
- package/src/analytics/birdeye/providers/trending.ts +365 -0
- package/src/analytics/birdeye/providers/wallet.ts +14 -0
- package/src/analytics/birdeye/search-category.test.ts +207 -0
- package/src/analytics/birdeye/search-category.ts +506 -0
- package/src/analytics/birdeye/service.ts +992 -0
- package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
- package/src/analytics/birdeye/types/api/common.ts +305 -0
- package/src/analytics/birdeye/types/api/defi.ts +220 -0
- package/src/analytics/birdeye/types/api/pair.ts +200 -0
- package/src/analytics/birdeye/types/api/search.ts +86 -0
- package/src/analytics/birdeye/types/api/token.ts +635 -0
- package/src/analytics/birdeye/types/api/trader.ts +76 -0
- package/src/analytics/birdeye/types/api/wallet.ts +181 -0
- package/src/analytics/birdeye/types/shared.ts +106 -0
- package/src/analytics/birdeye/utils.ts +700 -0
- package/src/analytics/dexscreener/errors.ts +28 -0
- package/src/analytics/dexscreener/index.ts +3 -0
- package/src/analytics/dexscreener/search-category.test.ts +49 -0
- package/src/analytics/dexscreener/search-category.ts +42 -0
- package/src/analytics/dexscreener/service.ts +595 -0
- package/src/analytics/dexscreener/types.ts +128 -0
- package/src/analytics/lpinfo/index.d.ts +7 -0
- package/src/analytics/lpinfo/index.ts +52 -0
- package/src/analytics/lpinfo/kamino/README.md +102 -0
- package/src/analytics/lpinfo/kamino/index.ts +24 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
- package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
- package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
- package/src/analytics/lpinfo/steer/README.md +169 -0
- package/src/analytics/lpinfo/steer/index.ts +23 -0
- package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
- package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
- package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
- package/src/analytics/news/index.ts +52 -0
- package/src/analytics/news/interfaces/types.ts +222 -0
- package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
- package/src/analytics/news/services/newsDataService.ts +332 -0
- package/src/analytics/news/utils/formatters.ts +151 -0
- package/src/analytics/token-info/action.ts +240 -0
- package/src/analytics/token-info/index.ts +3 -0
- package/src/analytics/token-info/params.ts +215 -0
- package/src/analytics/token-info/providers.ts +681 -0
- package/src/analytics/token-info/service.ts +168 -0
- package/src/analytics/token-info/types.ts +74 -0
- package/src/audit/audit-log.ts +45 -0
- package/src/browser-shim/build-shim.ts +123 -0
- package/src/browser-shim/index.ts +5 -0
- package/src/browser-shim/shim.template.js +563 -0
- package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
- package/src/chains/evm/LICENSE +21 -0
- package/src/chains/evm/README.md +106 -0
- package/src/chains/evm/actions/helpers.ts +147 -0
- package/src/chains/evm/actions/swap.ts +839 -0
- package/src/chains/evm/actions/transfer.ts +254 -0
- package/src/chains/evm/biome.json +61 -0
- package/src/chains/evm/bridge-router.ts +660 -0
- package/src/chains/evm/build.ts +89 -0
- package/src/chains/evm/chain-handler.ts +416 -0
- package/src/chains/evm/constants.ts +23 -0
- package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
- package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
- package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
- package/src/chains/evm/dex/aerodrome/index.ts +34 -0
- package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
- package/src/chains/evm/dex/aerodrome/types.ts +318 -0
- package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
- package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
- package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
- package/src/chains/evm/dex/uniswap/index.ts +35 -0
- package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
- package/src/chains/evm/dex/uniswap/types.ts +390 -0
- package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
- package/src/chains/evm/generated/specs/specs.ts +151 -0
- package/src/chains/evm/gov-router.ts +250 -0
- package/src/chains/evm/index.browser.ts +16 -0
- package/src/chains/evm/index.ts +31 -0
- package/src/chains/evm/prompts.ts +193 -0
- package/src/chains/evm/providers/get-balance.ts +123 -0
- package/src/chains/evm/providers/wallet.ts +715 -0
- package/src/chains/evm/routes/sign.ts +333 -0
- package/src/chains/evm/rpc-providers.ts +410 -0
- package/src/chains/evm/service.ts +140 -0
- package/src/chains/evm/templates/index.ts +10 -0
- package/src/chains/evm/types/index.ts +432 -0
- package/src/chains/evm/vitest.config.ts +18 -0
- package/src/chains/registry.ts +668 -0
- package/src/chains/solana/README.md +367 -0
- package/src/chains/wallet-action.ts +533 -0
- package/src/chains/wallet-router.test.ts +296 -0
- package/src/contracts.ts +65 -0
- package/src/core-augmentation.ts +10 -0
- package/src/index.ts +71 -0
- package/src/lib/server-wallet-trade.ts +192 -0
- package/src/lib/wallet-export-guard.ts +330 -0
- package/src/lp/actions/liquidity.ts +827 -0
- package/src/lp/e2e/real-token-tests.ts +428 -0
- package/src/lp/e2e/scenarios.ts +470 -0
- package/src/lp/e2e/test-utils.ts +145 -0
- package/src/lp/lp-manager-entry.ts +303 -0
- package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
- package/src/lp/services/DexInteractionService.ts +226 -0
- package/src/lp/services/LpManagementService.test.ts +148 -0
- package/src/lp/services/LpManagementService.ts +632 -0
- package/src/lp/services/UserLpProfileService.ts +163 -0
- package/src/lp/services/VaultService.ts +153 -0
- package/src/lp/services/YieldOptimizationService.ts +344 -0
- package/src/lp/services/__tests__/MockLpService.ts +146 -0
- package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
- package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
- package/src/lp/types.ts +582 -0
- package/src/lp/utils/solanaClient.ts +143 -0
- package/src/plugin.ts +125 -0
- package/src/policy/policy.ts +19 -0
- package/src/providers/canonical-provider.ts +27 -0
- package/src/providers/unified-wallet-provider.ts +79 -0
- package/src/register-routes.ts +11 -0
- package/src/routes/plugin.ts +47 -0
- package/src/routes/wallet-market-overview-route.ts +869 -0
- package/src/sdk/abi.ts +258 -0
- package/src/sdk/bridge/abis.ts +126 -0
- package/src/sdk/bridge/client.ts +518 -0
- package/src/sdk/bridge/index.ts +56 -0
- package/src/sdk/bridge/solana.ts +604 -0
- package/src/sdk/bridge/types.ts +202 -0
- package/src/sdk/convenience.ts +347 -0
- package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
- package/src/sdk/escrow/types.ts +64 -0
- package/src/sdk/escrow/verifiers.ts +73 -0
- package/src/sdk/identity/erc8004.ts +692 -0
- package/src/sdk/identity/reputation.ts +449 -0
- package/src/sdk/identity/uaid.ts +497 -0
- package/src/sdk/identity/validation.ts +372 -0
- package/src/sdk/index.ts +763 -0
- package/src/sdk/policy/SpendingPolicy.ts +260 -0
- package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
- package/src/sdk/router/PaymentRouter.ts +215 -0
- package/src/sdk/router/index.ts +8 -0
- package/src/sdk/swap/SwapModule.ts +310 -0
- package/src/sdk/swap/abi.ts +117 -0
- package/src/sdk/swap/index.ts +34 -0
- package/src/sdk/swap/types.ts +135 -0
- package/src/sdk/tokens/decimals.ts +140 -0
- package/src/sdk/tokens/registry.ts +911 -0
- package/src/sdk/tokens/solana.ts +419 -0
- package/src/sdk/tokens/transfers.ts +327 -0
- package/src/sdk/types.ts +158 -0
- package/src/sdk/wallet-core.ts +115 -0
- package/src/sdk/x402/budget.ts +168 -0
- package/src/sdk/x402/chains/abstract/index.ts +280 -0
- package/src/sdk/x402/client.ts +320 -0
- package/src/sdk/x402/index.ts +46 -0
- package/src/sdk/x402/middleware.ts +92 -0
- package/src/sdk/x402/multi-asset.ts +144 -0
- package/src/sdk/x402/types.ts +156 -0
- package/src/services/wallet-backend-service.ts +328 -0
- package/src/types/wallet-router.ts +227 -0
- package/src/utils/intent-trajectory.ts +106 -0
- package/src/wallet/backend.ts +62 -0
- package/src/wallet/errors.ts +49 -0
- package/src/wallet/index.ts +27 -0
- package/src/wallet/local-eoa-backend.ts +201 -0
- package/src/wallet/pending.ts +60 -0
- package/src/wallet/select-backend.ts +47 -0
- package/src/wallet/steward-backend.ts +161 -0
- package/src/wallet-action.ts +1 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module tokens/solana
|
|
3
|
+
* Solana SPL token support for AgentWallet v6.
|
|
4
|
+
*
|
|
5
|
+
* Uses @solana/web3.js as an optional peer dependency.
|
|
6
|
+
* All imports are done dynamically so EVM-only users pay zero overhead.
|
|
7
|
+
*
|
|
8
|
+
* Token addresses verified against:
|
|
9
|
+
* - Solana SPL Token Registry: https://raw.githubusercontent.com/solana-labs/token-list/main/src/tokens/solana.tokenlist.json
|
|
10
|
+
* - USDC on Solana: https://developers.circle.com/stablecoins/usdc-contract-addresses
|
|
11
|
+
* - Raydium: https://docs.raydium.io/raydium/token-pairs-and-liquidity
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { TransactionInstruction } from "@solana/web3.js";
|
|
15
|
+
import bs58 from "bs58";
|
|
16
|
+
|
|
17
|
+
type SolanaWeb3Module = typeof import("@solana/web3.js");
|
|
18
|
+
type SplTokenModule = typeof import("@solana/spl-token");
|
|
19
|
+
type SolanaConnectionInstance = InstanceType<SolanaWeb3Module["Connection"]>;
|
|
20
|
+
type SolanaKeypairInstance = InstanceType<SolanaWeb3Module["Keypair"]>;
|
|
21
|
+
type SolanaPublicKeyInstance = InstanceType<SolanaWeb3Module["PublicKey"]>;
|
|
22
|
+
|
|
23
|
+
interface ParsedSplTokenWalletAccountEntry {
|
|
24
|
+
account: {
|
|
25
|
+
data: {
|
|
26
|
+
parsed: {
|
|
27
|
+
info: {
|
|
28
|
+
mint: string;
|
|
29
|
+
tokenAmount: { amount: string; decimals: number };
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ─── Well-known Solana token mint addresses ───────────────────────────────────
|
|
37
|
+
//
|
|
38
|
+
// All addresses are base-58 encoded Solana public keys.
|
|
39
|
+
// Sources: Solana token registry + Circle USDC docs
|
|
40
|
+
|
|
41
|
+
export const SOLANA_TOKENS = {
|
|
42
|
+
// Native SOL (special: no mint address, use null or SystemProgram)
|
|
43
|
+
SOL: null as null, // native, not a mint
|
|
44
|
+
|
|
45
|
+
// USDC on Solana mainnet — Circle official
|
|
46
|
+
USDC: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
47
|
+
|
|
48
|
+
// USDT on Solana — Tether official
|
|
49
|
+
USDT: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
50
|
+
|
|
51
|
+
// Raydium
|
|
52
|
+
RAY: "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R",
|
|
53
|
+
|
|
54
|
+
// Serum (now Openbook predecessor token)
|
|
55
|
+
SRM: "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt",
|
|
56
|
+
|
|
57
|
+
// Bonk memecoin
|
|
58
|
+
BONK: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
|
|
59
|
+
|
|
60
|
+
// JitoSOL — Jito staked SOL
|
|
61
|
+
JITOSOL: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn",
|
|
62
|
+
|
|
63
|
+
// mSOL — Marinade staked SOL
|
|
64
|
+
MSOL: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So",
|
|
65
|
+
|
|
66
|
+
// Wrapped BTC on Solana (Portal/Wormhole)
|
|
67
|
+
WBTC: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh",
|
|
68
|
+
|
|
69
|
+
// Wrapped ETH on Solana (Portal/Wormhole)
|
|
70
|
+
WETH: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs",
|
|
71
|
+
} as const;
|
|
72
|
+
|
|
73
|
+
export type SolanaTokenSymbol = keyof typeof SOLANA_TOKENS;
|
|
74
|
+
|
|
75
|
+
export interface SolanaTokenInfo {
|
|
76
|
+
symbol: SolanaTokenSymbol;
|
|
77
|
+
mint: string | null; // null for native SOL
|
|
78
|
+
decimals: number;
|
|
79
|
+
name: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Known decimals for Solana tokens */
|
|
83
|
+
export const SOLANA_TOKEN_DECIMALS: Record<SolanaTokenSymbol, number> = {
|
|
84
|
+
SOL: 9,
|
|
85
|
+
USDC: 6,
|
|
86
|
+
USDT: 6,
|
|
87
|
+
RAY: 6,
|
|
88
|
+
SRM: 6,
|
|
89
|
+
BONK: 5,
|
|
90
|
+
JITOSOL: 9,
|
|
91
|
+
MSOL: 9,
|
|
92
|
+
WBTC: 8,
|
|
93
|
+
WETH: 8,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// ─── Dynamic import helper ────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
async function loadSolanaWeb3(): Promise<SolanaWeb3Module> {
|
|
99
|
+
try {
|
|
100
|
+
const mod = await import("@solana/web3.js");
|
|
101
|
+
return mod;
|
|
102
|
+
} catch {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"SolanaWallet requires @solana/web3.js. Install it: npm install @solana/web3.js",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function loadSplToken(): Promise<SplTokenModule> {
|
|
110
|
+
try {
|
|
111
|
+
const mod = await import("@solana/spl-token");
|
|
112
|
+
return mod;
|
|
113
|
+
} catch {
|
|
114
|
+
throw new Error(
|
|
115
|
+
"SolanaWallet SPL token operations require @solana/spl-token. Install it: npm install @solana/spl-token",
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ─── SolanaWallet class ───────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
export interface SolanaWalletConfig {
|
|
123
|
+
/** Solana RPC endpoint (default: mainnet) */
|
|
124
|
+
rpcUrl?: string;
|
|
125
|
+
/** Base-58 encoded private key for the signer */
|
|
126
|
+
privateKeyBase58?: string;
|
|
127
|
+
/** Keypair bytes (Uint8Array of 64 bytes) */
|
|
128
|
+
keypairBytes?: Uint8Array;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface SolBalanceResult {
|
|
132
|
+
rawBalance: bigint; // lamports
|
|
133
|
+
sol: string; // human-readable SOL
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface SplBalanceResult {
|
|
137
|
+
mint: string;
|
|
138
|
+
rawBalance: bigint;
|
|
139
|
+
humanBalance: string;
|
|
140
|
+
decimals: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface SolanaTxResult {
|
|
144
|
+
signature: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Solana wallet for native SOL and SPL token operations.
|
|
149
|
+
* Uses @solana/web3.js (optional peer dependency, dynamically imported).
|
|
150
|
+
*/
|
|
151
|
+
export class SolanaWallet {
|
|
152
|
+
private readonly rpcUrl: string;
|
|
153
|
+
private readonly config: SolanaWalletConfig;
|
|
154
|
+
|
|
155
|
+
// Lazily loaded modules and connection
|
|
156
|
+
private _connection: SolanaConnectionInstance | null = null;
|
|
157
|
+
private _keypair: SolanaKeypairInstance | null = null;
|
|
158
|
+
|
|
159
|
+
constructor(config: SolanaWalletConfig = {}) {
|
|
160
|
+
this.rpcUrl = config.rpcUrl ?? "https://api.mainnet-beta.solana.com";
|
|
161
|
+
this.config = config;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private async getConnection() {
|
|
165
|
+
if (this._connection) return this._connection;
|
|
166
|
+
const { Connection } = await loadSolanaWeb3();
|
|
167
|
+
this._connection = new Connection(this.rpcUrl, "confirmed");
|
|
168
|
+
return this._connection;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private async getKeypair() {
|
|
172
|
+
if (this._keypair) return this._keypair;
|
|
173
|
+
const { Keypair } = await loadSolanaWeb3();
|
|
174
|
+
|
|
175
|
+
if (this.config.keypairBytes) {
|
|
176
|
+
this._keypair = Keypair.fromSecretKey(this.config.keypairBytes);
|
|
177
|
+
} else if (this.config.privateKeyBase58) {
|
|
178
|
+
const decoded = bs58.decode(this.config.privateKeyBase58);
|
|
179
|
+
this._keypair = Keypair.fromSecretKey(decoded);
|
|
180
|
+
} else {
|
|
181
|
+
throw new Error(
|
|
182
|
+
"SolanaWallet: no private key provided. Set keypairBytes or privateKeyBase58 in config.",
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return this._keypair;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Get signer's public key as base-58 string */
|
|
190
|
+
async getPublicKey(): Promise<string> {
|
|
191
|
+
const kp = await this.getKeypair();
|
|
192
|
+
return kp.publicKey.toBase58();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get native SOL balance.
|
|
197
|
+
* @param address - Optional base-58 public key to check (defaults to wallet's key)
|
|
198
|
+
*/
|
|
199
|
+
async getSolBalance(address?: string): Promise<SolBalanceResult> {
|
|
200
|
+
const { PublicKey } = await loadSolanaWeb3();
|
|
201
|
+
const connection = await this.getConnection();
|
|
202
|
+
|
|
203
|
+
let pubkey: SolanaPublicKeyInstance;
|
|
204
|
+
if (address) {
|
|
205
|
+
pubkey = new PublicKey(address);
|
|
206
|
+
} else {
|
|
207
|
+
const kp = await this.getKeypair();
|
|
208
|
+
pubkey = kp.publicKey;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const lamports = await connection.getBalance(pubkey);
|
|
212
|
+
const rawBalance = BigInt(lamports);
|
|
213
|
+
const sol = (lamports / 1e9).toFixed(9).replace(/\.?0+$/, "");
|
|
214
|
+
|
|
215
|
+
return { rawBalance, sol };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get SPL token balance for a given mint.
|
|
220
|
+
* @param mintAddress - SPL token mint address (base-58)
|
|
221
|
+
* @param owner - Optional owner address (defaults to wallet's key)
|
|
222
|
+
*/
|
|
223
|
+
async getSplTokenBalance(
|
|
224
|
+
mintAddress: string,
|
|
225
|
+
owner?: string,
|
|
226
|
+
): Promise<SplBalanceResult> {
|
|
227
|
+
const { PublicKey } = await loadSolanaWeb3();
|
|
228
|
+
const splToken = await loadSplToken();
|
|
229
|
+
const connection = await this.getConnection();
|
|
230
|
+
|
|
231
|
+
let ownerPubkey: SolanaPublicKeyInstance;
|
|
232
|
+
if (owner) {
|
|
233
|
+
ownerPubkey = new PublicKey(owner);
|
|
234
|
+
} else {
|
|
235
|
+
const kp = await this.getKeypair();
|
|
236
|
+
ownerPubkey = kp.publicKey;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const mintPubkey = new PublicKey(mintAddress);
|
|
240
|
+
|
|
241
|
+
// Get associated token account
|
|
242
|
+
const ata = await splToken.getAssociatedTokenAddress(
|
|
243
|
+
mintPubkey,
|
|
244
|
+
ownerPubkey,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
let rawBalance = 0n;
|
|
248
|
+
let decimals = 9;
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const accountInfo = await splToken.getAccount(connection, ata);
|
|
252
|
+
rawBalance = accountInfo.amount;
|
|
253
|
+
|
|
254
|
+
// Get mint info for decimals
|
|
255
|
+
const mintInfo = await splToken.getMint(connection, mintPubkey);
|
|
256
|
+
decimals = mintInfo.decimals;
|
|
257
|
+
} catch {
|
|
258
|
+
// Token account doesn't exist — balance is 0
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const humanBalance =
|
|
262
|
+
(Number(rawBalance) / 10 ** decimals)
|
|
263
|
+
.toFixed(decimals)
|
|
264
|
+
.replace(/\.?0+$/, "") || "0";
|
|
265
|
+
|
|
266
|
+
return { mint: mintAddress, rawBalance, humanBalance, decimals };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Send native SOL to a recipient.
|
|
271
|
+
* @param to - Recipient base-58 public key
|
|
272
|
+
* @param amount - Lamports (bigint) OR SOL amount as string (e.g. "1.5")
|
|
273
|
+
*/
|
|
274
|
+
async sendSol(to: string, amount: string | bigint): Promise<SolanaTxResult> {
|
|
275
|
+
const { PublicKey, SystemProgram, Transaction, sendAndConfirmTransaction } =
|
|
276
|
+
await loadSolanaWeb3();
|
|
277
|
+
const connection = await this.getConnection();
|
|
278
|
+
const keypair = await this.getKeypair();
|
|
279
|
+
|
|
280
|
+
let lamports: bigint;
|
|
281
|
+
if (typeof amount === "string") {
|
|
282
|
+
// Parse SOL string (9 decimals)
|
|
283
|
+
const parts = amount.split(".");
|
|
284
|
+
const intPart = BigInt(parts[0] || "0");
|
|
285
|
+
const fracStr = (parts[1] ?? "").padEnd(9, "0").slice(0, 9);
|
|
286
|
+
lamports = intPart * 1_000_000_000n + BigInt(fracStr);
|
|
287
|
+
} else {
|
|
288
|
+
lamports = amount;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const transaction = new Transaction().add(
|
|
292
|
+
SystemProgram.transfer({
|
|
293
|
+
fromPubkey: keypair.publicKey,
|
|
294
|
+
toPubkey: new PublicKey(to),
|
|
295
|
+
lamports: Number(lamports),
|
|
296
|
+
}),
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const signature = await sendAndConfirmTransaction(connection, transaction, [
|
|
300
|
+
keypair,
|
|
301
|
+
]);
|
|
302
|
+
return { signature };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Send SPL tokens to a recipient.
|
|
307
|
+
* Creates the recipient's associated token account if it doesn't exist.
|
|
308
|
+
*
|
|
309
|
+
* @param to - Recipient base-58 public key
|
|
310
|
+
* @param amount - Raw token units (bigint) OR human-readable string
|
|
311
|
+
* @param mintAddress - SPL token mint address (base-58)
|
|
312
|
+
*/
|
|
313
|
+
async sendSplToken(
|
|
314
|
+
to: string,
|
|
315
|
+
amount: string | bigint,
|
|
316
|
+
mintAddress: string,
|
|
317
|
+
): Promise<SolanaTxResult> {
|
|
318
|
+
const { PublicKey } = await loadSolanaWeb3();
|
|
319
|
+
const splToken = await loadSplToken();
|
|
320
|
+
const connection = await this.getConnection();
|
|
321
|
+
const keypair = await this.getKeypair();
|
|
322
|
+
|
|
323
|
+
const mintPubkey = new PublicKey(mintAddress);
|
|
324
|
+
const toPubkey = new PublicKey(to);
|
|
325
|
+
|
|
326
|
+
// Get mint info for decimals
|
|
327
|
+
const mintInfo = await splToken.getMint(connection, mintPubkey);
|
|
328
|
+
const { decimals } = mintInfo;
|
|
329
|
+
|
|
330
|
+
// Parse amount
|
|
331
|
+
let rawAmount: bigint;
|
|
332
|
+
if (typeof amount === "string") {
|
|
333
|
+
const parts = amount.split(".");
|
|
334
|
+
const intPart = BigInt(parts[0] || "0");
|
|
335
|
+
const fracStr = (parts[1] ?? "").padEnd(decimals, "0").slice(0, decimals);
|
|
336
|
+
rawAmount = intPart * 10n ** BigInt(decimals) + BigInt(fracStr);
|
|
337
|
+
} else {
|
|
338
|
+
rawAmount = amount;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Get sender's associated token account
|
|
342
|
+
const fromAta = await splToken.getAssociatedTokenAddress(
|
|
343
|
+
mintPubkey,
|
|
344
|
+
keypair.publicKey,
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
// Get or create recipient's associated token account
|
|
348
|
+
const toAta = await splToken.getAssociatedTokenAddress(
|
|
349
|
+
mintPubkey,
|
|
350
|
+
toPubkey,
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
// Build instructions
|
|
354
|
+
const instructions: TransactionInstruction[] = [];
|
|
355
|
+
|
|
356
|
+
// Check if recipient ATA exists
|
|
357
|
+
const toAtaInfo = await connection.getAccountInfo(toAta);
|
|
358
|
+
if (!toAtaInfo) {
|
|
359
|
+
instructions.push(
|
|
360
|
+
splToken.createAssociatedTokenAccountInstruction(
|
|
361
|
+
keypair.publicKey, // payer
|
|
362
|
+
toAta,
|
|
363
|
+
toPubkey,
|
|
364
|
+
mintPubkey,
|
|
365
|
+
),
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Transfer instruction
|
|
370
|
+
instructions.push(
|
|
371
|
+
splToken.createTransferInstruction(
|
|
372
|
+
fromAta,
|
|
373
|
+
toAta,
|
|
374
|
+
keypair.publicKey,
|
|
375
|
+
rawAmount,
|
|
376
|
+
),
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
const { Transaction, sendAndConfirmTransaction } = await loadSolanaWeb3();
|
|
380
|
+
const transaction = new Transaction().add(...instructions);
|
|
381
|
+
|
|
382
|
+
const signature = await sendAndConfirmTransaction(connection, transaction, [
|
|
383
|
+
keypair,
|
|
384
|
+
]);
|
|
385
|
+
return { signature };
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* List all SPL token accounts for the wallet.
|
|
390
|
+
*/
|
|
391
|
+
async listSplTokenAccounts(): Promise<
|
|
392
|
+
Array<{ mint: string; amount: bigint; decimals: number }>
|
|
393
|
+
> {
|
|
394
|
+
const splToken = await loadSplToken();
|
|
395
|
+
const connection = await this.getConnection();
|
|
396
|
+
const keypair = await this.getKeypair();
|
|
397
|
+
|
|
398
|
+
const tokenAccounts = await connection.getParsedTokenAccountsByOwner(
|
|
399
|
+
keypair.publicKey,
|
|
400
|
+
{ programId: splToken.TOKEN_PROGRAM_ID },
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
return tokenAccounts.value.map((acc: ParsedSplTokenWalletAccountEntry) => {
|
|
404
|
+
const info = acc.account.data.parsed.info;
|
|
405
|
+
return {
|
|
406
|
+
mint: info.mint,
|
|
407
|
+
amount: BigInt(info.tokenAmount.amount),
|
|
408
|
+
decimals: info.tokenAmount.decimals,
|
|
409
|
+
};
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Create a SolanaWallet instance.
|
|
416
|
+
*/
|
|
417
|
+
export function createSolanaWallet(config: SolanaWalletConfig): SolanaWallet {
|
|
418
|
+
return new SolanaWallet(config);
|
|
419
|
+
}
|