Skip to content
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: add Bitcoin plugin with Taproot and Ark #1553

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

Conversation

tiero
Copy link

@tiero tiero commented Dec 29, 2024

🤖 Bitcoin for AI Agents

This PR enables Eliza agents to handle Bitcoin transactions autonomously through @arklabs/wallet-sdk integration. Agents can now receive payments for services, pay other agents, and manage their Bitcoin wallets with both on-chain and Layer 2 (Ark protocol) support.

🚨 WARNING

Caution: Until an external audit is completed, it is strongly recommended not to use this integration on the main Bitcoin network with more than a negligible amount of BTC.

🔑 Configuration

The plugin requires the following environment variables:

# Required
BITCOIN_PRIVATE_KEY=           # Your Bitcoin private key in WIF format
BITCOIN_NETWORK=              # Network type: bitcoin, testnet, regtest, signet, or mutinynet

# Optional - for Ark L2 support
ARK_SERVER_URL=              # Ark protocol server URL
ARK_SERVER_PUBLIC_KEY=       # Ark server public key for L2 operations

🚀 Available Actions

  1. SHOW_BITCOIN_ADDRESSES
// Get both on-chain and off-chain addresses
const addresses = await runtime.triggerAction("SHOW_BITCOIN_ADDRESSES");
// Returns: { onchain: "bc1...", offchain: "ark1..." }
  1. BALANCE
// Check wallet balance with USD conversion
const balance = await runtime.triggerAction("BALANCE");
// Returns formatted balance with on-chain/off-chain breakdown and USD values
  1. COINS
// List available UTXOs (both on-chain and virtual)
const coins = await runtime.triggerAction("COINS");
// Returns detailed UTXO information
  1. SEND_BITCOIN
// Send Bitcoin with various denomination options
await runtime.triggerAction("SEND_BITCOIN", {
  recipient: "bc1...",
  amount: "0.001",           // BTC amount
  amountUSD: "100",         // USD amount (alternative)
  amountSats: "100000"      // Satoshi amount (alternative)
});

🔍 Key Benefits for Agents

  1. Autonomous Financial Operations

    • Agents can receive payments for API calls, content generation, or other services
    • Automated payment processing for inter-agent service exchanges
    • Self-managed wallet with balance monitoring
  2. Flexible Payment Options

    • Support for both on-chain and Layer 2 transactions
    • USD-denominated transactions with automatic conversion
    • Real-time price awareness for fee estimation
  3. Enhanced Security

    • Private key management through environment variables
    • Support for Taproot addresses (P2TR)
    • Optional Layer 2 integration for lower fees and faster transactions

📋 Implementation Status

  • Core Bitcoin functionality
  • Ark protocol L2 integration
  • USD denomination support
  • BIP21 URI support
  • Silent Payments support (coming soon)
  • External security audit
  • Complete documentation

🧪 Testing

cd packages/plugin-bitcoin
pnpm test

📚 Example Usage

Here's how to integrate the Bitcoin plugin into your agent:

import { bitcoinPlugin } from "@elizaos/plugin-bitcoin";

const character = {
  // ... other character config
  plugins: [bitcoinPlugin],
};

Basic Transaction Flow

// 1. Check balance
const balance = await runtime.triggerAction("balance");
console.log("Current balance:", balance);

// 2. List available UTXOs
const coins = await runtime.triggerAction("coins");
console.log("Available coins:", coins);

// 3. Send payment
await runtime.triggerAction("SEND_BITCOIN", {
  recipient: "bc1...",
  amountUSD: "50", // Send $50 worth of BTC
});

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @tiero! Welcome to the ai16z community. Thanks for submitting your first pull request; your efforts are helping us accelerate towards AGI. We'll review it shortly. You are now a ai16z contributor!

@odilitime odilitime changed the base branch from main to develop December 29, 2024 19:43
@odilitime odilitime added the Plugin_new Mark PRs that are a new plugin label Dec 29, 2024
Copy link
Contributor

@nulLeeKH nulLeeKH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coooool

@tiero
Copy link
Author

tiero commented Jan 8, 2025

Hey @odilitime let me know what's may be needed to progress on this!

I see the GH actions have not been approved for run, on my side all the test pass

Copy link
Contributor

coderabbitai bot commented Jan 17, 2025

📝 Walkthrough

Walkthrough

The pull request introduces a comprehensive Bitcoin plugin for the Ark protocol, adding configuration options, a new package, and multiple actions for Bitcoin wallet interactions. The changes include environment configuration, a new @elizaos/plugin-bitcoin package with providers and actions for managing Bitcoin addresses, balances, coins, and transactions. The implementation supports various Bitcoin networks and provides robust error handling for wallet operations.

Changes

File Change Summary
.env.example Added Bitcoin and Ark protocol configuration entries
agent/package.json Added @elizaos/plugin-bitcoin workspace dependency
agent/src/index.ts Imported Bitcoin plugin, conditionally added to agent
packages/plugin-bitcoin/... New package with comprehensive Bitcoin functionality, including providers, actions, types, and configuration files

Finishing Touches

  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (16)
packages/plugin-bitcoin/src/providers/bitcoin.ts (2)

48-59: Simplify error handling in getBitcoinPrice

Rethrowing the error after logging leads to redundant error handling.

Consider removing the console.error to prevent duplicate logs:

            } catch (error) {
-                console.error("Error fetching Bitcoin price:", error);
                throw error;
            }

118-121: Improve error message clarity

The error message when the private key is missing can be more descriptive.

Update the message for better clarity:

            if (!privateKey) {
                throw new Error(
-                    "BITCOIN_PRIVATE_KEY environment variable is missing"
+                    "Bitcoin provider initialization failed: BITCOIN_PRIVATE_KEY is missing."
                );
            }
packages/plugin-bitcoin/src/actions/send.ts (2)

22-22: Remove console.log from production code

Logging content may expose sensitive information.

Remove the console.log statement:

-        console.log("Content for bitcoin transfer:", content);

178-179: Safely access error messages

Directly accessing error.message may fail if error is not an Error instance.

Safely retrieve the error message:

                    text: `Error sending Bitcoin: ${error instanceof Error ? error.message : String(error)}`,
packages/plugin-bitcoin/src/sdk.ts (1)

5-13: Use static imports instead of dynamic imports

Dynamic imports can complicate module resolution.

Simplify by using static imports:

-async function initSDK() {
-    const sdk = await import('@arklabs/wallet-sdk');
-    InMemoryKey = sdk.InMemoryKey;
-    Wallet = sdk.Wallet;
-}
-
-// Initialize the SDK
-initSDK().catch(console.error);
+// SDK initialized via static import
packages/plugin-bitcoin/src/types.ts (1)

15-23: Make BitcoinPrice interface more flexible.

The interface only supports USD. Consider making it more generic to support multiple currencies.

-export interface BitcoinPrice {
-  USD: {
+export interface BitcoinPrice<T extends string = string> {
+  [currency: T]: {
packages/plugin-bitcoin/src/index.ts (1)

13-26: Add version information to plugin metadata.

Include version information in the plugin metadata for better tracking and compatibility checks.

 export const bitcoinPlugin: Plugin = {
     name: "bitcoin",
+    version: "1.0.0",
     description:
packages/plugin-bitcoin/src/test-setup.ts (1)

17-30: Make mock values configurable.

Replace hardcoded balance values with configurable ones to support different test scenarios.

+const DEFAULT_BALANCE = {
+  total: 150000000,
+  onchain: {
+    total: 130000000,
+    confirmed: 100000000,
+    unconfirmed: 30000000
+  },
+  offchain: {
+    total: 20000000,
+    settled: 20000000,
+    pending: 0,
+    swept: 0
+  }
+};

-getBalance: vi.fn().mockResolvedValue({
-  total: 150000000,
+getBalance: vi.fn().mockResolvedValue(config.balance || DEFAULT_BALANCE)
packages/plugin-bitcoin/src/actions/balance.ts (1)

51-54: Consider handling Promise.all rejection

The parallel execution of getWalletBalance and getBitcoinPrice could fail independently. Consider handling partial failures gracefully.

-            const [balance, price] = await Promise.all([
-                provider.getWalletBalance(),
-                provider.getBitcoinPrice(),
-            ]);
+            const [balanceResult, priceResult] = await Promise.allSettled([
+                provider.getWalletBalance(),
+                provider.getBitcoinPrice(),
+            ]);
+            
+            if (balanceResult.status === 'rejected') {
+                throw new Error('Failed to fetch wallet balance');
+            }
+            if (priceResult.status === 'rejected') {
+                console.warn('Price fetch failed, using fallback price');
+                return { text: `Bitcoin Balance: ${balanceResult.value.total.toLocaleString()} sats` };
+            }
+            
+            const balance = balanceResult.value;
+            const price = priceResult.value;
packages/plugin-bitcoin/src/tests/balance.test.ts (1)

21-45: Add edge case tests for extreme values

The mock data uses "safe" values. Consider adding tests for edge cases:

  • Maximum possible balance
  • Zero balance
  • Negative price movements
packages/plugin-bitcoin/src/tests/bitcoin.test.ts (1)

91-98: Add test for maximum amount

While testing dust amount, also test the maximum allowed amount to ensure proper bounds checking.

+    it("should handle maximum amount", async () => {
+      const recipientAddress = "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx";
+      const MAX_BITCOIN = 21_000_000n * 100_000_000n;
+
+      await expect(provider.sendBitcoin({
+        address: recipientAddress,
+        amount: MAX_BITCOIN + 1n
+      })).rejects.toThrow("Amount exceeds maximum possible Bitcoin supply");
+    });
packages/plugin-bitcoin/src/actions/addresses.ts (1)

20-54: Well-structured error handling and address display!

The implementation properly handles both onchain and offchain scenarios with appropriate error handling.

Consider adding address validation before display to ensure the addresses are in the correct format for the selected network (mainnet/testnet).

.env.example (1)

363-364: Add validation hints for Ark server configuration.

Consider adding format examples and validation requirements for the server URL and public key.

-ARK_SERVER_URL=                # Ark protocol server URL
-ARK_SERVER_PUBLIC_KEY=         # Ark server public key for L2 operations
+ARK_SERVER_URL=                # Ark protocol server URL (e.g., https://ark.example.com)
+ARK_SERVER_PUBLIC_KEY=         # Ark server public key for L2 operations (33 or 65 bytes hex string)
packages/plugin-bitcoin/src/tests/coins.test.ts (3)

16-39: Consider improving mock data readability and type safety.

The mock provider implementation could be enhanced:

  1. Use constants for UTXO values to clarify their meaning
  2. Consider using a proper type-safe mock implementation instead of type casting
 const mockProvider = {
     wallet: {
         getCoins: async () => [
             {
-                txid: "tx1",
-                vout: 0,
-                value: 1000,
+                txid: "tx1", // Consider using TEST_TXID_1
+                vout: 0,
+                value: 1000, // Consider using SATS_PER_TEST_UTXO
                 status: { confirmed: true },
             },
             // ... similar changes for other mock UTXOs
         ],
     },
-} as unknown as BitcoinTaprootProvider;
+} satisfies Partial<BitcoinTaprootProvider>;

57-73: Enhance test coverage for confirmed UTXOs.

Consider adding assertions for:

  1. Total number of confirmed UTXOs
  2. Format of displayed values (e.g., decimal places)
  3. Error cases with malformed UTXO data

109-147: Well-implemented error handling test cases!

The error scenarios are thoroughly covered. Consider adding specific error type checks for better error handling validation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2102ddb and e466712.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .env.example (1 hunks)
  • agent/package.json (1 hunks)
  • agent/src/index.ts (2 hunks)
  • packages/plugin-bitcoin/package.json (1 hunks)
  • packages/plugin-bitcoin/src/actions/addresses.ts (1 hunks)
  • packages/plugin-bitcoin/src/actions/balance.ts (1 hunks)
  • packages/plugin-bitcoin/src/actions/coins.ts (1 hunks)
  • packages/plugin-bitcoin/src/actions/send.ts (1 hunks)
  • packages/plugin-bitcoin/src/index.ts (1 hunks)
  • packages/plugin-bitcoin/src/providers/bitcoin.ts (1 hunks)
  • packages/plugin-bitcoin/src/sdk.ts (1 hunks)
  • packages/plugin-bitcoin/src/test-setup.ts (1 hunks)
  • packages/plugin-bitcoin/src/tests/balance.test.ts (1 hunks)
  • packages/plugin-bitcoin/src/tests/bitcoin.test.ts (1 hunks)
  • packages/plugin-bitcoin/src/tests/coins.test.ts (1 hunks)
  • packages/plugin-bitcoin/src/types.ts (1 hunks)
  • packages/plugin-bitcoin/src/types/index.ts (1 hunks)
  • packages/plugin-bitcoin/tsconfig.json (1 hunks)
  • packages/plugin-bitcoin/tsup.config.ts (1 hunks)
  • packages/plugin-bitcoin/vitest.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/plugin-bitcoin/vitest.config.ts
  • packages/plugin-bitcoin/tsconfig.json
  • packages/plugin-bitcoin/tsup.config.ts
🧰 Additional context used
🪛 Gitleaks (8.21.2)
packages/plugin-bitcoin/src/tests/bitcoin.test.ts

9-9: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


10-10: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (4)
packages/plugin-bitcoin/src/actions/balance.ts (1)

60-62: 🛠️ Refactor suggestion

Prevent potential numeric overflow

The calculations involving price conversion should handle potential numeric overflow for large amounts.

-            const onchainUSD = (onchainTotal * price.USD.last) / 100_000_000;
-            const offchainUSD = (offchainTotal * price.USD.last) / 100_000_000;
-            const totalUSD = (total * price.USD.last) / 100_000_000;
+            const convertToUSD = (sats: number) => {
+                const BTC = Number(sats) / 100_000_000;
+                return BTC * price.USD.last;
+            };
+            const onchainUSD = convertToUSD(onchainTotal);
+            const offchainUSD = convertToUSD(offchainTotal);
+            const totalUSD = convertToUSD(total);
agent/package.json (1)

62-62: LGTM!

The Bitcoin plugin dependency is correctly added and follows the workspace dependency pattern.

agent/src/index.ts (1)

604-604: Clean integration of Bitcoin plugin!

The implementation follows the established pattern for blockchain plugins, maintaining consistency with the codebase.

packages/plugin-bitcoin/package.json (1)

18-19: Verify dependency versions for security and stability.

  1. @arklabs/[email protected] is an early version that might be unstable
  2. [email protected] should be checked for vulnerabilities

Comment on lines +75 to +84
async sendBitcoin(params: {
address: string;
amount: bigint;
message?: string;
}) {
return this.wallet.sendBitcoin({
address: params.address,
amount: Number(params.amount),
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid precision loss when converting bigint to number

In the sendBitcoin method, converting amount from bigint to number may cause precision loss for large amounts.

Ensure the amount retains its precision by keeping it as a bigint if the underlying SDK supports it, or validate that the amount is within the safe number range.

Comment on lines +126 to +141
// Convert amounts if needed
let amount: bigint | undefined;
if (content.amount) {
// Convert BTC to satoshis
amount = BigInt(
Math.floor(Number(content.amount) * 100_000_000)
);
} else if (content.amountSats) {
// Already in satoshis
amount = BigInt(Math.floor(Number(content.amountSats)));
} else if (content.amountUSD) {
// Get current BTC price and convert USD to satoshis
const price = await provider.getBitcoinPrice();
const btcAmount = Number(content.amountUSD) / price.USD.last;
amount = BigInt(Math.floor(btcAmount * 100_000_000));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validate amount inputs to prevent errors

Inputs for amounts are not validated and may cause runtime errors if invalid.

Add validation to ensure amounts are valid numbers before processing.

Comment on lines +85 to +89
const content = await generateObjectDeprecated({
runtime,
context: transferContext,
modelClass: ModelClass.SMALL,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update deprecated function usage

The function generateObjectDeprecated is deprecated.

Replace with the updated function, such as generateObject:

 const content = await generateObject({
     runtime,
     context: transferContext,
     modelClass: ModelClass.SMALL,
 });

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +1 to +4
// @ts-ignore
let InMemoryKey: any;
let Wallet: any;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid suppressing TypeScript checks

Using @ts-ignore and any types reduces type safety.

Import types directly to maintain type safety:

-// @ts-ignore
-let InMemoryKey: any;
-let Wallet: any;
+import { InMemoryKey, Wallet } from '@arklabs/wallet-sdk';
📝 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.

Suggested change
// @ts-ignore
let InMemoryKey: any;
let Wallet: any;
import { InMemoryKey, Wallet } from '@arklabs/wallet-sdk';

Comment on lines +1 to +26
import { IAgentRuntime, Memory, State } from "@elizaos/core";

export interface BitcoinConfig {
privateKey: string;
network: "bitcoin" | "testnet" | "mutinynet" | "regtest" | "signet";
arkServerPublicKey?: string;
arkServerUrl?: string;
}

export interface SendBitcoinParams {
address: string;
amount?: bigint; // in satoshis, optional if sendAll is true
amountUSD?: number; // amount in USD
sendAll?: boolean; // if true, sends all available funds minus fee
feeRate?: number; // sats/vbyte, optional
}

export interface BitcoinPrice {
[currency: string]: {
"15m": number;
last: number;
buy: number;
sell: number;
symbol: string;
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove duplicate type definitions.

This file duplicates interfaces from types.ts. Consolidate type definitions into a single location to prevent inconsistencies.

Additionally, there's a type inconsistency for the amount field:

  • types/index.ts: amount?: bigint
  • types.ts: amount?: number

This could lead to runtime errors when handling Bitcoin amounts.

Comment on lines +41 to +51
if (amount < 546n) {
throw new Error('Amount must be at least 546 sats (dust limit)');
}
if (!address.startsWith('tb1') && !address.startsWith('tark1')) {
throw new Error('Invalid Bitcoin address');
}
if (amount > 1000000000n) {
throw new Error('Insufficient funds');
}
return 'txid';
}),
Copy link
Contributor

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 in sendBitcoin mock.

The mock implementation needs more comprehensive error cases:

  • Network errors
  • Rate limiting
  • Invalid fee rates
  • Double-spend attempts
 sendBitcoin: vi.fn()
   .mockImplementation(({ address, amount, feeRate }) => {
     if (amount < 546n) {
       throw new Error('Amount must be at least 546 sats (dust limit)');
     }
     if (!address.startsWith('tb1') && !address.startsWith('tark1')) {
       throw new Error('Invalid Bitcoin address');
     }
     if (amount > 1000000000n) {
       throw new Error('Insufficient funds');
     }
+    if (feeRate && (feeRate < 1 || feeRate > 500)) {
+      throw new Error('Invalid fee rate');
+    }
+    if (Math.random() < 0.1) { // Simulate network errors
+      throw new Error('Network error');
+    }
     return 'txid';
   }),
📝 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.

Suggested change
if (amount < 546n) {
throw new Error('Amount must be at least 546 sats (dust limit)');
}
if (!address.startsWith('tb1') && !address.startsWith('tark1')) {
throw new Error('Invalid Bitcoin address');
}
if (amount > 1000000000n) {
throw new Error('Insufficient funds');
}
return 'txid';
}),
if (amount < 546n) {
throw new Error('Amount must be at least 546 sats (dust limit)');
}
if (!address.startsWith('tb1') && !address.startsWith('tark1')) {
throw new Error('Invalid Bitcoin address');
}
if (amount > 1000000000n) {
throw new Error('Insufficient funds');
}
if (feeRate && (feeRate < 1 || feeRate > 500)) {
throw new Error('Invalid fee rate');
}
if (Math.random() < 0.1) { // Simulate network errors
throw new Error('Network error');
}
return 'txid';
}),

Comment on lines +44 to +51
const confirmedTotal = confirmedCoins.reduce(
(sum, coin) => sum + coin.value,
0
);
const unconfirmedTotal = unconfirmedCoins.reduce(
(sum, coin) => sum + coin.value,
0
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using BigInt for sats calculations

Bitcoin amounts should be handled as BigInt to prevent precision loss with large numbers.

-            const confirmedTotal = confirmedCoins.reduce(
-                (sum, coin) => sum + coin.value,
-                0
-            );
-            const unconfirmedTotal = unconfirmedCoins.reduce(
-                (sum, coin) => sum + coin.value,
-                0
-            );
+            const confirmedTotal = confirmedCoins.reduce(
+                (sum, coin) => sum + BigInt(coin.value),
+                0n
+            );
+            const unconfirmedTotal = unconfirmedCoins.reduce(
+                (sum, coin) => sum + BigInt(coin.value),
+                0n
+            );
📝 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.

Suggested change
const confirmedTotal = confirmedCoins.reduce(
(sum, coin) => sum + coin.value,
0
);
const unconfirmedTotal = unconfirmedCoins.reduce(
(sum, coin) => sum + coin.value,
0
);
const confirmedTotal = confirmedCoins.reduce(
(sum, coin) => sum + BigInt(coin.value),
0n
);
const unconfirmedTotal = unconfirmedCoins.reduce(
(sum, coin) => sum + BigInt(coin.value),
0n
);

Comment on lines +19 to +21
const provider = runtime.providers.find(
(p) => p instanceof BitcoinTaprootProvider
) as BitcoinTaprootProvider;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Unsafe type assertion

The type assertion to BitcoinTaprootProvider could fail at runtime. Consider using type guard pattern.

-            const provider = runtime.providers.find(
-                (p) => p instanceof BitcoinTaprootProvider
-            ) as BitcoinTaprootProvider;
+            const provider = runtime.providers.find(
+                (p): p is BitcoinTaprootProvider => p instanceof BitcoinTaprootProvider
+            );
📝 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.

Suggested change
const provider = runtime.providers.find(
(p) => p instanceof BitcoinTaprootProvider
) as BitcoinTaprootProvider;
const provider = runtime.providers.find(
(p): p is BitcoinTaprootProvider => p instanceof BitcoinTaprootProvider
);

Comment on lines +8 to +10
// Test private key (DO NOT USE IN PRODUCTION)
const testPrivateKey = "ce66c68f8875c0c98a502c666303dc183a21600130013c06f9d1edf60207abf2";
const testServerPubKey = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security: Remove hardcoded test keys

Even test private keys should not be committed to the repository. Consider using environment variables for test keys.

-  const testPrivateKey = "ce66c68f8875c0c98a502c666303dc183a21600130013c06f9d1edf60207abf2";
-  const testServerPubKey = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
+  const testPrivateKey = process.env.TEST_BITCOIN_PRIVATE_KEY ?? "mock_key";
+  const testServerPubKey = process.env.TEST_ARK_SERVER_PUBLIC_KEY ?? "mock_pubkey";
📝 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.

Suggested change
// Test private key (DO NOT USE IN PRODUCTION)
const testPrivateKey = "ce66c68f8875c0c98a502c666303dc183a21600130013c06f9d1edf60207abf2";
const testServerPubKey = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
// Test private key (DO NOT USE IN PRODUCTION)
const testPrivateKey = process.env.TEST_BITCOIN_PRIVATE_KEY ?? "mock_key";
const testServerPubKey = process.env.TEST_ARK_SERVER_PUBLIC_KEY ?? "mock_pubkey";
🧰 Tools
🪛 Gitleaks (8.21.2)

9-9: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


10-10: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

@@ -356,3 +356,9 @@ CRONOSZKEVM_PRIVATE_KEY=

# Fuel Ecosystem (FuelVM)
FUEL_WALLET_PRIVATE_KEY=

# Bitcoin Configuration
BITCOIN_PRIVATE_KEY= # Your Bitcoin private key in WIF format
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add security warning for private key storage.

The private key should be stored securely and never committed to version control.

-BITCOIN_PRIVATE_KEY=            # Your Bitcoin private key in WIF format
+BITCOIN_PRIVATE_KEY=            # Your Bitcoin private key in WIF format (IMPORTANT: Store securely, never commit to version control)
📝 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.

Suggested change
BITCOIN_PRIVATE_KEY= # Your Bitcoin private key in WIF format
BITCOIN_PRIVATE_KEY= # Your Bitcoin private key in WIF format (IMPORTANT: Store securely, never commit to version control)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Plugin_new Mark PRs that are a new plugin
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants