Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e8f4633
.env, .elizadb*
odilitime Oct 16, 2025
64be54c
core to latest, bump spl-token, add spl-token-metadata
odilitime Oct 16, 2025
c029a73
fix npm org
odilitime Oct 16, 2025
edaf09f
general update
odilitime Oct 16, 2025
296a2a7
add declarationDir & exclude
odilitime Oct 16, 2025
70f0881
add declarationDir
odilitime Oct 16, 2025
7b803fd
modernize init, export service symbols, update description
odilitime Oct 16, 2025
f0a04b9
new file per PR9
odilitime Oct 16, 2025
c5f2503
getAddressesTypes(), getCirculatingSupplies(), getDecimals(), getToke…
odilitime Oct 16, 2025
2c7f488
SOL_ADDRESS isn't required
odilitime Oct 16, 2025
be2e9a5
minor clean up
odilitime Oct 16, 2025
7812a62
bump tsup/typescript versions
odilitime Oct 16, 2025
a859be4
go to TS 5.9.3
odilitime Oct 16, 2025
e93026c
fix ServiceTypeName type
odilitime Oct 16, 2025
e4c08ba
bun build
odilitime Oct 17, 2025
878a32d
switch to bun build, include service-interfaces, bun-types, more deps…
odilitime Oct 17, 2025
5a04d1a
modernize, fix types
odilitime Oct 17, 2025
c02c208
modernize, guards/fix types
odilitime Oct 17, 2025
47c87b8
newer zod uses issues not errors
odilitime Oct 17, 2025
dad5abc
fix types
odilitime Oct 17, 2025
dfbe9d0
update comment to match
odilitime Oct 17, 2025
3b1065c
change lib, remove paths/baseUrl, gpt reorder
odilitime Oct 17, 2025
00695c6
bun types, no declaration
odilitime Oct 17, 2025
1dfee25
ISolanaPluginServiceAPI/IWalletService extension/support, type fixes
odilitime Oct 17, 2025
29a91dc
remove types
odilitime Oct 17, 2025
ecccb09
make only public key required
odilitime Oct 17, 2025
759f9cb
getPublicKey is not async
odilitime Oct 17, 2025
a1d5e52
getPortfolio - fix assets
odilitime Oct 17, 2025
f020d0e
implement transferSol, fetchPrices update key, getWalletKeypair use p…
odilitime Oct 17, 2025
ae7546e
split SolanaWalletService from SolanaService
odilitime Oct 20, 2025
a5afbb5
split SolanaWalletService from SolanaService, adjust private/public, …
odilitime Oct 20, 2025
9b98467
add catch to init promise
odilitime Oct 20, 2025
d9396e8
getBalance fixes, clean up subscription, fix types
odilitime Oct 21, 2025
60eda4b
getBalance fix, getAddressesTypes better implementation, fix warning
odilitime Oct 21, 2025
dac64af
additional number warning fixes
odilitime Oct 21, 2025
fcf5815
fix name in comment
odilitime Oct 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
node_modules
.turbo
dist
.env
.elizadb
.elizadb-test
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# @elizaos-plugins/plugin-solana
# @elizaos/plugin-solana

Core Solana blockchain plugin for Eliza OS that provides essential services and actions for token operations, trading, and DeFi integrations.

Expand Down Expand Up @@ -55,7 +55,7 @@ The Solana plugin serves as a foundational component of Eliza OS, bridging Solan
## Installation

```bash
npm install @elizaos-plugins/plugin-solana
npm install @elizaos/plugin-solana
```

## Configuration
Expand All @@ -80,7 +80,7 @@ const solanaEnvSchema = {
### Basic Setup

```typescript
import { solanaPlugin } from '@elizaos-plugins/plugin-solana';
import { solanaPlugin } from '@elizaos/plugin-solana';

// Initialize the plugin
const runtime = await initializeRuntime({
Expand Down
38 changes: 38 additions & 0 deletions build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bun
/**
* Build script for @elizaos/plugin-solana using standardized build utilities
*/

import { createBuildRunner } from '../../build-utils';

// Create and run the standardized build runner
const run = createBuildRunner({
packageName: '@elizaos/plugin-solana',
buildOptions: {
entrypoints: ['src/index.ts'],
outdir: 'dist',
target: 'bun', // instead of 'node'
format: 'esm',
strict: true,
clean: true,
external: [
// keep third-party externals
'dotenv','@reflink/reflink','@node-llama-cpp',
'agentkeepalive','safe-buffer','base-x','bs58','borsh',
'@solana/buffer-layout','querystring',
'@elizaos/core','@elizaos/service-interfaces','zod',
'node:stream/web', // optional if you reference it; bun-types has it
'fs','path','https','http','stream','buffer'
],
sourcemap: true,
minify: false,
generateDts: false,
},
});


// Execute the build
run().catch((error) => {
//console.error('Build script error:', error);
process.exit(1);
});
32 changes: 32 additions & 0 deletions env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Solana Plugin Environment Variables
# Copy this file to .env and fill in your actual values

# Solana RPC URL (required)
# You can use public endpoints or get a dedicated one from providers like Helius, QuickNode, etc.
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com

# Birdeye API Key (required for price data and portfolio valuation)
# Get your free API key from https://birdeye.so/
BIRDEYE_API_KEY=YourBirdeyeApiKeyHere

# Optional: Helius API Key (for enhanced RPC features)
# Get your API key from https://helius.xyz/
HELIUS_API_KEY=YourHeliusApiKeyHere

# Solana Private Key (base58 encoded)
# Required for sending transactions (like transfers, swaps) and for account subscriptions.
# If not provided, the plugin will operate in a read-only mode for basic portfolio viewing (if public key was previously used/cached or if functionality is adapted to not require it for reads).
# WARNING: Keep this secret and never commit to version control if you put a real one here for testing.
# For development, if this is not set, a new key may be generated by some test environments.
SOLANA_PRIVATE_KEY=YourPrivateKeyHere_Base58Encoded_e_g_5jZ2p...

# Optional: Slippage tolerance for swaps (default: 0.5%)
SLIPPAGE=0.5

# Optional: SOL token address (usually the wrapped SOL address for DeFi interactions)
SOL_ADDRESS=So11111111111111111111111111111111111111112

# Example values for testing (replace with your actual values if needed):
# SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
# BIRDEYE_API_KEY=your-birdeye-api-key-here
# SOLANA_PRIVATE_KEY= # Fill with a testnet/devnet private key for transaction tests
40 changes: 24 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "@elizaos/plugin-solana",
"version": "1.2.0",
"engines": { "bun": ">=1.1.0" },
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/elizaos-plugins/plugin-solana.git"
Expand All @@ -21,33 +21,41 @@
"files": [
"dist"
],
"dependencies": {
"@elizaos/core": "^1.0.0",
"@solana/spl-token": "0.4.13",
"@solana/web3.js": "^1.98.0",
"bignumber.js": "9.3.0",
"bs58": "6.0.0",
"tweetnacl": "^1.0.3",
"vitest": "3.1.3"
},
"devDependencies": {
"prettier": "3.5.3",
"tsup": "8.4.0",
"typescript": "^5.8.2"
},
"scripts": {
"build": "tsup",
"build": "bun run build.ts",
"dev": "tsup --watch",
"test": "vitest run",
"lint": "prettier --write ./src",
"clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json tsconfig.tsbuildinfo",
"format": "prettier --write ./src",
"format:check": "prettier --check ./src"
},
"dependencies": {
"@solana/spl-token": "0.4.14",
"@solana/spl-token-metadata": "^0.1.6",
"@solana/web3.js": "^1.98.0",
"bignumber.js": "9.3.0",
"bs58": "6.0.0",
"tweetnacl": "^1.0.3"
},
"devDependencies": {
"@elizaos/core": "latest",
"@elizaos/service-interfaces": "latest",
"bun-types": "^1.3.0",
"prettier": "3.5.3",
"tsup": "8.5.0",
"typescript": "^5.9.3",
"vitest": "3.1.3"
},
"peerDependencies": {
"@elizaos/core": "latest",
"@elizaos/service-interfaces": "latest",
"form-data": "4.0.2",
"whatwg-url": "7.1.0"
},
"tsup": {
"external": ["@elizaos/core", "@elizaos/service-interfaces"]
},
"gitHead": "646c632924826e2b75c2304a75ee56959fe4a460",
"agentConfig": {
"pluginType": "elizaos:plugin:1.0.0",
Expand Down
27 changes: 14 additions & 13 deletions src/actions/swap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
type Action,
type ActionExample,
type ActionResult,
type HandlerCallback,
type IAgentRuntime,
type Memory,
Expand Down Expand Up @@ -72,11 +73,11 @@ async function swapToken(
const amountBN = new BigNumber(amount);
const adjustedAmount = amountBN.multipliedBy(new BigNumber(10).pow(decimals));

logger.log('Fetching quote with params:', {
logger.log({
inputMint: inputTokenCA,
outputMint: outputTokenCA,
amount: adjustedAmount,
});
}, 'Fetching quote with params:');

const quoteResponse = await fetch(
`https://quote-api.jup.ag/v6/quote?inputMint=${inputTokenCA}&outputMint=${outputTokenCA}&amount=${adjustedAmount}&dynamicSlippage=true&maxAccounts=64`
Expand All @@ -86,7 +87,7 @@ async function swapToken(
};

if (!quoteData || quoteData.error) {
logger.error('Quote error:', quoteData);
logger.error({ quoteData },'Quote error');
throw new Error(`Failed to get quote: ${quoteData?.error || 'Unknown error'}`);
}

Expand All @@ -113,15 +114,15 @@ async function swapToken(
};

if (!swapData || !swapData.swapTransaction) {
logger.error('Swap error:', swapData);
logger.error({ swapData }, 'Swap error');
throw new Error(
`Failed to get swap transaction: ${swapData?.error || 'No swap transaction returned'}`
);
}

return swapData;
} catch (error) {
logger.error('Error in swapToken:', error);
logger.error({ error }, 'Error in swapToken:');
throw error;
}
}
Expand Down Expand Up @@ -155,7 +156,7 @@ async function getTokenFromWallet(

return token ? token.address : null;
} catch (error) {
logger.error('Error checking token in wallet:', error);
logger.error({ error }, 'Error checking token in wallet');
return null;
}
}
Expand Down Expand Up @@ -250,7 +251,7 @@ export const executeSwap: Action = {
state: State | undefined,
_options: { [key: string]: unknown } | undefined,
callback?: HandlerCallback
): Promise<boolean> => {
): Promise<void | ActionResult | undefined> => {
state = await runtime.composeState(message, ['RECENT_MESSAGES']);

try {
Expand Down Expand Up @@ -293,7 +294,7 @@ export const executeSwap: Action = {
(await getTokenFromWallet(runtime, response.inputTokenSymbol)) || undefined;
if (!response.inputTokenCA) {
callback?.({ text: 'Could not find the input token in your wallet' });
return false;
return;
}
}

Expand All @@ -304,13 +305,13 @@ export const executeSwap: Action = {
callback?.({
text: 'Could not find the output token in your wallet',
});
return false;
return;
}
}

if (!response.amount) {
callback?.({ text: 'Please specify the amount you want to swap' });
return false;
return;
}

const connection = new Connection(
Expand Down Expand Up @@ -365,15 +366,15 @@ export const executeSwap: Action = {
content: { success: true, txid },
});

return true;
return;
} catch (error) {
if (error instanceof Error) {
logger.error('Error during token swap:', error);
logger.error({ error }, 'Error during token swap');
callback?.({
text: `Swap failed: ${error.message}`,
content: { error: error.message },
});
return false;
return;
}
throw error;
}
Expand Down
Loading