sclaw-agent 1.0.0

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.
@@ -0,0 +1,96 @@
1
+ import { HELIUS_RPC_URL, HELIUS_API_KEY, HELIUS_API_URL } from '../config';
2
+ export async function heliusRpc(request) {
3
+ const res = await fetch(HELIUS_RPC_URL, {
4
+ method: 'POST',
5
+ headers: { 'Content-Type': 'application/json' },
6
+ body: JSON.stringify({
7
+ jsonrpc: '2.0',
8
+ id: 1,
9
+ method: request.method,
10
+ params: request.params,
11
+ }),
12
+ });
13
+ const data = await res.json();
14
+ if (data.error)
15
+ throw new Error(data.error.message);
16
+ return data.result;
17
+ }
18
+ export async function simulateTransaction(encodedTx) {
19
+ const result = await heliusRpc({
20
+ method: 'simulateTransaction',
21
+ params: [
22
+ encodedTx,
23
+ {
24
+ encoding: 'base64',
25
+ commitment: 'confirmed',
26
+ replaceRecentBlockhash: true,
27
+ accounts: {
28
+ encoding: 'jsonParsed',
29
+ addresses: [],
30
+ },
31
+ },
32
+ ],
33
+ });
34
+ return {
35
+ success: result.value.err === null,
36
+ logs: result.value.logs || [],
37
+ unitsConsumed: result.value.unitsConsumed || 0,
38
+ error: result.value.err ? JSON.stringify(result.value.err) : null,
39
+ accounts: result.value.accounts || [],
40
+ };
41
+ }
42
+ export async function getTokenMetadata(mintAddress) {
43
+ const res = await fetch(`${HELIUS_API_URL}/token-metadata?api-key=${HELIUS_API_KEY}`, {
44
+ method: 'POST',
45
+ headers: { 'Content-Type': 'application/json' },
46
+ body: JSON.stringify({
47
+ mintAccounts: [mintAddress],
48
+ includeOffChain: true,
49
+ disableCache: false,
50
+ }),
51
+ });
52
+ return res.json();
53
+ }
54
+ export async function getAsset(assetId) {
55
+ const res = await fetch(HELIUS_RPC_URL, {
56
+ method: 'POST',
57
+ headers: { 'Content-Type': 'application/json' },
58
+ body: JSON.stringify({
59
+ jsonrpc: '2.0',
60
+ id: 1,
61
+ method: 'getAsset',
62
+ params: { id: assetId },
63
+ }),
64
+ });
65
+ const data = await res.json();
66
+ return data.result;
67
+ }
68
+ export async function getBalance(address) {
69
+ const result = await heliusRpc({
70
+ method: 'getBalance',
71
+ params: [address],
72
+ });
73
+ return result.value;
74
+ }
75
+ export async function getTokenAccounts(ownerAddress) {
76
+ const result = await heliusRpc({
77
+ method: 'getTokenAccountsByOwner',
78
+ params: [
79
+ ownerAddress,
80
+ { programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' },
81
+ { encoding: 'jsonParsed' },
82
+ ],
83
+ });
84
+ return result;
85
+ }
86
+ export async function getTransactionHistory(address, limit = 10) {
87
+ const res = await fetch(`${HELIUS_API_URL}/addresses/${address}/transactions?api-key=${HELIUS_API_KEY}&limit=${limit}`);
88
+ return res.json();
89
+ }
90
+ export async function getParsedTransaction(signature) {
91
+ const result = await heliusRpc({
92
+ method: 'getTransaction',
93
+ params: [signature, { encoding: 'jsonParsed', maxSupportedTransactionVersion: 0 }],
94
+ });
95
+ return result;
96
+ }
@@ -0,0 +1,24 @@
1
+ export interface TokenSecurityReport {
2
+ mint: string;
3
+ name: string | null;
4
+ symbol: string | null;
5
+ supply: number | null;
6
+ decimals: number | null;
7
+ freezeAuthority: string | null;
8
+ mintAuthority: string | null;
9
+ isFreezable: boolean;
10
+ isMintable: boolean;
11
+ topHolders: {
12
+ address: string;
13
+ amount: number;
14
+ percentage: number;
15
+ }[];
16
+ holderConcentration: number;
17
+ lpInfo: {
18
+ locked: boolean;
19
+ pool: string | null;
20
+ } | null;
21
+ metadata: unknown;
22
+ risks: string[];
23
+ }
24
+ export declare function analyzeToken(mintAddress: string): Promise<TokenSecurityReport>;
@@ -0,0 +1,84 @@
1
+ import { heliusRpc, getTokenMetadata } from './helius';
2
+ export async function analyzeToken(mintAddress) {
3
+ const risks = [];
4
+ const mintInfo = await heliusRpc({
5
+ method: 'getAccountInfo',
6
+ params: [mintAddress, { encoding: 'jsonParsed' }],
7
+ });
8
+ const parsed = mintInfo?.value?.data?.parsed?.info;
9
+ const mintAuthority = parsed?.mintAuthority || null;
10
+ const freezeAuthority = parsed?.freezeAuthority || null;
11
+ const supply = parsed?.supply ? Number(parsed.supply) : null;
12
+ const decimals = parsed?.decimals ?? null;
13
+ const isMintable = mintAuthority !== null;
14
+ const isFreezable = freezeAuthority !== null;
15
+ if (isMintable)
16
+ risks.push('MINT_AUTHORITY_ACTIVE — token supply can be increased');
17
+ if (isFreezable)
18
+ risks.push('FREEZE_AUTHORITY_ACTIVE — accounts can be frozen');
19
+ let name = null;
20
+ let symbol = null;
21
+ let metadata = null;
22
+ try {
23
+ const metaResult = await getTokenMetadata(mintAddress);
24
+ if (metaResult?.[0]) {
25
+ metadata = metaResult[0];
26
+ name = metaResult[0]?.onChainMetadata?.metadata?.data?.name ||
27
+ metaResult[0]?.offChainMetadata?.metadata?.name || null;
28
+ symbol = metaResult[0]?.onChainMetadata?.metadata?.data?.symbol ||
29
+ metaResult[0]?.offChainMetadata?.metadata?.symbol || null;
30
+ }
31
+ }
32
+ catch {
33
+ risks.push('METADATA_FETCH_FAILED — could not retrieve token metadata');
34
+ }
35
+ let topHolders = [];
36
+ let holderConcentration = 0;
37
+ try {
38
+ const holders = await heliusRpc({
39
+ method: 'getTokenLargestAccounts',
40
+ params: [mintAddress],
41
+ });
42
+ const totalSupply = supply && decimals !== null ? supply / Math.pow(10, decimals) : 0;
43
+ topHolders = (holders?.value || []).slice(0, 10).map((h) => {
44
+ const amount = Number(h.amount) / Math.pow(10, decimals || 0);
45
+ const percentage = totalSupply > 0 ? (amount / totalSupply) * 100 : 0;
46
+ return {
47
+ address: h.address,
48
+ amount,
49
+ percentage: Math.round(percentage * 100) / 100,
50
+ };
51
+ });
52
+ holderConcentration = topHolders.reduce((sum, h) => sum + h.percentage, 0);
53
+ holderConcentration = Math.round(holderConcentration * 100) / 100;
54
+ if (holderConcentration > 80) {
55
+ risks.push(`HIGH_CONCENTRATION — top 10 holders own ${holderConcentration}% of supply`);
56
+ }
57
+ else if (holderConcentration > 50) {
58
+ risks.push(`MODERATE_CONCENTRATION — top 10 holders own ${holderConcentration}% of supply`);
59
+ }
60
+ const bigWhale = topHolders.find(h => h.percentage > 20);
61
+ if (bigWhale) {
62
+ risks.push(`WHALE_ALERT — single holder owns ${bigWhale.percentage}% (${bigWhale.address.slice(0, 8)}...)`);
63
+ }
64
+ }
65
+ catch {
66
+ risks.push('HOLDER_ANALYSIS_FAILED — could not fetch holder data');
67
+ }
68
+ return {
69
+ mint: mintAddress,
70
+ name,
71
+ symbol,
72
+ supply,
73
+ decimals,
74
+ freezeAuthority,
75
+ mintAuthority,
76
+ isFreezable,
77
+ isMintable,
78
+ topHolders,
79
+ holderConcentration,
80
+ lpInfo: null,
81
+ metadata,
82
+ risks,
83
+ };
84
+ }
@@ -0,0 +1 @@
1
+ export declare const riskRoute: import("express-serve-static-core").Router;
@@ -0,0 +1,57 @@
1
+ import { Router } from 'express';
2
+ import { getBalance, getTokenAccounts, getTransactionHistory } from '../lib/helius';
3
+ import { clawAnalyze } from '../lib/claw-agent';
4
+ export const riskRoute = Router();
5
+ riskRoute.get('/wallet/:address', async (req, res) => {
6
+ try {
7
+ const { address } = req.params;
8
+ const results = await Promise.allSettled([
9
+ getBalance(address),
10
+ getTokenAccounts(address),
11
+ getTransactionHistory(address, 5),
12
+ ]);
13
+ const balance = results[0].status === 'fulfilled' ? results[0].value : 0;
14
+ const tokenAccounts = results[1].status === 'fulfilled' ? results[1].value : { value: [] };
15
+ const recentTxs = results[2].status === 'fulfilled' ? results[2].value : [];
16
+ const txSummary = recentTxs?.map((tx) => ({
17
+ type: tx.type,
18
+ source: tx.source,
19
+ fee: tx.fee,
20
+ description: tx.description?.slice(0, 200),
21
+ timestamp: tx.timestamp,
22
+ })) || [];
23
+ const clawReport = await clawAnalyze(JSON.stringify({
24
+ type: 'WALLET_RISK_ANALYSIS',
25
+ address,
26
+ balanceSOL: balance / 1e9,
27
+ tokenAccountCount: tokenAccounts?.value?.length || 0,
28
+ recentTransactionSummary: txSummary,
29
+ }));
30
+ res.json({
31
+ address,
32
+ balanceSOL: balance / 1e9,
33
+ tokenAccounts,
34
+ recentTransactions: recentTxs,
35
+ clawAnalysis: clawReport,
36
+ });
37
+ }
38
+ catch (err) {
39
+ res.status(500).json({ error: err.message || 'Wallet analysis failed' });
40
+ }
41
+ });
42
+ riskRoute.post('/analyze', async (req, res) => {
43
+ try {
44
+ const { data, context } = req.body;
45
+ if (!data) {
46
+ return res.status(400).json({ error: 'Missing data for analysis' });
47
+ }
48
+ const clawReport = await clawAnalyze(JSON.stringify({
49
+ type: context || 'CUSTOM_ANALYSIS',
50
+ data,
51
+ }));
52
+ res.json({ clawAnalysis: clawReport });
53
+ }
54
+ catch (err) {
55
+ res.status(500).json({ error: err.message });
56
+ }
57
+ });
@@ -0,0 +1 @@
1
+ export declare const simulateRoute: import("express-serve-static-core").Router;
@@ -0,0 +1,60 @@
1
+ import { Router } from 'express';
2
+ import { simulateTransaction, getBalance, getParsedTransaction } from '../lib/helius';
3
+ import { clawAnalyze } from '../lib/claw-agent';
4
+ export const simulateRoute = Router();
5
+ simulateRoute.post('/transaction', async (req, res) => {
6
+ try {
7
+ const { transaction, walletAddress } = req.body;
8
+ if (!transaction) {
9
+ return res.status(400).json({ error: 'Missing transaction (base64 encoded)' });
10
+ }
11
+ let preBalance = null;
12
+ if (walletAddress) {
13
+ preBalance = await getBalance(walletAddress);
14
+ }
15
+ const simResult = await simulateTransaction(transaction);
16
+ let estimatedCost = null;
17
+ if (preBalance !== null && simResult.unitsConsumed > 0) {
18
+ estimatedCost = simResult.unitsConsumed * 0.000005;
19
+ }
20
+ const clawReport = await clawAnalyze(JSON.stringify({
21
+ type: 'TRANSACTION_SIMULATION',
22
+ success: simResult.success,
23
+ logs: simResult.logs,
24
+ unitsConsumed: simResult.unitsConsumed,
25
+ error: simResult.error,
26
+ walletAddress,
27
+ preBalance: preBalance ? preBalance / 1e9 : null,
28
+ estimatedCostSOL: estimatedCost,
29
+ }));
30
+ res.json({
31
+ simulation: simResult,
32
+ preBalance: preBalance ? preBalance / 1e9 : null,
33
+ estimatedCostSOL: estimatedCost,
34
+ clawAnalysis: clawReport,
35
+ });
36
+ }
37
+ catch (err) {
38
+ res.status(500).json({ error: err.message });
39
+ }
40
+ });
41
+ simulateRoute.post('/preview', async (req, res) => {
42
+ try {
43
+ const { signature } = req.body;
44
+ if (!signature) {
45
+ return res.status(400).json({ error: 'Missing transaction signature' });
46
+ }
47
+ const txData = await getParsedTransaction(signature);
48
+ const clawReport = await clawAnalyze(JSON.stringify({
49
+ type: 'TRANSACTION_REVIEW',
50
+ transaction: txData,
51
+ }));
52
+ res.json({
53
+ transaction: txData,
54
+ clawAnalysis: clawReport,
55
+ });
56
+ }
57
+ catch (err) {
58
+ res.status(500).json({ error: err.message });
59
+ }
60
+ });
@@ -0,0 +1 @@
1
+ export declare const tokenRoute: import("express-serve-static-core").Router;
@@ -0,0 +1,36 @@
1
+ import { Router } from 'express';
2
+ import { analyzeToken } from '../lib/token-analysis';
3
+ import { getTransactionHistory } from '../lib/helius';
4
+ import { clawAnalyze } from '../lib/claw-agent';
5
+ export const tokenRoute = Router();
6
+ tokenRoute.get('/:mint', async (req, res) => {
7
+ try {
8
+ const { mint } = req.params;
9
+ if (!mint || mint.length < 32) {
10
+ return res.status(400).json({ error: 'Invalid mint address' });
11
+ }
12
+ const report = await analyzeToken(mint);
13
+ const clawReport = await clawAnalyze(JSON.stringify({
14
+ type: 'TOKEN_SECURITY_ANALYSIS',
15
+ ...report,
16
+ }));
17
+ res.json({
18
+ token: report,
19
+ clawAnalysis: clawReport,
20
+ });
21
+ }
22
+ catch (err) {
23
+ res.status(500).json({ error: err.message });
24
+ }
25
+ });
26
+ tokenRoute.get('/:mint/history', async (req, res) => {
27
+ try {
28
+ const { mint } = req.params;
29
+ const limit = parseInt(req.query.limit) || 10;
30
+ const history = await getTransactionHistory(mint, limit);
31
+ res.json({ history });
32
+ }
33
+ catch (err) {
34
+ res.status(500).json({ error: err.message });
35
+ }
36
+ });
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "sclaw-agent",
3
+ "version": "1.0.0",
4
+ "description": "SCLAW — ShadowClawAI Pre-Execution Engine. Simulate Solana transactions, analyze token security, get AI risk reports.",
5
+ "type": "module",
6
+ "main": "server/index.ts",
7
+ "bin": {
8
+ "sclaw": "./dist/cli/index.js"
9
+ },
10
+ "scripts": {
11
+ "server": "npx tsx server/index.ts",
12
+ "cli": "npx tsx cli/index.ts",
13
+ "build": "npx tsc",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "solana",
18
+ "transaction",
19
+ "simulator",
20
+ "security",
21
+ "ai",
22
+ "claw",
23
+ "helius",
24
+ "token",
25
+ "risk",
26
+ "pre-execution",
27
+ "blockchain",
28
+ "defi",
29
+ "web3"
30
+ ],
31
+ "author": "sclaw-ai",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/alc0hol120/SHADOWCLAW"
36
+ },
37
+ "homepage": "https://github.com/alc0hol120/SHADOWCLAW",
38
+ "files": [
39
+ "dist",
40
+ "server",
41
+ "cli",
42
+ "README.md"
43
+ ],
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "dependencies": {
48
+ "@solana/web3.js": "^1.98.4",
49
+ "cors": "^2.8.6",
50
+ "express": "^5.2.1"
51
+ },
52
+ "devDependencies": {
53
+ "@types/cors": "^2.8.19",
54
+ "@types/express": "^5.0.6",
55
+ "@types/node": "^24.12.0",
56
+ "tsx": "^4.21.0",
57
+ "typescript": "~5.9.3"
58
+ }
59
+ }
@@ -0,0 +1,5 @@
1
+ export const HELIUS_API_KEY = process.env.HELIUS_API_KEY || '';
2
+ export const HELIUS_RPC_URL = `https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`;
3
+ export const HELIUS_API_URL = `https://api.helius.xyz/v0`;
4
+ export const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY || '';
5
+ export const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions';
@@ -0,0 +1,23 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import { simulateRoute } from './routes/simulate';
4
+ import { tokenRoute } from './routes/token';
5
+ import { riskRoute } from './routes/risk';
6
+
7
+ const app = express();
8
+ const PORT = process.env.PORT || 3001;
9
+
10
+ app.use(cors());
11
+ app.use(express.json());
12
+
13
+ app.use('/api/simulate', simulateRoute);
14
+ app.use('/api/token', tokenRoute);
15
+ app.use('/api/risk', riskRoute);
16
+
17
+ app.get('/api/health', (_req, res) => {
18
+ res.json({ status: 'CLAW Engine Online', version: '1.0.0' });
19
+ });
20
+
21
+ app.listen(PORT, () => {
22
+ console.log(`[CLAW] ShadowClaw engine running on port ${PORT}`);
23
+ });
@@ -0,0 +1,78 @@
1
+ import { OPENROUTER_API_KEY, OPENROUTER_URL } from '../config';
2
+
3
+ const CLAW_SYSTEM_PROMPT = `You are CLAW (ShadowClawAI), a specialized AI agent for blockchain transaction analysis and risk assessment.
4
+
5
+ Your role:
6
+ - Analyze transaction simulation results and identify risks
7
+ - Detect potential rug pulls, honeypots, and scam patterns
8
+ - Assess smart contract risks based on on-chain data
9
+ - Provide clear, actionable risk reports
10
+
11
+ Rules:
12
+ - Be direct and precise. No fluff.
13
+ - Always provide a risk score from 0-100 (0 = safe, 100 = extreme danger)
14
+ - Categorize risks: SAFE, LOW, MEDIUM, HIGH, CRITICAL
15
+ - Flag specific red flags with evidence
16
+ - Never give financial advice, only technical risk analysis
17
+ - Use real data only, never fabricate information`;
18
+
19
+ export interface ClawAnalysis {
20
+ riskScore: number;
21
+ riskLevel: 'SAFE' | 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
22
+ summary: string;
23
+ flags: string[];
24
+ details: string;
25
+ }
26
+
27
+ export async function clawAnalyze(context: string): Promise<ClawAnalysis> {
28
+ const res = await fetch(OPENROUTER_URL, {
29
+ method: 'POST',
30
+ headers: {
31
+ 'Content-Type': 'application/json',
32
+ 'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
33
+ 'HTTP-Referer': 'https://sclaw.ai',
34
+ 'X-Title': 'SCLAW - ShadowClawAI',
35
+ },
36
+ body: JSON.stringify({
37
+ model: 'anthropic/claude-sonnet-4',
38
+ messages: [
39
+ { role: 'system', content: CLAW_SYSTEM_PROMPT },
40
+ {
41
+ role: 'user',
42
+ content: `Analyze the following blockchain data and provide a risk assessment. Respond ONLY with valid JSON matching this schema:
43
+ {
44
+ "riskScore": number (0-100),
45
+ "riskLevel": "SAFE" | "LOW" | "MEDIUM" | "HIGH" | "CRITICAL",
46
+ "summary": "one-line summary",
47
+ "flags": ["array of specific red flags"],
48
+ "details": "detailed analysis"
49
+ }
50
+
51
+ Data to analyze:
52
+ ${context}`,
53
+ },
54
+ ],
55
+ temperature: 0.1,
56
+ max_tokens: 2000,
57
+ }),
58
+ });
59
+
60
+ const data = await res.json();
61
+ const content = data.choices?.[0]?.message?.content || '';
62
+
63
+ try {
64
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
65
+ if (jsonMatch) {
66
+ return JSON.parse(jsonMatch[0]);
67
+ }
68
+ } catch {
69
+ }
70
+
71
+ return {
72
+ riskScore: -1,
73
+ riskLevel: 'MEDIUM',
74
+ summary: 'CLAW agent could not complete analysis',
75
+ flags: ['Analysis incomplete — review manually'],
76
+ details: content,
77
+ };
78
+ }
@@ -0,0 +1,117 @@
1
+ import { HELIUS_RPC_URL, HELIUS_API_KEY, HELIUS_API_URL } from '../config';
2
+
3
+ interface HeliusRpcRequest {
4
+ method: string;
5
+ params: unknown[];
6
+ }
7
+
8
+ export async function heliusRpc(request: HeliusRpcRequest): Promise<unknown> {
9
+ const res = await fetch(HELIUS_RPC_URL, {
10
+ method: 'POST',
11
+ headers: { 'Content-Type': 'application/json' },
12
+ body: JSON.stringify({
13
+ jsonrpc: '2.0',
14
+ id: 1,
15
+ method: request.method,
16
+ params: request.params,
17
+ }),
18
+ });
19
+ const data = await res.json();
20
+ if (data.error) throw new Error(data.error.message);
21
+ return data.result;
22
+ }
23
+
24
+ export async function simulateTransaction(encodedTx: string): Promise<{
25
+ success: boolean;
26
+ logs: string[];
27
+ unitsConsumed: number;
28
+ error: string | null;
29
+ accounts: unknown[];
30
+ }> {
31
+ const result = await heliusRpc({
32
+ method: 'simulateTransaction',
33
+ params: [
34
+ encodedTx,
35
+ {
36
+ encoding: 'base64',
37
+ commitment: 'confirmed',
38
+ replaceRecentBlockhash: true,
39
+ accounts: {
40
+ encoding: 'jsonParsed',
41
+ addresses: [],
42
+ },
43
+ },
44
+ ],
45
+ }) as any;
46
+
47
+ return {
48
+ success: result.value.err === null,
49
+ logs: result.value.logs || [],
50
+ unitsConsumed: result.value.unitsConsumed || 0,
51
+ error: result.value.err ? JSON.stringify(result.value.err) : null,
52
+ accounts: result.value.accounts || [],
53
+ };
54
+ }
55
+
56
+ export async function getTokenMetadata(mintAddress: string): Promise<unknown> {
57
+ const res = await fetch(`${HELIUS_API_URL}/token-metadata?api-key=${HELIUS_API_KEY}`, {
58
+ method: 'POST',
59
+ headers: { 'Content-Type': 'application/json' },
60
+ body: JSON.stringify({
61
+ mintAccounts: [mintAddress],
62
+ includeOffChain: true,
63
+ disableCache: false,
64
+ }),
65
+ });
66
+ return res.json();
67
+ }
68
+
69
+ export async function getAsset(assetId: string): Promise<unknown> {
70
+ const res = await fetch(HELIUS_RPC_URL, {
71
+ method: 'POST',
72
+ headers: { 'Content-Type': 'application/json' },
73
+ body: JSON.stringify({
74
+ jsonrpc: '2.0',
75
+ id: 1,
76
+ method: 'getAsset',
77
+ params: { id: assetId },
78
+ }),
79
+ });
80
+ const data = await res.json();
81
+ return data.result;
82
+ }
83
+
84
+ export async function getBalance(address: string): Promise<number> {
85
+ const result = await heliusRpc({
86
+ method: 'getBalance',
87
+ params: [address],
88
+ }) as any;
89
+ return result.value;
90
+ }
91
+
92
+ export async function getTokenAccounts(ownerAddress: string): Promise<unknown> {
93
+ const result = await heliusRpc({
94
+ method: 'getTokenAccountsByOwner',
95
+ params: [
96
+ ownerAddress,
97
+ { programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' },
98
+ { encoding: 'jsonParsed' },
99
+ ],
100
+ });
101
+ return result;
102
+ }
103
+
104
+ export async function getTransactionHistory(address: string, limit = 10): Promise<unknown> {
105
+ const res = await fetch(
106
+ `${HELIUS_API_URL}/addresses/${address}/transactions?api-key=${HELIUS_API_KEY}&limit=${limit}`
107
+ );
108
+ return res.json();
109
+ }
110
+
111
+ export async function getParsedTransaction(signature: string): Promise<unknown> {
112
+ const result = await heliusRpc({
113
+ method: 'getTransaction',
114
+ params: [signature, { encoding: 'jsonParsed', maxSupportedTransactionVersion: 0 }],
115
+ });
116
+ return result;
117
+ }