-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: plugin Solana web3.js V2 & automated LPing on Orca #2136
base: develop
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughThe pull request introduces a new Solana Plugin V2 ( Changes
Possibly related PRs
Suggested Labels
Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
🧹 Nitpick comments (9)
packages/plugin-solana-v2/src/providers/orca/positionProvider.ts (1)
50-50
: Use consistent variable naming.Variable
FetchedPositionsStatistics
should be in camelCase to match naming conventions.Apply this diff for consistency:
- const FetchedPositionsStatistics: FetchedPositionStatistics[] = await Promise.all(positions.map(async (position) => { + const fetchedPositionsStatistics: FetchedPositionStatistics[] = await Promise.all(positions.map(async (position) => {packages/plugin-solana-v2/src/utils/TEE/deriveKeyProvider.ts (2)
24-26
: Replaceconsole.log
withelizaLogger
for consistent logging.Use the provided logging utility for uniform log management.
Example changes:
- console.log("TEE: Connecting to local simulator at localhost:8090"); + elizaLogger.log("TEE: Connecting to local simulator at localhost:8090");Apply similar changes to other
console.log
statements.Also applies to: 30-32, 36-38, 59-62, 77-79, 92-93
107-134
: Ensure consistent error handling and return values inget
method.Returning empty strings on error may lead to unclear failures. Consider throwing exceptions or returning
null
.packages/plugin-solana-v2/src/index.ts (1)
14-21
: Remove commented-outorcaPlugin
code.Cleaning up unused code improves readability.
Apply this diff to remove the commented code:
-// export const orcaPlugin: Plugin = { -// name: "orca", -// description: "Orca Plugin for Eliza", -// actions: [managePositions, repositionPositions], -// evaluators: [repositionEvaluator], -// providers: [positionProvider], -// }packages/plugin-solana-v2/src/evaluators/orca/repositionEvaluator.ts (1)
38-38
: Fix typo in variable name.The variable name contains a typo.
- const instervalMs = config.intervalSeconds * 1000; + const intervalMs = config.intervalSeconds * 1000;packages/plugin-solana-v2/tsup.config.ts (1)
3-26
: Consider additional build optimizations.The configuration could benefit from performance improvements.
export default defineConfig({ entry: ['src/index.ts'], format: ['esm'], dts: true, splitting: false, sourcemap: true, clean: true, + minify: true, + treeshake: true, external: [package.json (1)
51-53
: Well-structured version management strategy.The overrides section effectively manages multiple web3.js versions:
- v1.95.5 for NFT generation
- v1.95.8 for core and plugin-solana
- v2.0.0 for the new plugin-solana-v2
Consider documenting this version management strategy in the project's README to help future contributors understand the multi-version setup.
packages/plugin-solana-v2/README.md (2)
26-26
: Fix typo: "isntance" → "instance"-- Accepts the RPC isntance, transaction instructions, and a wallet. ++ Accepts the RPC instance, transaction instructions, and a wallet.
70-76
: Enhance code example with importsThe configuration example should include import statements for better clarity.
+import { managePositions, repositionPosition } from './actions'; +import { repositionEvaluator } from './evaluators'; +import { positionProvider } from './providers'; + export const solanaPluginV2: Plugin = { name: "solanaV2", description: "Solana Plugin V2 for Eliza",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (20)
agent/package.json
(1 hunks)agent/src/index.ts
(3 hunks)package.json
(1 hunks)packages/core/package.json
(1 hunks)packages/plugin-nft-generation/package.json
(1 hunks)packages/plugin-solana-v2/README.md
(1 hunks)packages/plugin-solana-v2/package.json
(1 hunks)packages/plugin-solana-v2/src/actions/orca/managePositions.ts
(1 hunks)packages/plugin-solana-v2/src/evaluators/orca/repositionEvaluator.ts
(1 hunks)packages/plugin-solana-v2/src/index.ts
(1 hunks)packages/plugin-solana-v2/src/providers/orca/positionProvider.ts
(1 hunks)packages/plugin-solana-v2/src/utils/TEE/deriveKeyProvider.ts
(1 hunks)packages/plugin-solana-v2/src/utils/TEE/remoteAttestationProvider.ts
(1 hunks)packages/plugin-solana-v2/src/utils/TEE/types.ts
(1 hunks)packages/plugin-solana-v2/src/utils/loadWallet.ts
(1 hunks)packages/plugin-solana-v2/src/utils/sendMessage.ts
(1 hunks)packages/plugin-solana-v2/src/utils/sendTransaction.ts
(1 hunks)packages/plugin-solana-v2/tsconfig.json
(1 hunks)packages/plugin-solana-v2/tsup.config.ts
(1 hunks)packages/plugin-solana/package.json
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/plugin-solana-v2/tsconfig.json
🧰 Additional context used
🪛 LanguageTool
packages/plugin-solana-v2/README.md
[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...TEE functionality. - sendTransaction
: Smart transaction handling with CU opti...
(UNLIKELY_OPENING_PUNCTUATION)
🪛 Biome (1.9.4)
packages/plugin-solana-v2/src/actions/orca/managePositions.ts
[error] 219-219: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
[error] 246-246: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
🔇 Additional comments (11)
packages/plugin-solana-v2/src/utils/loadWallet.ts (1)
1-83
: LGTMThe
loadWallet
function is well-implemented, correctly handling different TEE modes and runtime settings to return the appropriate keypair or public key.agent/src/index.ts (4)
58-58
: ImportingsolanaPluginV2
.The import statement correctly brings in the new Solana V2 plugin.
537-537
: Conditional inclusion ofsolanaPluginV2
.The logic properly includes the plugin when Solana credentials are present.
609-609
: AddingechoChamberPlugin
based on secrets.The plugin is conditionally added when the required secrets are available.
614-614
: Using.flat()
to handle nested plugin arrays.Flattening the plugins array ensures correct plugin integration.
packages/plugin-solana-v2/src/utils/TEE/types.ts (2)
1-6
: EnumTEEMode
is well-defined.It accurately represents the different TEE modes with clear comments.
8-11
: InterfaceRemoteAttestationQuote
is properly defined.The structure includes necessary properties for attestation quotes.
packages/plugin-solana/package.json (1)
27-27
: LGTM! Explicit npm alias helps prevent version conflicts.The change to use
npm:@solana/[email protected]
ensures consistent version resolution.packages/plugin-nft-generation/package.json (1)
30-30
: LGTM! Consistent version management approach.Using
npm:@solana/[email protected]
aligns with the project-wide version resolution strategy.packages/core/package.json (1)
42-42
: LGTM! Maintains version consistency.The explicit npm alias for web3.js matches the project-wide approach.
agent/package.json (1)
51-51
: Verify integration with existing Solana plugin.The addition of
@elizaos/plugin-solana-v2
alongside the existing v1 plugin requires careful consideration of plugin initialization order and potential conflicts.✅ Verification successful
No plugin conflict risk detected
The codebase implements controlled loading of Solana plugins:
- V2 plugin loads for standard Solana operations
- V1 plugin only activates in TEE mode with specific configuration
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for potential plugin conflicts rg -A 5 "plugin-solana|plugin-solana-v2" | grep -i "initialize\|setup\|configure"Length of output: 368
Script:
#!/bin/bash # Search for plugin imports and usage echo "=== Checking imports and plugin registration ===" rg -l "plugin-solana-v2|@elizaos/plugin-solana-v2" echo -e "\n=== Checking plugin initialization patterns ===" ast-grep --pattern 'import $_ from "@elizaos/plugin-solana$$$"' ast-grep --pattern 'import $_ from "@elizaos/plugin-solana-v2$$$"' echo -e "\n=== Looking for plugin registration code ===" rg -A 5 "registerPlugin|addPlugin|usePlugin"Length of output: 5800
Script:
#!/bin/bash echo "=== Checking agent initialization code ===" cat agent/src/index.ts echo -e "\n=== Looking for plugin configuration patterns ===" ast-grep --pattern 'new AgentRuntime($$$)'Length of output: 37411
const prioritizationFee = await rpc.getRecentPrioritizationFees() | ||
.send() | ||
.then(fees => | ||
fees | ||
.map(fee => Number(fee.prioritizationFee)) | ||
.sort((a, b) => a - b) | ||
[Math.ceil(0.95 * fees.length) - 1] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle empty prioritization fees array
If getRecentPrioritizationFees()
returns an empty array, the calculation of prioritizationFee
will fail due to accessing an undefined index. Ensure that you handle the case when no fees are returned.
Apply this diff to handle empty fees:
const fees = await rpc.getRecentPrioritizationFees()
.send();
+ if (!fees || fees.length === 0) {
+ throw new Error('No prioritization fees available');
+ }
const prioritizationFee = fees
.map(fee => Number(fee.prioritizationFee))
.sort((a, b) => a - b)
[Math.ceil(0.95 * fees.length) - 1];
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const prioritizationFee = await rpc.getRecentPrioritizationFees() | |
.send() | |
.then(fees => | |
fees | |
.map(fee => Number(fee.prioritizationFee)) | |
.sort((a, b) => a - b) | |
[Math.ceil(0.95 * fees.length) - 1] | |
); | |
const fees = await rpc.getRecentPrioritizationFees() | |
.send(); | |
if (!fees || fees.length === 0) { | |
throw new Error('No prioritization fees available'); | |
} | |
const prioritizationFee = fees | |
.map(fee => Number(fee.prioritizationFee)) | |
.sort((a, b) => a - b) | |
[Math.ceil(0.95 * fees.length) - 1]; |
while (Date.now() - startTime < timeoutMs) { | ||
const transactionStartTime = Date.now(); | ||
const signature = await rpc.sendTransaction(base64EncodedWireTransaction, { | ||
maxRetries: 0n, | ||
skipPreflight: true, | ||
encoding: 'base64' | ||
}).send(); | ||
const statuses = await rpc.getSignatureStatuses([signature]).send(); | ||
if (statuses.value[0]) { | ||
if (!statuses.value[0].err) { | ||
elizaLogger.log(`Transaction confirmed: ${signature}`); | ||
return signature | ||
} else { | ||
throw new Error(`Transaction failed: ${statuses.value[0].err.toString()}`); | ||
} | ||
} | ||
const elapsedTime = Date.now() - transactionStartTime; | ||
const remainingTime = Math.max(0, 1000 - elapsedTime); | ||
if (remainingTime > 0) { | ||
await new Promise(resolve => setTimeout(resolve, remainingTime)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for transaction sending and confirmation
If rpc.sendTransaction()
or rpc.getSignatureStatuses()
throw an error, the exception isn't caught, which may cause the function to fail unexpectedly. Wrap these calls in a try-catch block to handle exceptions gracefully.
Apply this diff to add error handling:
while (Date.now() - startTime < timeoutMs) {
const transactionStartTime = Date.now();
+ try {
const signature = await rpc.sendTransaction(base64EncodedWireTransaction, {
maxRetries: 0n,
skipPreflight: true,
encoding: 'base64'
}).send();
const statuses = await rpc.getSignatureStatuses([signature]).send();
if (statuses.value[0]) {
if (!statuses.value[0].err) {
elizaLogger.log(`Transaction confirmed: ${signature}`);
return signature;
} else {
throw new Error(`Transaction failed: ${statuses.value[0].err.toString()}`);
}
}
+ } catch (error) {
+ elizaLogger.error(`Error sending transaction: ${error}`);
+ // Optionally handle retry logic or exit
+ }
const elapsedTime = Date.now() - transactionStartTime;
const remainingTime = Math.max(0, 1000 - elapsedTime);
if (remainingTime > 0) {
await new Promise(resolve => setTimeout(resolve, remainingTime));
}
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
while (Date.now() - startTime < timeoutMs) { | |
const transactionStartTime = Date.now(); | |
const signature = await rpc.sendTransaction(base64EncodedWireTransaction, { | |
maxRetries: 0n, | |
skipPreflight: true, | |
encoding: 'base64' | |
}).send(); | |
const statuses = await rpc.getSignatureStatuses([signature]).send(); | |
if (statuses.value[0]) { | |
if (!statuses.value[0].err) { | |
elizaLogger.log(`Transaction confirmed: ${signature}`); | |
return signature | |
} else { | |
throw new Error(`Transaction failed: ${statuses.value[0].err.toString()}`); | |
} | |
} | |
const elapsedTime = Date.now() - transactionStartTime; | |
const remainingTime = Math.max(0, 1000 - elapsedTime); | |
if (remainingTime > 0) { | |
await new Promise(resolve => setTimeout(resolve, remainingTime)); | |
} | |
} | |
while (Date.now() - startTime < timeoutMs) { | |
const transactionStartTime = Date.now(); | |
try { | |
const signature = await rpc.sendTransaction(base64EncodedWireTransaction, { | |
maxRetries: 0n, | |
skipPreflight: true, | |
encoding: 'base64' | |
}).send(); | |
const statuses = await rpc.getSignatureStatuses([signature]).send(); | |
if (statuses.value[0]) { | |
if (!statuses.value[0].err) { | |
elizaLogger.log(`Transaction confirmed: ${signature}`); | |
return signature | |
} else { | |
throw new Error(`Transaction failed: ${statuses.value[0].err.toString()}`); | |
} | |
} | |
} catch (error) { | |
elizaLogger.error(`Error sending transaction: ${error}`); | |
// Optionally handle retry logic or exit | |
} | |
const elapsedTime = Date.now() - transactionStartTime; | |
const remainingTime = Math.max(0, 1000 - elapsedTime); | |
if (remainingTime > 0) { | |
await new Promise(resolve => setTimeout(resolve, remainingTime)); | |
} | |
} |
constructor(teeMode?: string) { | ||
let endpoint: string | undefined; | ||
|
||
// Both LOCAL and DOCKER modes use the simulator, just with different endpoints | ||
switch (teeMode) { | ||
case TEEMode.LOCAL: | ||
endpoint = "http://localhost:8090"; | ||
console.log( | ||
"TEE: Connecting to local simulator at localhost:8090" | ||
); | ||
break; | ||
case TEEMode.DOCKER: | ||
endpoint = "http://host.docker.internal:8090"; | ||
console.log( | ||
"TEE: Connecting to simulator via Docker at host.docker.internal:8090" | ||
); | ||
break; | ||
case TEEMode.PRODUCTION: | ||
endpoint = undefined; | ||
console.log( | ||
"TEE: Running in production mode without simulator" | ||
); | ||
break; | ||
default: | ||
throw new Error( | ||
`Invalid TEE_MODE: ${teeMode}. Must be one of: LOCAL, DOCKER, PRODUCTION` | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle undefined TEE_MODE
setting
If TEE_MODE
is undefined, the constructor will throw an error. Since TEE_MODE
might not be set, provide a default value or handle the undefined case to prevent unexpected errors.
Apply this diff to set a default TEE_MODE
:
+ teeMode = teeMode || TEEMode.PRODUCTION;
switch (teeMode) {
case TEEMode.LOCAL:
endpoint = "http://localhost:8090";
console.log(
"TEE: Connecting to local simulator at localhost:8090"
);
break;
// existing cases...
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
constructor(teeMode?: string) { | |
let endpoint: string | undefined; | |
// Both LOCAL and DOCKER modes use the simulator, just with different endpoints | |
switch (teeMode) { | |
case TEEMode.LOCAL: | |
endpoint = "http://localhost:8090"; | |
console.log( | |
"TEE: Connecting to local simulator at localhost:8090" | |
); | |
break; | |
case TEEMode.DOCKER: | |
endpoint = "http://host.docker.internal:8090"; | |
console.log( | |
"TEE: Connecting to simulator via Docker at host.docker.internal:8090" | |
); | |
break; | |
case TEEMode.PRODUCTION: | |
endpoint = undefined; | |
console.log( | |
"TEE: Running in production mode without simulator" | |
); | |
break; | |
default: | |
throw new Error( | |
`Invalid TEE_MODE: ${teeMode}. Must be one of: LOCAL, DOCKER, PRODUCTION` | |
); | |
} | |
constructor(teeMode?: string) { | |
let endpoint: string | undefined; | |
// Both LOCAL and DOCKER modes use the simulator, just with different endpoints | |
teeMode = teeMode || TEEMode.PRODUCTION; | |
switch (teeMode) { | |
case TEEMode.LOCAL: | |
endpoint = "http://localhost:8090"; | |
console.log( | |
"TEE: Connecting to local simulator at localhost:8090" | |
); | |
break; | |
case TEEMode.DOCKER: | |
endpoint = "http://host.docker.internal:8090"; | |
console.log( | |
"TEE: Connecting to simulator via Docker at host.docker.internal:8090" | |
); | |
break; | |
case TEEMode.PRODUCTION: | |
endpoint = undefined; | |
console.log( | |
"TEE: Running in production mode without simulator" | |
); | |
break; | |
default: | |
throw new Error( | |
`Invalid TEE_MODE: ${teeMode}. Must be one of: LOCAL, DOCKER, PRODUCTION` | |
); | |
} |
|
||
return FetchedPositionsStatistics | ||
} catch (error) { | ||
throw new Error("Error during feching positions"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typo in error message.
There's a typo at line 92: "feching" should be "fetching".
Apply this diff to correct the typo:
- throw new Error("Error during feching positions");
+ throw new Error("Error during fetching positions");
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
throw new Error("Error during feching positions"); | |
throw new Error("Error during fetching positions"); |
🛠️ Refactor suggestion
Include original error message when rethrowing exception.
Including the original error message aids in debugging.
Apply this diff to include the original error:
- throw new Error("Error during fetching positions");
+ throw new Error(`Error during fetching positions: ${error.message}`);
Committable suggestion skipped: line range outside the PR's diff.
if (!path || !subject) { | ||
console.error( | ||
"Path and Subject are required for key derivation" | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throw an error when required parameters are missing.
After logging the error, the function should throw an exception to prevent further execution.
Apply this diff:
console.error(
"Path and Subject are required for key derivation"
);
+ throw new Error("Missing path or subject for key derivation");
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if (!path || !subject) { | |
console.error( | |
"Path and Subject are required for key derivation" | |
); | |
} | |
if (!path || !subject) { | |
console.error( | |
"Path and Subject are required for key derivation" | |
); | |
throw new Error("Missing path or subject for key derivation"); | |
} |
const BASE_URL = "http://localhost:3000"; | ||
const response = await fetch(`${BASE_URL}/${agentId}/message`, { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify(requestBody) | ||
}); | ||
if (!response.ok) { | ||
throw new Error(`Failed to send message: ${response.statusText}`); | ||
} | ||
const data = (await response.json()) as TextResponse[]; | ||
return data; | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance error handling and add request timeout.
The current implementation lacks robust error handling and request timeout configuration.
+ const timeout = process.env.REQUEST_TIMEOUT_MS || 5000;
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
const response = await fetch(`${BASE_URL}/${agentId}/message`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
- body: JSON.stringify(requestBody)
+ body: JSON.stringify(requestBody),
+ signal: controller.signal
});
+ clearTimeout(timeoutId);
if (!response.ok) {
- throw new Error(`Failed to send message: ${response.statusText}`);
+ throw new Error(`Failed to send message: ${response.status} ${response.statusText}`);
}
const data = (await response.json()) as TextResponse[];
return data;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const BASE_URL = "http://localhost:3000"; | |
const response = await fetch(`${BASE_URL}/${agentId}/message`, { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify(requestBody) | |
}); | |
if (!response.ok) { | |
throw new Error(`Failed to send message: ${response.statusText}`); | |
} | |
const data = (await response.json()) as TextResponse[]; | |
return data; | |
} catch (error) { | |
const BASE_URL = "http://localhost:3000"; | |
const timeout = process.env.REQUEST_TIMEOUT_MS || 5000; | |
const controller = new AbortController(); | |
const timeoutId = setTimeout(() => controller.abort(), timeout); | |
const response = await fetch(`${BASE_URL}/${agentId}/message`, { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify(requestBody), | |
signal: controller.signal | |
}); | |
clearTimeout(timeoutId); | |
if (!response.ok) { | |
throw new Error(`Failed to send message: ${response.status} ${response.statusText}`); | |
} | |
const data = (await response.json()) as TextResponse[]; | |
return data; | |
} catch (error) { |
await new Promise((resolve) => setTimeout(resolve, instervalMs)); | ||
sendMessage({ | ||
agentId: runtime.agentId, | ||
text: message.content.text, // Reuse the original message text | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Implement proper timeout cleanup.
The current implementation could lead to memory leaks if the runtime is terminated while the timeout is active.
- await new Promise((resolve) => setTimeout(resolve, instervalMs));
+ const timeoutPromise = new Promise((resolve, reject) => {
+ const timeoutId = setTimeout(() => {
+ resolve(true);
+ }, intervalMs);
+ runtime.onShutdown(() => {
+ clearTimeout(timeoutId);
+ reject(new Error('Runtime shutdown'));
+ });
+ });
+ await timeoutPromise;
sendMessage({
agentId: runtime.agentId,
text: message.content.text, // Reuse the original message text
});
Committable suggestion skipped: line range outside the PR's diff.
{ | ||
"name": "@elizaos/plugin-solana-v2", | ||
"version": "0.1.7-alpha.2", | ||
"main": "dist/index.js", | ||
"type": "module", | ||
"types": "dist/index.d.ts", | ||
"dependencies": { | ||
"@elizaos/core": "workspace:*", | ||
"@elizaos/plugin-tee": "workspace:*", | ||
"@orca-so/whirlpools": "^1.0.2", | ||
"@orca-so/whirlpools-core": "^1.0.2", | ||
"@orca-so/whirlpools-client": "1.0.2", | ||
"@solana-program/compute-budget": "^0.6.1", | ||
"@solana-program/system": "^0.6.2", | ||
"@solana-program/token-2022": "^0.3.1", | ||
"@solana/codecs": "^2.0.0", | ||
"@solana/web3.js": "^2.0.0", | ||
"@types/bs58": "^4.0.4", | ||
"bs58": "^6.0.0" | ||
}, | ||
"scripts": { | ||
"build": "tsup --format esm --dts", | ||
"dev": "tsup --format esm --dts --watch" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^22.8.7", | ||
"tsup": "8.3.5", | ||
"vitest": "2.1.4" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add missing package metadata and update dependencies.
The package.json is missing essential fields and contains outdated dependencies.
{
"name": "@elizaos/plugin-solana-v2",
"version": "0.1.7-alpha.2",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/elizaOS/eliza.git"
+ },
+ "peerDependencies": {
+ "@solana/web3.js": "^2.0.0"
+ },
"dependencies": {
...
},
"devDependencies": {
- "@types/node": "^22.8.7",
+ "@types/node": "^20.11.0",
"tsup": "8.3.5",
"vitest": "2.1.4"
}
}
Committable suggestion skipped: line range outside the PR's diff.
SOLANA_PRIVATE_KEY= | ||
SOLANA_PUBLIC_KEY= | ||
RPC_URL= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add environment variable specifications
Please enhance the environment variables section with:
- Required format for SOLANA_PRIVATE_KEY (base58, hex, etc.)
- Supported Solana networks (mainnet, testnet, devnet)
- Example RPC_URL format
#### Trusted Execution Environment (TEE) | ||
- For Trusted Execution Environment (TEE) functionality, this plugin transitions from `Keypair` (used in v1) to `CryptoKeyPair` from the Web Crypto API. This change aligns with `@solana/web3.js` v2's zero-dependency, modern JavaScript architecture. | ||
- A modified implementation for TEE integration is included in `src/utils/`, following the same patterns used in `plugin-tee`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add security warnings for private key handling
The TEE section should include explicit security warnings about:
- Safe private key management practices
- Risks of exposing private keys in environment variables
- Recommendations for production deployments
Background
What does this PR do?
plugin-solana-v2
, leveraging the latest features of@solana/web3.js
v2@solana/web3.js
v1.@solana/web3.js
v2pluting-tee
usesKeypair
from@solana/web3.js
v1, while v2 usesCryptoKeyPair
from the web api. To account for this, I added some utils that add TEE functionality for solana-plugin-v2 as well (tested locally).repositionThresholdBps
).What kind of change is this?
Features (non-breaking change which adds functionality)
Why are we doing this? Any context or related work?
Future proof Eliza for new projects that build on top of the new Solana SDK.
Documentation changes needed?
My changes do not require a change to the project documentation.
I added a README to the plugin.
Testing
I'm currently still testing the stability of the repositioning functionality. The behavior of the agent is at times unpredictable. I would like one of the core devs to give me guidance on the following:
Where should a reviewer start?
TBA
Detailed testing steps
TBA
Discord username
@calintje
Summary by CodeRabbit
Release Notes for Solana Plugin V2
New Features
Improvements
@solana/web3.js
v2 with modern JavaScript practicesDependencies
@elizaos/plugin-solana-v2
package