<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged solana</title>
<link>https://coderlegion.com/tag/solana</link>
<description>Powered by Question2Answer</description>
<item>
<title>How to Authenticate Users with Solana Wallets in NestJS</title>
<link>https://coderlegion.com/27699/how-to-authenticate-users-with-solana-wallets-in-nestjs</link>
<description>&lt;p&gt;Let's talk about wallet based auth in NestJS. What this is, is basically an auth system where the user is authenticated and authorized based on their web3 wallet. We'll be doing this with a Solana wallet. The process is quite straightforward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User requests a nonce (a single-use random number that prevents replay attacks)&lt;/li&gt;
&lt;li&gt;Backend sends the nonce&lt;/li&gt;
&lt;li&gt;User signs the nonce with their wallet address and returns the signed nonce back to the backend&lt;/li&gt;
&lt;li&gt;Backend verifies that the nonce was signed by the right address&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From this point on it's your regular auth flow and you can hook this up to any existing JWT or session auth system you've implemented.&lt;/p&gt;
&lt;p&gt;One thing to note is that a frontend is required for this or at least some way for the client to sign nonces with their web3 wallet. We'll be using &lt;code&gt;@solana/kit&lt;/code&gt; SDK for this as it's the modern implementation of the &lt;code&gt;@solana/web3.js&lt;/code&gt; SDK and recommended for production use by Anza.&lt;/p&gt;
&lt;h3 id=&quot;backend&quot;&gt;Backend&lt;/h3&gt;
&lt;p&gt;The backend's job is to generate unique challenges (nonces), verify that signatures were created by the claimed wallet address, and issue JWT tokens on successful authentication. &lt;/p&gt;
&lt;p&gt;We'll need to install &lt;code&gt;@solana/kit&lt;/code&gt; as well as &lt;code&gt;redis&lt;/code&gt; since we will be using that to store our nonces. Redis is ideal here because it provides fast in-memory storage with built-in TTL (time-to-live) expiration, automatically cleaning up old nonces without manual intervention.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install @solana/kit redis
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;redis-service&quot;&gt;Redis Service&lt;/h4&gt;
&lt;p&gt;Let's set up our redis client and service.&lt;/p&gt;
&lt;p&gt;In NestJS, when you're working with non-class instances like Redis clients, you can't use the standard class-based dependency injection. Instead, you use string tokens as injection identifiers. The Redis client is created by a factory function (not instantiated via new RedisService()), so TypeScript can't use the class itself as a token. String constants provide a unique identifier that NestJS can use to register and retrieve the instance.&lt;/p&gt;
&lt;p&gt;This is why we define &lt;code&gt;REDIS_CLIENT&lt;/code&gt; as a constant string token that we'll use to register and inject our Redis client throughout the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;//redis.constants.ts
export const REDIS_CLIENT = 'REDIS_CLIENT';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need two specific methods here. The &lt;code&gt;setNonce&lt;/code&gt; method stores the nonce with a 5-minute expiration using Redis's &lt;code&gt;EX&lt;/code&gt; option, which automatically cleans up old nonces and prevents replay attacks.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;getAndDeleteNonce&lt;/code&gt; method atomically retrieves and deletes the nonce in one operation, ensuring each nonce can only be used once for verification. This pattern prevents an attacker from reusing a previously signed nonce.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;//redis.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { REDIS_CLIENT } from './redis.constants';
import type { RedisClientType } from 'redis';

@Injectable()
export class RedisService {
  constructor(@Inject(REDIS_CLIENT) private readonly redis: RedisClientType) {}

  // Store nonce with 5-minute expiration
  async setNonce(address: string, nonce: string): Promise&amp;lt;void&amp;gt; {
    await this.redis.set(`nonce:${address}`, nonce, { EX: 300 });
  }

  // Retrieve and immediately delete nonce to prevent replay attacks
  async getAndDeleteNonce(address: string): Promise&amp;lt;string | null&amp;gt; {
    const nonce = await this.redis.get(`nonce:${address}`);
    
    if (nonce) {
      await this.redis.del(`nonce:${address}`);
    }
    
    return nonce;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We're using NestJS's &lt;code&gt;ConfigService&lt;/code&gt; to manage environment variables in a type-safe way. This is better than directly accessing &lt;code&gt;process.env&lt;/code&gt; because it centralizes configuration, provides validation, and makes testing easier. You can validate required variables at startup (fail fast), type-check them, and mock them in tests without polluting the global process object.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;@Global()&lt;/code&gt; decorator makes this module available throughout your application without needing to import it into every module. Make sure to set up &lt;code&gt;ConfigModule&lt;/code&gt; in your &lt;code&gt;AppModule&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
// ... other imports

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true, // Makes ConfigModule available globally
    }),
    // ... other modules
  ],
  // ... controllers and providers
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can set up our Redis module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;//redis.module.ts
import { Global, Module } from '@nestjs/common';
import { RedisService } from './redis.service';
import { REDIS_CLIENT } from './redis.constants';
import { ConfigService } from '@nestjs/config';
import { createClient } from 'redis';

@Global()
@Module({
  providers: [
    {
      provide: REDIS_CLIENT,
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) =&amp;gt; {
        const client = createClient({
          url: configService.get&amp;lt;string&amp;gt;('REDIS_URL'),
        });
        
        client.on('error', (err) =&amp;gt; console.error('Redis client error', err));
        
        await client.connect();
        
        return client;
      },
    },
    RedisService,
  ],
  exports: [REDIS_CLIENT, RedisService],
})
export class RedisModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;auth-service&quot;&gt;Auth Service&lt;/h4&gt;
&lt;p&gt;With Redis configured to handle nonce storage, we can build the authentication logic. The auth service will generate nonces, create SIWS-compliant messages, verify signatures, and issue JWT tokens. Let's implement our service logic.&lt;/p&gt;
&lt;p&gt;We need to provide a way for the frontend to request a nonce. We also need to use our redis methods to store the nonce we provide to be used during verification later.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;randomBytes&lt;/code&gt; from Node's crypto module to generate cryptographically secure random values. The 16 bytes of random data are then converted to base64url encoding, which is URL-safe and produces a string without padding characters. This encoding ensures the nonce can be safely included in URLs and JSON without escaping issues, while 16 bytes provides sufficient entropy (2^128 possible values) to prevent collision attacks. This gives us a unique, unpredictable nonce for each authentication attempt.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { randomBytes } from 'crypto';

generateNonce(): string {
  return randomBytes(16).toString('base64url');
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The message format follows the Sign-In with Solana (SIWS) standard, which is analogous to Sign-In with Ethereum (SIWE). This standardized format includes the domain requesting authentication, the user's wallet address, a human-readable message, the unique nonce, and a timestamp. This structure ensures the user knows exactly what they're signing and prevents phishing attacks where a malicious site might try to get users to sign messages intended for other domains.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;async getChallenge(address: string) {
  const nonce = this.generateNonce();
  
  await this.redisService.setNonce(address, nonce);
  
  // Standard SIWS message format for wallet authentication
  const message = `titan-app.com wants you to sign in with your Solana account:\n${address}\n\nSign this message to authenticate.\n\nNonce: ${nonce}\nTimestamp: ${Date.now()}`;
  
  return { message, nonce };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The signature verification method is the heart of the authentication system. It retrieves the stored nonce, reconstructs the exact message that was signed, and uses Solana's cryptographic primitives to verify that the signature was created by the private key corresponding to the claimed wallet address. If any part of this fails, authentication is rejected.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { getAddressFromPublicKey, getBase58Decoder, getBase58Encoder } from '@solana/kit';

async verifySolanaSignature(data: {
  address: string;
  signatureBase58: Uint8Array;
  message: Uint8Array;
  nonce: string;
}): Promise&amp;lt;boolean&amp;gt; {
  const { address, signatureBase58, message, nonce } = data;

  // Retrieve and delete the nonce to prevent replay attacks
  const storedNonce = await this.redisService.getAndDeleteNonce(address);

  if (!storedNonce || storedNonce !== nonce) {
    return false;
  }

  try {
    // Decode the signature and message from base58
    const signature = getBase58Decoder().decode(signatureBase58);
    const messageBytes = getBase58Decoder().decode(message);
    
    // Verify the signature matches the address
    const publicKey = getAddressFromPublicKey(
      getBase58Decoder().decode(address)
    );
    
    // Use Solana's signature verification
    const isValid = await verifySignature(publicKey, messageBytes, signature);
    
    return isValid;
  } catch (error) {
    console.error('Signature verification error:', error);
    return false;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;validateUserWithWallet&lt;/code&gt; method either finds an existing user by wallet address or creates a new one. This is where you'd integrate with your user management system. In this example, we're using Prisma to handle database operations, but you could adapt this to any ORM or database layer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;async validateUserWithWallet(address: string): Promise&amp;lt;UserEntity | null&amp;gt; {
  // Find existing user by wallet address
  let user = await this.prisma.user.findUnique({
    where: { walletAddress: address },
  });

  // If no user exists, create one
  if (!user) {
    user = await this.prisma.user.create({
      data: {
        walletAddress: address,
      },
    });
  }

  return user;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The login function creates JWT tokens after successful authentication. We build a payload containing the user's ID and device information, then conditionally add email and wallet address if they exist. The function returns both an access token for immediate use and a refresh token for obtaining new access tokens when the current one expires. The refresh token is handled by a separate service that manages longer-lived tokens with different expiration rules.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;async login(
  user: UserEntity,
  deviceInfo: string,
  walletAddress?: string,
): Promise&amp;lt;{
  access_token: string;
  refresh_token: string;
}&amp;gt; {
  const payload = {
    sub: user.id,
    deviceInfo,
  };

  if (user.email) {
    payload['email'] = user.email;
  }

  if (walletAddress) {
    payload['walletAddress'] = walletAddress;
  }

  const refresh_token = await this.jwtRefreshService.create(payload);
  
  return {
    access_token: this.jwtService.sign(payload),
    refresh_token,
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;wallet-auth-guard&quot;&gt;Wallet Auth Guard&lt;/h4&gt;
&lt;p&gt;Now we need a way to protect our login endpoint. NestJS guards intercept incoming requests before they reach the controller, making them perfect for authentication logic. &lt;/p&gt;
&lt;p&gt;The guard is responsible for intercepting requests to protected endpoints and verifying that the wallet signature is valid before allowing the request to proceed. It extracts the signed data from the request body, verifies the signature using our auth service, finds or creates the user, and attaches both the user entity and wallet address to the request object for use in the controller.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// guards/wallet-auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthService } from '../auth.service';
import { UnauthorizedException } from '@nestjs/common';

@Injectable()
export class LocalWalletAuthGuard implements CanActivate {
  constructor(private readonly authService: AuthService) {}

  async canActivate(context: ExecutionContext): Promise&amp;lt;boolean&amp;gt; {
    const request = context.switchToHttp().getRequest();
    const { address, signatureBase58, message, nonce } = request.body;

    // Verify signature first
    const isValid = await this.authService.verifySolanaSignature({
      address,
      signatureBase58,
      message,
      nonce,
    });

    if (!isValid) {
      throw new UnauthorizedException('Invalid signature');
    }

    // Find or create user
    const user = await this.authService.validateUserWithWallet(address);

    if (!user) {
      throw new UnauthorizedException('Could not validate user');
    }

    // Attach user and address to request for use in controller
    request.user = user;
    request.address = address;

    return true;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;auth-controller&quot;&gt;Auth Controller&lt;/h4&gt;
&lt;p&gt;With our guard handling verification, the controller becomes simple. It just needs to provide nonces to unauthenticated users and issue tokens after the guard confirms valid signatures.&lt;/p&gt;
&lt;p&gt;In the controller, we have two endpoints. The &lt;code&gt;loginWithWallet&lt;/code&gt; endpoint uses our &lt;code&gt;LocalWalletAuthGuard&lt;/code&gt; which verifies the signature and attaches both the user entity and wallet address to the request object. By the time we reach this controller method, we know the authentication is valid. We extract device information from the user-agent header, call the login service, set the refresh token as an httpOnly cookie for security, and return the access token. The &lt;code&gt;getChallenge&lt;/code&gt; endpoint is marked with &lt;code&gt;@Public()&lt;/code&gt; decorator since users need to request a nonce before they can authenticate. It simply returns the SIWS message and nonce for the given wallet address.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;@Post('login-with-wallet')
@UseGuards(LocalWalletAuthGuard)
async loginWithWallet(
  @Request() req: RequestType &amp;amp; { user: UserEntity; address: string },
  @Response({ passthrough: true }) res: ResponseType,
) {
  const deviceInfo = req.headers['user-agent'] || 'Unknown Device';

  const { access_token, refresh_token } = await this.authService.login(
    req.user,
    deviceInfo,
    req.address,
  );

  // Set refresh token as httpOnly cookie for security
  res.cookie('titan_refresh_token', refresh_token, {
    httpOnly: true,
    secure: true,
    sameSite: 'strict',
  });

  return { access_token };
}

@Public()
@Get('nonce/:address')
@ApiOperation({ summary: 'Request nonce for wallet-based authentication' })
@ApiResponse({
  description: 'Nonce and SIWS message sent successfully.',
  status: 200,
  example: {
    message:
      'titan-app.com wants you to sign in with your Solana account:\n${address}\n\nSign this message to authenticate.\n\nNonce: ${nonce}\nTimestamp: ${Date.now()}',
    nonce: '1234xlrhex',
  },
})
async getChallenge(@Param('address') address: string) {
  return await this.authService.getChallenge(address);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;backend-summary&quot;&gt;Backend Summary&lt;/h4&gt;
&lt;p&gt;That covers the backend implementation. We've set up a Redis-backed nonce system that generates unique challenges for each authentication attempt, an auth service that creates SIWS-compliant messages and manages JWT token generation, a guard that verifies signatures using Solana's cryptographic primitives, and controller endpoints that handle the nonce request and login flow. The signature verification ensures that only the holder of the wallet's private key can authenticate, while the nonce system prevents replay attacks.&lt;/p&gt;
&lt;h3 id=&quot;frontend&quot;&gt;Frontend&lt;/h3&gt;
&lt;p&gt;The backend is now ready to issue nonces and verify signatures. The frontend's job is to request these nonces, get the user to sign them with their wallet's private key (which never leaves their browser), and send the signed message back for verification. Now let's implement the frontend of our auth system.&lt;/p&gt;
&lt;p&gt;Now let's implement the frontend of our auth system. The user needs to sign our message with their private key. It is important this private key stays secure and never leaves the frontend. A tool that facilitates this is a wallet. Since we're using Solana we'll be using the Phantom wallet.&lt;/p&gt;
&lt;p&gt;The setup steps are straightforward. First, install Phantom as a browser extension. Once installed, create a new wallet or import an existing one. Then navigate to Settings, go to Developer Settings, and enable Testnet mode. In Testnet mode, select Solana Devnet. You could use Localnet if you have a test validator running locally or Testnet for a shared testing environment, but Devnet provides a good balance of accessibility and realistic network conditions.&lt;/p&gt;
&lt;p&gt;Once all this is done we can start hacking. We'll spin up a small React frontend. This is just for speed and general accessibility. You can implement this in any frontend stack as long as you understand the core steps. I used Vite to set up my React project with TypeScript and Tailwind. We should also install the &lt;code&gt;@solana/kit&lt;/code&gt; package, which automatically includes &lt;code&gt;@solana/react&lt;/code&gt; and other necessary dependencies, along with &lt;code&gt;@wallet-standard/react-core&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install @solana/kit @wallet-standard/react-core
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After we're done with project setup, the first thing we want to do is define our Solana client instance. This will be used to communicate with the Solana chain via its RPC endpoints.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// lib/solana-client.ts
import type {
  Rpc,
  RpcSubscriptions,
  SolanaRpcApi,
  SolanaRpcSubscriptionsApi,
} from &quot;@solana/kit&quot;;

export type Client = {
  rpc: Rpc&amp;lt;SolanaRpcApi&amp;gt;;
  rpcSubscriptions: RpcSubscriptions&amp;lt;SolanaRpcSubscriptionsApi&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// lib/helpers.ts
import { createSolanaRpc, createSolanaRpcSubscriptions } from &quot;@solana/kit&quot;;
import type { Client } from &quot;./solana-client&quot;;

let client: Client | undefined;

export function createClient(): Client {
  if (!client) {
    client = {
      rpc: createSolanaRpc(`${import.meta.env.SOLANA_RPC_URL}`),
      rpcSubscriptions: createSolanaRpcSubscriptions(
        `${import.meta.env.SOLANA_RPC_SUBSCRIPTIONS_URL}`
      ),
    };
  }
  
  return client;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure your &lt;code&gt;.env&lt;/code&gt; file contains the Devnet URLs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-env&quot;&gt;SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_RPC_SUBSCRIPTIONS_URL=wss://api.devnet.solana.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the Solana client configured, we need functions to communicate with our backend. In our &lt;code&gt;features/auth/api&lt;/code&gt; folder, we'll create two API calls: one to request a nonce and another to submit the signed message. Let's define them both.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/types
export type RequestNonceOutput = {
  message: string;
  nonce: string;
};

export type VerifyNonceInput = {
  address: string;
  signatureBase58: Uint8Array&amp;lt;ArrayBufferLike&amp;gt;;
  message: Uint8Array&amp;lt;ArrayBufferLike&amp;gt;;
  nonce: string;
};

export type LoginResponse = {
  access_token: string;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/api/requestNonce.ts
import type { RequestNonceOutput } from &quot;../types&quot;;

export async function requestNonce(
  address: string
): Promise&amp;lt;RequestNonceOutput&amp;gt; {
  const response = await fetch(
    `${import.meta.env.VITE_API_URL}/auth/nonce/${address}`
  );

  if (!response.ok) {
    throw new Error(`Failed to request nonce: ${response.statusText}`);
  }

  const data = await response.json();
  
  // Validate response structure
  if (!data.message || !data.nonce) {
    throw new Error('Invalid response format from nonce endpoint');
  }
  
  return data as RequestNonceOutput;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/api/loginWithWallet.ts
import type { VerifyNonceInput, LoginResponse } from &quot;../types&quot;;

export async function loginWithWallet(
  signedData: VerifyNonceInput
): Promise&amp;lt;LoginResponse&amp;gt; {
  const response = await fetch(
    `${import.meta.env.VITE_API_URL}/auth/login-with-wallet`,
    {
      method: &quot;POST&quot;,
      headers: {
        &quot;Content-Type&quot;: &quot;application/json&quot;,
      },
      body: JSON.stringify(signedData),
    }
  );

  if (!response.ok) {
    const errorData = await response.json().catch(() =&amp;gt; ({}));
    throw new Error(
      errorData.message || `Login failed: ${response.statusText}`
    );
  }

  const data = await response.json();
  
  // Validate response contains access token
  if (!data.access_token) {
    throw new Error('Invalid response format from login endpoint');
  }
  
  return data as LoginResponse;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are going to serve as our connection to the backend we made previously. &lt;/p&gt;
&lt;p&gt;Before we build the UI components, we need to manage wallet connection state across the app. React Context provides a clean way to share the selected wallet without prop drilling.&lt;/p&gt;
&lt;p&gt;As this is only an auth demonstration it's not going to be anything fancy, just enough to implement the authentication flow and some state to show we're logged in.&lt;/p&gt;
&lt;p&gt;First off, our wallet account context. You can use some other way to manage context in your application. Here we'll be using the React Context API.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// src/context/SelectedWalletAccountContext.tsx
import { createContext } from &quot;react&quot;;
import type { UiWallet, UiWalletAccount } from &quot;@wallet-standard/react-core&quot;;

export type SelectedWalletAccountState = UiWalletAccount | undefined;

export const SelectedWalletAccountContext = createContext&amp;lt;
  readonly [
    selectedWalletAccount: SelectedWalletAccountState,
    setSelectedWalletAccount: React.Dispatch&amp;lt;
      React.SetStateAction&amp;lt;SelectedWalletAccountState&amp;gt;
    &amp;gt;,
    selectedWallet: UiWallet | undefined
  ]
&amp;gt;([
  undefined,
  function setSelectedWalletAccount() {
    /* empty */
  },
  undefined,
]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The wallet account context provider handles persistence and synchronization of the selected wallet across sessions. When a user selects a wallet, we save a storage key composed of the wallet name and account address to localStorage. On subsequent visits, the provider attempts to restore the previously selected wallet if it's still available. The provider also handles cleanup when wallets disconnect and ensures the selected account stays synchronized with the actual connected wallets from the Wallet Standard registry.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// src/context/SelectedWalletAccountContextProvider.tsx
import { useEffect, useMemo, useState } from &quot;react&quot;;
import {
  SelectedWalletAccountContext,
  type SelectedWalletAccountState,
} from &quot;./SelectedWalletAccountContext&quot;;
import {
  getUiWalletAccountStorageKey,
  uiWalletAccountBelongsToUiWallet,
  uiWalletAccountsAreSame,
  useWallets,
  type UiWallet,
  type UiWalletAccount,
} from &quot;@wallet-standard/react-core&quot;;

const STORAGE_KEY = &quot;solana-wallet-standard-react:selected-wallet-and-address&quot;;

let wasSetterInvoked = false;

// Attempts to restore previously selected wallet from localStorage
function getSavedWalletAccountAndWallet(
  wallets: readonly UiWallet[]
):
  | { account: UiWalletAccount | undefined; wallet: UiWallet | undefined }
  | undefined {
  // Stop auto-selecting after user makes explicit choice
  if (wasSetterInvoked) {
    return;
  }
  
  const savedWalletNameAndAddress = localStorage.getItem(STORAGE_KEY);
  if (
    !savedWalletNameAndAddress ||
    typeof savedWalletNameAndAddress !== &quot;string&quot;
  ) {
    return;
  }
  
  const [savedWalletName, savedAccountAddress] =
    savedWalletNameAndAddress.split(&quot;:&quot;);
    
  if (!savedWalletName || !savedAccountAddress) {
    return;
  }
  
  // Find matching wallet and account in current connected wallets
  for (const wallet of wallets) {
    if (wallet.name === savedWalletName) {
      for (const account of wallet.accounts) {
        if (account.address === savedAccountAddress) {
          return { account, wallet };
        }
      }
    }
  }
}

export function SelectedWalletAccountContextProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const wallets = useWallets();
  
  const [selectedWalletAccount, setSelectedWalletAccountInternal] =
    useState&amp;lt;SelectedWalletAccountState&amp;gt;(
      () =&amp;gt; getSavedWalletAccountAndWallet(wallets)?.account
    );
  
  const [selectedWallet, setSelectedWalletInternal] = useState&amp;lt;
    UiWallet | undefined
  &amp;gt;(() =&amp;gt; getSavedWalletAccountAndWallet(wallets)?.wallet);
  
  // Wrapper that saves selection to localStorage
  const setSelectedWalletAccount: React.Dispatch&amp;lt;
    React.SetStateAction&amp;lt;SelectedWalletAccountState&amp;gt;
  &amp;gt; = (setStateAction) =&amp;gt; {
    setSelectedWalletAccountInternal((prevSelectedWalletAccount) =&amp;gt; {
      wasSetterInvoked = true;
      const nextWalletAccount =
        typeof setStateAction === &quot;function&quot;
          ? setStateAction(prevSelectedWalletAccount)
          : setStateAction;
          
      const accountKey = nextWalletAccount
        ? getUiWalletAccountStorageKey(nextWalletAccount)
        : undefined;
        
      if (accountKey) {
        localStorage.setItem(STORAGE_KEY, accountKey);
      } else {
        localStorage.removeItem(STORAGE_KEY);
      }
      
      return nextWalletAccount;
    });
  };
  
  // Restore saved wallet on mount
  useEffect(() =&amp;gt; {
    const savedWalletAccount = getSavedWalletAccountAndWallet(wallets)?.account;
    const savedWallet = getSavedWalletAccountAndWallet(wallets)?.wallet;
    
    if (savedWalletAccount &amp;amp;&amp;amp; savedWallet) {
      setSelectedWalletAccountInternal(savedWalletAccount);
      setSelectedWalletInternal(savedWallet);
    }
  }, [wallets]);
  
  // Keep selected account synchronized with connected wallets
  const walletAccount = useMemo(() =&amp;gt; {
    if (selectedWalletAccount) {
      for (const uiWallet of wallets) {
        for (const uiWalletAccount of uiWallet.accounts) {
          if (uiWalletAccountsAreSame(selectedWalletAccount, uiWalletAccount)) {
            return uiWalletAccount;
          }
        }
        
        // If selected account's wallet is connected, use its first account
        if (
          uiWalletAccountBelongsToUiWallet(selectedWalletAccount, uiWallet) &amp;amp;&amp;amp;
          uiWallet.accounts[0]
        ) {
          return uiWallet.accounts[0];
        }
      }
    }
  }, [selectedWalletAccount, wallets]);
  
  const wallet = useMemo(() =&amp;gt; {
    if (selectedWallet) {
      for (const uiWallet of wallets) {
        if (uiWallet.name === selectedWallet.name) {
          return uiWallet;
        }
      }
    }
  }, [selectedWallet, wallets]);
  
  // Clear selection if wallet disconnects
  useEffect(() =&amp;gt; {
    if (selectedWalletAccount &amp;amp;&amp;amp; !walletAccount) {
      setSelectedWalletAccountInternal(undefined);
    }
  }, [selectedWalletAccount, walletAccount]);
  
  return (
    &amp;lt;SelectedWalletAccountContext.Provider
      value={useMemo(
        () =&amp;gt; [walletAccount, setSelectedWalletAccount, wallet],
        [walletAccount, wallet]
      )}
    &amp;gt;
      {children}
    &amp;lt;/SelectedWalletAccountContext.Provider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once our context is set up we can import and use it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// src/main.tsx
import { StrictMode } from &quot;react&quot;;
import { createRoot } from &quot;react-dom/client&quot;;
import &quot;./index.css&quot;;
import App from &quot;./App.tsx&quot;;
import { SelectedWalletAccountContextProvider } from &quot;./context/SelectedWalletAccountContextProvider.tsx&quot;;

createRoot(document.getElementById(&quot;root&quot;)!).render(
  &amp;lt;StrictMode&amp;gt;
    &amp;lt;SelectedWalletAccountContextProvider&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/SelectedWalletAccountContextProvider&amp;gt;
  &amp;lt;/StrictMode&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;wallet-list&quot;&gt;Wallet List&lt;/h4&gt;
&lt;p&gt;With context set up to track wallet state, we can build the UI. Users need a way to see available wallets and connect them to our app. The Wallet Standard exposes all compatible browser wallets, so we'll create a dialog that lists them. We'll start with the wallet list item.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/components/wallet_list_item.tsx
import { Button } from &quot;@/components/ui/button&quot;
import { SelectedWalletAccountContext } from &quot;@/context/SelectedWalletAccountContext&quot;;
import { useConnect, type UiWallet } from &quot;@wallet-standard/react-core&quot;;
import { useContext } from &quot;react&quot;;

type Props = {
  wallet: UiWallet;
  setOpen: () =&amp;gt; void;
};

export const WalletListItem = ({ wallet, setOpen }: Props) =&amp;gt; {
  const [isConnecting, connect] = useConnect(wallet);
  const [_, setSelectedWalletAccount] = useContext(
    SelectedWalletAccountContext
  );
  
  const handleConnect = () =&amp;gt; {
    try {
      // Connect returns array of accounts, we select the first one
      connect().then((res) =&amp;gt; {
        setSelectedWalletAccount(res[0]);
      });
    } catch (error) {
      console.error(&quot;Failed to connect:&quot;, error);
    } finally {
      setOpen();
    }
  };
  
  if (!wallet) return;

  return (
    &amp;lt;li&amp;gt;
      &amp;lt;Button
        variant=&quot;outline&quot;
        disabled={isConnecting}
        onClick={handleConnect}
        className=&quot;flex flex-row p-4 items-center justify-start gap-3 w-full&quot;
      &amp;gt;
        &amp;lt;img alt=&quot;wallet logo&quot; src={wallet.icon} className=&quot;w-6 h-6&quot; /&amp;gt;
        &amp;lt;p className=&quot;text-lg font-semibold&quot;&amp;gt;{wallet.name}&amp;lt;/p&amp;gt;
      &amp;lt;/Button&amp;gt;
    &amp;lt;/li&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing to note is that while we can fetch all wallets connected to the browser, you often only want the ones that support the chain your application is based on. To do this we can create a hook to fetch and filter these wallets for us. You can extend this to work for multiple chains if need be. Extracting this logic into a custom hook is production-grade because it encapsulates the filtering logic in a reusable, testable unit. It makes your components cleaner by separating concerns, and if you need to add more complex filtering logic later or support multiple chains, you only need to modify this one hook rather than hunting through multiple components.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/hooks/useFilteredWallets.tsx
import { useWallets } from &quot;@wallet-standard/react-core&quot;;

export function useFilteredWallets() {
  const wallets = useWallets();
  
  // Filter wallets that support Solana chains
  const solanaWallets = wallets.filter((uiWallet) =&amp;gt;
    uiWallet.chains.some((chain) =&amp;gt; chain.startsWith(&quot;solana:&quot;))
  );

  return solanaWallets;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can implement the actual wallet list to render all connected wallets that match our base chain.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/components/wallet_list.tsx
import { Button } from &quot;@/components/ui/button&quot;;
import {
  DialogHeader,
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogTitle,
  DialogDescription,
} from &quot;@/components/ui/dialog&quot;;
import { WalletListItem } from &quot;./wallet_list_item&quot;;
import { useFilteredWallets } from &quot;../hooks/useFilteredWallets&quot;;
import { useState } from &quot;react&quot;;
  
export const WalletList = () =&amp;gt; {
  const [open, setOpen] = useState(false);
  const solanaWallets = useFilteredWallets();

  return (
    &amp;lt;Dialog open={open} onOpenChange={setOpen}&amp;gt;
      &amp;lt;form&amp;gt;
        &amp;lt;DialogTrigger asChild&amp;gt;
          &amp;lt;Button variant=&quot;outline&quot;&amp;gt;View Wallets&amp;lt;/Button&amp;gt;
        &amp;lt;/DialogTrigger&amp;gt;

        &amp;lt;DialogContent className=&quot;sm:max-w-106.25&quot;&amp;gt;
          &amp;lt;DialogHeader&amp;gt;
            &amp;lt;DialogTitle&amp;gt;Select Wallet&amp;lt;/DialogTitle&amp;gt;
            &amp;lt;DialogDescription&amp;gt;
              Select the wallet you want to connect to Titan.
            &amp;lt;/DialogDescription&amp;gt;
          &amp;lt;/DialogHeader&amp;gt;

          &amp;lt;ul className=&quot;flex flex-col gap-2&quot;&amp;gt;
            {solanaWallets.map((wallet, idx) =&amp;gt; (
              &amp;lt;WalletListItem
                key={idx}
                wallet={wallet}
                setOpen={() =&amp;gt; setOpen(false)}
              /&amp;gt;
            ))}
          &amp;lt;/ul&amp;gt;
        &amp;lt;/DialogContent&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/Dialog&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;sign-in-button&quot;&gt;Sign-In Button&lt;/h4&gt;
&lt;p&gt;Once a wallet is connected, we need to authenticate the user. This is where the full flow comes together: request nonce, sign it, send to backend. This is just going to be a simple button that triggers the auth flow.&lt;/p&gt;
&lt;p&gt;The first thing that will happen on click is that we request a nonce from our backend. Immediately after we get the nonce we use the &lt;code&gt;useSignIn&lt;/code&gt; hook to sign our message. We then extract the results we need and send them in our login request.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// features/auth/components/auth_buttons.tsx
import { useSignIn } from &quot;@solana/react&quot;;
import { Button } from &quot;@/components/ui/button&quot;;
import { requestNonce } from &quot;../api/requestNonce&quot;;
import { loginWithWallet } from &quot;../api/loginWithWallet&quot;;
import type { UiWallet } from &quot;@wallet-standard/react-core&quot;;

type SignInProps = {
  address: string;
  wallet: UiWallet;
};

export const SignInButton = ({ wallet, address }: SignInProps) =&amp;gt; {
  const signIn = useSignIn(wallet);
  
  if (!wallet) return;

  const handleSignIn = async () =&amp;gt; {
    try {
      // Request nonce from backend
      const res = await requestNonce(address);

      // Sign the message with wallet's private key
      const { account, signedMessage, signature } = await signIn({
        nonce: res.nonce,
        domain: import.meta.env.VITE_APP_DOMAIN || &quot;localhost:5173&quot;,
      });

      // Send signed data to backend for verification
      const loginResponse = await loginWithWallet({
        address: account.address,
        signatureBase58: signature,
        message: signedMessage,
        nonce: res.nonce,
      });
      
      // Store access token (you might want to use a state management solution)
      localStorage.setItem('access_token', loginResponse.access_token);
      
      console.log('Successfully authenticated!');
    } catch (error) {
      console.error(&quot;Failed to sign in:&quot;, error);
      // You might want to show this error to the user via a toast or alert
    }
  };
  
  return &amp;lt;Button onClick={handleSignIn}&amp;gt;Sign In&amp;lt;/Button&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our finished App.tsx looks like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// App.tsx
import { useContext } from &quot;react&quot;;
import { WalletList } from &quot;./features/auth/components/wallet_list&quot;;
import { SelectedWalletAccountContext } from &quot;./context/SelectedWalletAccountContext&quot;;
import { SignInButton } from &quot;./features/auth/components/auth_buttons&quot;;

function App() {
  const [selectedWalletAccount, _, selectedWallet] = useContext(
    SelectedWalletAccountContext
  );

  return (
    &amp;lt;div className=&quot;flex gap-3 min-h-svh flex-col items-center justify-center&quot;&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p className=&quot;text-lg font-semibold&quot;&amp;gt;
          Active account: {selectedWalletAccount?.address || 'None'}
        &amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;WalletList /&amp;gt;

      {selectedWalletAccount &amp;amp;&amp;amp; selectedWallet &amp;amp;&amp;amp; (
        &amp;lt;SignInButton
          address={selectedWalletAccount.address}
          wallet={selectedWallet}
        /&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;frontend-summary&quot;&gt;Frontend Summary&lt;/h4&gt;
&lt;p&gt;That wraps up the frontend implementation. We've built a wallet connection system that integrates with the Wallet Standard to support any compatible Solana wallet, not just Phantom. The context provider manages wallet selection persistence across sessions, while the sign-in flow requests a nonce from the backend, prompts the user to sign it with their wallet, and sends the signed message back for verification. The private key never leaves the user's wallet, ensuring security throughout the process.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;We've implemented a complete wallet-based authentication system for Solana. The backend generates unique nonces with Redis-backed storage, creates SIWS-compliant challenge messages, verifies signatures using Solana's cryptographic primitives, and manages JWT token generation after successful verification. The frontend leverages the Wallet Standard to support multiple wallet providers and handles the signing flow securely within the user's wallet extension.&lt;/p&gt;
&lt;p&gt;This auth pattern is fundamentally different from traditional username/password authentication because the user proves ownership of their wallet through cryptographic signatures rather than shared secrets. The nonce prevents replay attacks, the standardized message format prevents phishing, and the time-limited Redis storage ensures old challenges can't be reused. You can extend this system by adding additional user data to the JWT payload, implementing token refresh logic, or supporting multiple blockchain networks with minimal modifications to the core flow.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/27699/how-to-authenticate-users-with-solana-wallets-in-nestjs</guid>
<pubDate>Sat, 19 Sep 2026 07:40:14 +0000</pubDate>
</item>
<item>
<title>Building an AI DeFi Agent: When the LLM gets &quot;Paper Hands&quot;</title>
<link>https://coderlegion.com/24360/building-an-ai-defi-agent-when-the-llm-gets-paper-hands</link>
<description>&lt;p&gt;A reality check on building in public: Sometimes, your AI Agent isn’t stopped by market volatility, but by its own over-cautious brain.&lt;br&gt;
Here is a live lesson from the development of OpenClaw—my autonomous DLMM LP bot on Solana.&lt;/p&gt;
&lt;p&gt;The Incident&lt;br&gt;
Yesterday, while managing a SOL-USDC pool, the market was completely fine.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Position Health: 100% In-range (Deviation was at a tight 12 bps).&lt;/li&gt;
&lt;li&gt;The Math: Fee earned was $0.11, while Impermanent Loss (IL) sat at $0.34.&lt;br&gt;
Because \(Fee &amp;lt; IL\) at that exact moment, our LLM engine (DeepSeek) triggered a hard AVOID verdict. It was blindly following an old system prompt hint: “Avoid the position if fee_over_il &amp;lt; 1 for multiple ticks to prevent bleeding.”&lt;br&gt;
As a result, the bot ignored the core strategy's SAFE signal, panicked, and flattened the position for a minor -$0.24 loss. It chose safety over data.&lt;br&gt;
The Realization&lt;br&gt;
In Concentrated Liquidity (CLMM/DLMM), temporary IL exceeding fees during minor price movements is completely normal. If you panic-exit every time the price wiggles, you get eaten alive by gas, slippage, and transaction fees. The LLM was being too &quot;chicken&quot; (paper hands).&lt;br&gt;
The Fix : We just pushed an architectural update to tighten the chain of command:&lt;ol&gt;
&lt;li&gt;The &quot;In-Band Ride&quot; Rule: If the position is live, healthy, and inside the safe band, the bot must HOLD. The LLM cannot override and force an exit solely based on temporary \(Fee &amp;lt; IL\) metrics.&lt;/li&gt;
&lt;li&gt;Context Refinement: Rewrote the prompt instructions. The AI now understands that volatility breeds opportunity, and running away too early is a guaranteed loss.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Current Status&lt;br&gt;
The patch is live. The bot is back in the trenches, scanning, and riding the waves with a bit more grit this time.&lt;br&gt;
Building an automated financial agent isn't about creating a perfect system on day one. It’s about logging the errors, refining the boundaries between hard-coded boundaries and AI reasoning, and surviving the edge cases.&lt;br&gt;
Real capital. Real code. Real lessons.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24360/building-an-ai-defi-agent-when-the-llm-gets-paper-hands</guid>
<pubDate>Mon, 10 Aug 2026 04:26:54 +0000</pubDate>
</item>
<item>
<title>The Contract Is Not the Story. The Process Behind It Is.</title>
<link>https://coderlegion.com/21208/the-contract-is-not-the-story-the-process-behind-it-is</link>
<description>&lt;p&gt;How behavioral intent detection changes the security calculus — in Web3 and beyond.&lt;/p&gt;
&lt;p&gt;Most security tools ask a binary question: is this object safe or not? Is this contract clean? Is this password valid? Is this file malicious?&lt;/p&gt;
&lt;p&gt;That framing made sense when attackers were unsophisticated. It no longer does.&lt;/p&gt;
&lt;p&gt;The dominant threat model today is not a single bad actor running a single bad transaction. It is an industrial process — coordinated, automated, temporally distributed — designed specifically to pass every object-level check while the damage accumulates invisibly underneath.&lt;/p&gt;
&lt;p&gt;The answer is not a better scanner. It is a fundamentally different question: not what is this object, but what process produced it, and what does that process intend to do next?&lt;/p&gt;
&lt;p&gt;Stage 2 vs Stage 3: A Shift in What We're Analyzing&lt;/p&gt;
&lt;p&gt;Classic blockchain security operates at what we call Stage 2: the analysis of stabilized objects. A deployed contract. A token's holder distribution. A wallet's current balance. These are artifacts — the frozen output of processes that have already run.&lt;/p&gt;
&lt;p&gt;Stage 2 tools are necessary. They are not sufficient.&lt;/p&gt;
&lt;p&gt;Stage 3 is the analysis of processes before they stabilize — catching the signal in the pre-action layer, while intent is still forming and before it crystallizes into an on-chain fact.&lt;/p&gt;
&lt;p&gt;On Solana, this means three concrete data extraction points.&lt;/p&gt;
&lt;p&gt;Three Pre-Action Signal Layers on Solana&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Jito MEV Mempool and Transaction Buffer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ordinary transactions go directly to slot leaders. Complex activity — bots, snipers, coordination structures — routes through the Jito mempool for tip optimization and front-run minimization.&lt;/p&gt;
&lt;p&gt;This creates a detectable pre-execution layer.&lt;/p&gt;
&lt;p&gt;When 20 new wallets simultaneously submit transactions sharing identical simulation hashes in Jito, that is not organic user activity. That is the deployment signature of a coordinated process. The object — the contract, the token — does not yet exist. The process creating it is already visible.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pre-Funding Chain Analysis&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Token factories and Sybil networks reveal themselves during the gas-funding phase. Even when they route through bridges or liquidity distributors, the timing and volume distribution of those funding flows create a unique wave signature.&lt;/p&gt;
&lt;p&gt;We model this as a directed graph where edge weights are determined by the time delta between funding transactions.&lt;/p&gt;
&lt;p&gt;An organic user funds a wallet from an exchange or personal address — spontaneously, inconsistently. An automated network does it in a cascade: deterministic intervals, consistent amounts, predictable depth. The vector field captures this cascade at the first or second child transaction, long before any token is deployed or any pool is created.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Dry-Run and Simulation Traffic&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Large-scale attack operators always probe before they strike. They use simulateTransaction at scale to verify that their contract or exploit will execute correctly under current network conditions.&lt;/p&gt;
&lt;p&gt;Individual simulation logs are private to specific nodes. But aggregated anomaly patterns from RPC providers — sudden spikes in simulation requests against specific pool metadata, unusual call structure clustering — expose the preparation phase. The attack has not happened. The intent is already measurable.&lt;/p&gt;
&lt;p&gt;The Intent Vector Field&lt;/p&gt;
&lt;p&gt;These three signal layers feed into what we call the Intent Vector Field: a probability distribution over competing behavioral scenarios.&lt;/p&gt;
&lt;p&gt;When we observe an anomalous micro-variance jitter — a sudden burst of correlated micro-activity across multiple addresses — the system does not flag it as &quot;suspicious.&quot; It distributes probability mass across competing interpretations:&lt;/p&gt;
&lt;p&gt;Wash trading setup — manufactured volume to simulate organic interest&lt;br&gt;
Liquidity drain preparation — coordinated positioning before a rug&lt;br&gt;
Organic hype — genuine sudden interest from real users&lt;/p&gt;
&lt;p&gt;Each scenario has a different temporal signature, a different graph topology, a different simulation traffic pattern. The model weights these signals dynamically as new data arrives, updating the probability distribution in real time.&lt;/p&gt;
&lt;p&gt;The output is not a binary alert. It is a vector of intent — explainable, auditable, and falsifiable.&lt;/p&gt;
&lt;p&gt;The Same Logic Applied to Web2: FortiBleed&lt;/p&gt;
&lt;p&gt;The paradigm shift from object analysis to process analysis is not specific to blockchain. It is a general security architecture principle — and its absence is why traditional enterprise security keeps failing at scale.&lt;/p&gt;
&lt;p&gt;Consider the FortiBleed credential harvesting campaign: 659 discrete collection cycles, 86,000 internet-facing FortiGate devices compromised, 110 million credentials extracted. The attacker was an Initial Access Broker operating as an automated factory — not a hacker, a process.&lt;/p&gt;
&lt;p&gt;Traditional defenses asked the wrong question at every layer: Is this traffic authorized? Is this password valid? Is this file known malware? The answers were often yes, yes, and no — while the exfiltration continued.&lt;/p&gt;
&lt;p&gt;A Stage 3 behavioral architecture would have intervened at three points.&lt;/p&gt;
&lt;p&gt;First: Process clustering, not device isolation. When 430,000 firewalls across the world begin executing synchronous micro-requests toward the same command-and-control infrastructure, the distributed pattern is the signal. Each individual device looks clean. The coordinated behavior across devices is the attack. A behavioral engine modeling this as a unified process — rather than 430,000 independent events — produces an intent vector early: Data Exfiltration Campaign: 0.95.&lt;/p&gt;
&lt;p&gt;Second: Pre-action detection of credential validation. IABs do not just steal credentials — they verify them. The FortigateSniffer toolchain included automated validity checking of collected accounts. This verification process generates an anomalous internal authentication traffic pattern on the compromised device: bursts of auth requests, not tied to any user session, testing accounts that are not currently active.&lt;/p&gt;
&lt;p&gt;A system monitoring this pre-action behavior layer detects the credential validation phase as preparation — not as exfiltration, which comes later — giving defenders a window to intervene before the harvested data leaves the network.&lt;/p&gt;
&lt;p&gt;Third: Identity scoring over binary access. NATO defense contractors operate on binary access models: if you have the right credentials, you are in. This assumption breaks completely when credentials are the attack surface.&lt;/p&gt;
&lt;p&gt;An identity scoring layer changes the question from did this entity authenticate correctly? to does this entity's behavior match a known-legitimate access pattern? Even with a valid stolen password, a session driven by automated tooling — anomalous navigation speed, unusual data request patterns, network-layer jitter inconsistent with human interaction — scores high on archetypes like Automated_Data_Scraper or Lateral_Movement_Operator. The session is isolated regardless of credential validity.&lt;/p&gt;
&lt;p&gt;The Common Thread&lt;/p&gt;
&lt;p&gt;NexusVeritas applies this architecture to Web3: behavioral classification of wallet deployers, identification of coordinated Sybil structures, pre-deployment signal detection on Solana. The specific domain is on-chain. The mathematical foundation is domain-agnostic.&lt;/p&gt;
&lt;p&gt;The pattern across every major breach of the past year — MEV honeypots, bridge proof forgery, infinite mint exploits, supply-chain backdoors, credential harvesting campaigns — is consistent:&lt;/p&gt;
&lt;p&gt;The object passed inspection. The process behind it did not.&lt;/p&gt;
&lt;p&gt;A fake token pair that passes contract verification. A forged bridge proof that passes cryptographic validation. A stolen password that passes authentication. A backdoored plugin update that passes integrity checks.&lt;/p&gt;
&lt;p&gt;In every case, the process that produced the malicious object had a behavioral signature before the object existed. In every case, the tools being used were not designed to read that signature.&lt;/p&gt;
&lt;p&gt;The question is not whether the contract is lying. It is whether the process that deployed it has done this before — and what it is preparing to do next...?&lt;/p&gt;
&lt;p&gt;*NexusVeritas is a behavioral risk infrastructure for Solana — deployer history analysis, wallet archetype classification, and pre-deployment signal detection.&lt;br&gt;
GitHub: github.com/cryptaveritas | X: @Syp_137&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21208/the-contract-is-not-the-story-the-process-behind-it-is</guid>
<pubDate>Tue, 23 Jun 2026 12:58:39 +0000</pubDate>
</item>
<item>
<title>We Were About to Launch. First, We Decided to Hack Ourselves.</title>
<link>https://coderlegion.com/20807/we-were-about-to-launch-first-we-decided-to-hack-ourselves</link>
<description>&lt;p&gt;It was an ordinary Tuesday. The API was running, tests were passing, Docker came up on the first try. We were already imagining our first clients — B2B integrations, Telegram bots, deals.&lt;/p&gt;
&lt;p&gt;Then someone on the team said: &quot;What if we try to break everything first?&quot;&lt;/p&gt;
&lt;p&gt;Good idea. It almost always turns out things break faster than you expect.&lt;/p&gt;
&lt;p&gt;What We Were Building&lt;/p&gt;
&lt;p&gt;An analytical API for assessing Solana token risks. Not another contract scanner — there are dozens of those. We do behavioral analysis: who's behind the token, what's the history of that wallet, does the pattern resemble known manipulation schemes.&lt;/p&gt;
&lt;p&gt;Over several months we built a database, trained a classifier, stood up a NestJS API with PostgreSQL and Redis, wrapped everything in Docker. By all indications — production-ready.&lt;/p&gt;
&lt;p&gt;By all indications.&lt;/p&gt;
&lt;p&gt;Hour One. &quot;Wait, You Can Actually Break This&quot;&lt;/p&gt;
&lt;p&gt;We found the first vulnerability almost immediately. Not because we searched long — we just looked at the code with fresh eyes.&lt;/p&gt;
&lt;p&gt;Our API accepts a Solana token address in the URL and passes it to an external script for analysis. It looked something like this:&lt;/p&gt;
&lt;p&gt;const output = execSync(&lt;br&gt;
  &lt;code&gt;node -e &quot;fetchData('${mintAddress}').then(...)&quot;&lt;/code&gt;&lt;br&gt;
);&lt;/p&gt;
&lt;p&gt;See the problem? We were inserting a string from an HTTP request directly into a shell command. Without any validation whatsoever.&lt;/p&gt;
&lt;p&gt;In theory, anyone who knows our endpoint address could send something like '); rm -rf /app; node -e (' instead of a token address — and that command would execute on our server. It's called shell injection, and it's one of the oldest vulnerabilities in the book.&lt;/p&gt;
&lt;p&gt;We had been running for several months. This code had been there the whole time.&lt;/p&gt;
&lt;p&gt;It was a little unsettling.&lt;/p&gt;
&lt;p&gt;Fixed it in twenty minutes: added a format check before touching the input at all. Solana addresses are base58 — a strictly defined character set. Everything else gets an immediate 400.&lt;/p&gt;
&lt;p&gt;typescriptif (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(mintAddress)) {&lt;br&gt;
  throw new BadRequestException('Invalid mint address format');&lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;Simple. Effective. Should have been there from day one.&lt;/p&gt;
&lt;p&gt;Hour Two. When Everything Works, Just Not the Way You Think&lt;/p&gt;
&lt;p&gt;The second finding was subtler. Looks harmless on the surface. In practice — a ticking time bomb.&lt;/p&gt;
&lt;p&gt;NestJS has a Dependency Injection mechanism: you register services in modules, the framework figures out who provides what to whom. Convenient. But we had registered the same service in two places at once.&lt;/p&gt;
&lt;p&gt;What happens in that case? NestJS doesn't complain. Doesn't warn you. It just quietly creates two separate instances of the same service.&lt;/p&gt;
&lt;p&gt;Sounds benign. But our database service holds a connection pool to PostgreSQL. Two instances — two pools. Under load, that means twice as many open connections as planned. PostgreSQL has a limit on simultaneous connections. Exceed that limit and the database stops responding.&lt;/p&gt;
&lt;p&gt;We would have discovered this at three in the morning when the first client complained the API was down.&lt;/p&gt;
&lt;p&gt;Hour Three. When &quot;All Green&quot; Is a Lie&lt;/p&gt;
&lt;p&gt;The next discovery was, perhaps, the most uncomfortable. Not because it was dangerous — because it was embarrassing.&lt;/p&gt;
&lt;p&gt;We have a list of known exchange and bridge addresses. If several large buyers of a token were funded from one of these addresses — that's normal, that's not insider collusion. Sound logic.&lt;/p&gt;
&lt;p&gt;But when we opened the file with those addresses, here's what we saw:&lt;/p&gt;
&lt;p&gt;typescriptconst BRIDGE_ADDRESSES = new Set([
  'BLZRi6frs4X4DNLw56waFf6jNav84j6bKrikoZejset5', // Mayan — real
  'debridge...',  // ← literally three dots
  'worm...',      // ← three dots again
  'binance...',   // ← and again
]);&lt;/p&gt;
&lt;p&gt;Someone at some point wrote a placeholder instead of a real address. And forgot. Tests didn't catch it because tests didn't know what a correct Wormhole Bridge address was supposed to look like.&lt;/p&gt;
&lt;p&gt;The code compiled. The service started. The function was called. Results were returned. Everything was &quot;green.&quot;&lt;/p&gt;
&lt;p&gt;And everything was wrong.&lt;/p&gt;
&lt;p&gt;Three out of four addresses in our protection list didn't exist. Any coordinated buying scheme through those bridges would have gone undetected.&lt;/p&gt;
&lt;p&gt;We spent an hour finding real verified addresses and replacing the stubs with actual data. Tedious work. But exactly these tedious things stand between you and a reputational disaster.&lt;/p&gt;
&lt;p&gt;Hour Four. The Detective and the Unreliable Witness&lt;/p&gt;
&lt;p&gt;Probably the most interesting finding — and the hardest to debug.&lt;/p&gt;
&lt;p&gt;One of the key elements of our analysis is determining the token creator. Who launched this memecoin? What's their history? Have we seen this wallet before?&lt;/p&gt;
&lt;p&gt;The algorithm was straightforward: page through the token's transaction history from the end backward, find the very first one — that's the creation transaction, its initiator is the creator.&lt;/p&gt;
&lt;p&gt;The problem surfaced by accident. We made three consecutive requests to the same token and got three different creator addresses.&lt;/p&gt;
&lt;p&gt;One token. Three requests. Three different &quot;creators.&quot;&lt;/p&gt;
&lt;p&gt;The investigation took a while. Turns out: the algorithm paged through history in batches of 1,000 transactions but made a maximum of three batches. For popular tokens with thousands of transactions, the algorithm simply never reached the very first one — and each time returned a different result depending on which transactions ended up &quot;last&quot; in the pagination.&lt;/p&gt;
&lt;p&gt;Imagine a detective questioning witnesses in random order and getting different testimony every time. Not because the witnesses are lying — he just talks to different people each time.&lt;/p&gt;
&lt;p&gt;The fix was straightforward: increase the batch limit from three to ten. Now the algorithm always reaches the beginning of the history. Three requests — one result.&lt;/p&gt;
&lt;p&gt;Hour Five. The Things You Don't Think About Until It's Too Late&lt;/p&gt;
&lt;p&gt;The rest of the day went to what most developers put off &quot;for later.&quot; Things that seem obvious when you read about them — and that you don't think about when you're writing code at two in the morning.&lt;/p&gt;
&lt;p&gt;API without rate limiting. Our endpoint was open to any volume of requests. A single script could take down the service with endless calls or exhaust the limits of the external APIs we depend on. We added 60 requests per minute per IP — standard protection, but it wasn't there.&lt;/p&gt;
&lt;p&gt;No security headers. Browser clients received no security policy instructions whatsoever. We added helmet — one line of code that closes an entire class of browser-based attacks.&lt;/p&gt;
&lt;p&gt;500 instead of 400. When a request came in for an unsupported blockchain, our API returned 500 Internal Server Error. Not because something was broken — we were just throwing a plain Error instead of a BadRequestException. For an integrator, the difference between 400 and 500 is fundamental: the first means &quot;you did something wrong,&quot; the second means &quot;we crashed.&quot;&lt;/p&gt;
&lt;p&gt;The Tally: Seven Hours Against Seven Vulnerabilities&lt;/p&gt;
&lt;p&gt;By evening we had seven closed items and one uncomfortable realization.&lt;/p&gt;
&lt;p&gt;We hadn't done anything exotic. We hadn't used unvetted libraries. We hadn't reinvented the wheel where we didn't need to. We just wrote code — the way most of us write it in &quot;ship the feature&quot; mode.&lt;/p&gt;
&lt;p&gt;And in that code lived perfectly classic vulnerabilities. Shell injection from a 1998 textbook. Provider duplication that doesn't complain but breaks logic under load. Stubs in a critical place that nobody replaced.&lt;/p&gt;
&lt;p&gt;All of this would have been discovered by the first clients. At the worst possible moment. When fixing it would cost far more.&lt;/p&gt;
&lt;p&gt;The most important thing we learned: a security audit isn't about hunting exotic zero-day vulnerabilities. It's about slowing down and looking at your own code like a stranger would. What here was done on autopilot? What was a &quot;temporary solution&quot; three months ago? What do tests not check — because they don't know what to check for?&lt;/p&gt;
&lt;p&gt;Seven hours of work. Seven findings. Not one of them required genius — just attention.&lt;/p&gt;
&lt;p&gt;The project is currently in closed beta. Due to the nature of our security research and the uniqueness of the underlying classification methodology, only a partial overview is made available to the public at this stage. Core components — including the behavioral classifier, archetype definitions, and wallet dataset — remain proprietary. We'll announce the public launch and partnership opportunities separately.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20807/we-were-about-to-launch-first-we-decided-to-hack-ourselves</guid>
<pubDate>Wed, 17 Jun 2026 13:07:28 +0000</pubDate>
</item>
<item>
<title>The Death of Smart Contract Audits: Why NexusVeritas Hunts Web3 Scammers via Behavioral DNA</title>
<link>https://coderlegion.com/20402/the-death-smart-contract-audits-why-nexusveritas-hunts-web3-scammers-via-behavioral-dna</link>
<description>&lt;p&gt;The Web3 security industry is facing a fundamental methodology crisis. For years, smart contract auditing—encompassing Abstract Syntax Tree (AST) static analysis, formal verification, and searching for vulnerabilities like Reentrancy—has been considered the gold standard of asset protection.&lt;/p&gt;
&lt;p&gt;However, the threat landscape has shifted. In high-speed ecosystems (primarily Solana), a new type of fraud dominates. Attackers no longer need to write complex code with hidden backdoors. They deploy perfectly legitimate, templated tokens or use automated launchpads (such as pump.fun), executing the exploit (Rug Pulls, liquidity manipulation) entirely at the behavioral mechanics layer.&lt;/p&gt;
&lt;p&gt;In this environment, traditional code analysis is blind. The NexusVeritas project introduces an alternative paradigm: a definitive shift from token-centric audits to behavioral operator fingerprinting (Actor-Centric Security).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Shift to Actor-Centric Security&lt;br&gt;
Modern Web3 security metrics present a paradox: while the volume of malicious tokens stealing user funds is skyrocketing, their underlying code often remains completely flawless. On Solana, a standard SPL token can be deployed in a few clicks. The fraudulent scheme relies entirely on a pre-funded, coordinated network of interconnected wallets managing rotation, fund recycling, and wash trading.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The contract itself might be textbook-perfect, but the deployer's behavioral footprint is always uniquely identifiable. Fraudsters operate under tight time and resource constraints, repeating the same infrastructure patterns over and over. NexusVeritas captures this exact &quot;digital DNA&quot;.&lt;/p&gt;
&lt;p&gt;Conceptual Paradigm Shift: Instead of evaluating the safety of isolated software code, NexusVeritas profiles the reputational and behavioral history of the actor operating that code. It acts as an advanced on-chain equivalent to credit scoring for pseudo-anonymous entities.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Core Engineering: Time-Decay Windows and Data Architecture&lt;br&gt;
The core engine transforms on-chain primitives (funding sources, launch cadence, signature density, wallet rotation) into behavioral embeddings. The system ingests raw blockchain data, models the operator profile, and pushes vectors into a pgvector storage engine built on PostgreSQL for similarity searches against known malicious archetypes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Temporal Dynamics (Variant A)&lt;br&gt;
The biggest vulnerability of anti-fraud systems is behavioral volatility. An operator might execute a rug pull, remain dormant or act legitimately for months, and then spin up a new exploit network. To solve this, NexusVeritas decouples the actor's behavior into three independent sliding temporal windows, managed via distinct HNSW/IVFFlat indexes:&lt;/p&gt;
&lt;p&gt;30d (Current Activity): Tracks operational signature density and immediate launch cadence. Powered by a high-precision HNSW index for real-time inference.&lt;br&gt;
90d (Medium-Term Patterns): Evaluates the consistency of the actor's behavioral cadence.&lt;br&gt;
all_time (Historical Attribution): Traces the genesis of capital and operational origin. Uses an IVFFlat index to optimize RAM scaling over large historical volumes.&lt;br&gt;
The mathematical divergence (cosine distance) between these temporal slices is extracted as an independent machine learning feature (Delta-features). If short-term embeddings radically diverge from the historical baseline, the system flags a trajectory anomaly (e.g., a &quot;professional creator&quot; profiling shift into a &quot;serial scammer&quot;).&lt;/p&gt;
&lt;p&gt;The Solana Data Challenge&lt;br&gt;
NexusVeritas chose a Solana-first engineering path, which presents significantly higher data-ingestion complexity than EVM chains. In Ethereum, parsers lean on standardized Event Logs. Solana lacks a native event log model; data pipelines must continuously process Account State Transitions and deserialize nested cross-program instructions (Inner Instructions / CPI). Resolving this at the data-mapper adapter layer allows the core fingerprinting methodology to remain fully chain-agnostic.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Defeating Cold Start: The Active Learning Pipeline&lt;br&gt;
Training the final production classifier (XGBoost) requires a highly vetted, high-confidence labeled dataset. Training on noisy or sparse data inevitably leads to overfitting. NexusVeritas circumvents data scarcity via a production-grade Active Learning loop (blending Uncertainty and Diversity query sampling strategies) powered by an ultra-lean Express + HTMX review panel.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;[60 Ground Truth Cases] ➔ [k-NN Search in pgvector] ➔ [Candidate Queue]&lt;br&gt;
▼&lt;br&gt;
[Valid Dataset for XGBoost] ◀ [Hotkeys 1/2/3 Click] ◀ [Review UI (HTMX)]&lt;/p&gt;
&lt;p&gt;Manual tracking of complex funding chains via Solscan typically consumes up to 40 minutes per operator. By leveraging a custom UI that pre-caches top-3 primary funding nodes directly into the candidate metadata, this audit is reduced to seconds. Combined with native keyboard hotkeys (1 — Confirm, 2 — Reject, 3 — Skip), labeling throughput surges from 1–2 cases to 100+ cases per hour, building a pristine 500+ sample ground truth dataset within a week.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mitigation of Invisible Threat: Halting Silent Degradation&lt;br&gt;
A major risk surfaced during architectural design: Silent Degradation. As professional scam syndicates evolve, they mask capital deployment through multi-layered Sybil splitter networks 4 to 5 hops deep. Standard recursive SQL Common Table Expressions (CTEs) within relational databases fail to resolve the origin, causing the system to silently degrade—emitting Safe scores for advanced exploit networks without throwing fatal application alerts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To eliminate Silent Degradation, NexusVeritas implements a three-layered defense matrix:&lt;/p&gt;
&lt;p&gt;Proactive Memgraph Migration Threshold: The milestone for migrating to an in-memory graph architecture has been moved forward to the 1,000–1,500 operator range, preventing recursive CTE production crashes.&lt;br&gt;
Failsafe Query Timeouts and Metrics: The pipeline engine (build_graph.js) enforces a strict database constraint: SET statement_timeout = '5s'. If a complex Sybil structure triggers this timeout, the engine catches it, returns a partial graph, and appends a graph_truncated: true flag. Monitoring the ratio of truncated graphs via daily_metrics.js serves as an early-warning signal for infrastructure scaling.&lt;br&gt;
Combinatorial Explosion Filtering: Prior to graph recursion, a knownServices.json filter drops highly connected network hubs (centralized exchanges, systemic aggregators) at hop-1, preventing graph path inflation.&lt;br&gt;
⚠️ Feature Engineering Guardrail: Binary features are explicitly mapped into three structural states for XGBoost (both_positive, both_negative, one_positive). This guarantees that the gradient boosting model learns true shared infrastructure signals instead of building split decisions on shared absence (Zero-Zero agreement sparsity).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Target State: The Polyglot Persistence Hybrid Architecture&lt;br&gt;
The mature target architecture for NexusVeritas deploys a polyglot persistence model. An in-memory graph database does not replace the vector index; rather, it decouples graph traversal logic from flat vector arithmetic in a high-throughput pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ComponentRole in EngineMechanicsCore Advantage&lt;br&gt;
Memgraph + GNN LayerNetwork ContextualizerAsynchronously processes network topologies, computes node centrality metrics (PageRank), and extracts deep structural embeddings via GraphSAGE algorithms.Eliminates multi-hop blind spots; unmasks sophisticated, deeply nested Sybil splitter structures.&lt;br&gt;
pgvector (PostgreSQL)Fast Similarity MatcherStores real-time behavioral vectors (30d/90d) alongside structural GNN embeddings exported from Memgraph. Runs low-latency K-NN searches.Highly predictable RAM overhead, ultra-fast transactional queries, and rock-solid storage persistence.&lt;br&gt;
By bypassing the &quot;black box&quot; nature of massive, uninterpretable neural networks, NexusVeritas provides an explainable, lightning-fast risk scoring framework positioned at the intersection of behavioral and structural blockchain analysis. In an ecosystem where transaction speeds are measured in milliseconds, actor-centric risk engines are transitioning from an operational luxury to a core piece of Web3 infrastructure.&lt;/p&gt;
&lt;p&gt;*&lt;em&gt;Methodology and Sources:&lt;/em&gt; This architectural disclosure is synthesized from NexusVeritas project design files, Active Learning frameworks for low-label entity classification, and hybrid graph-vector engineering patterns optimized for high-throughput block execution runtimes (EVM/Solana, 2026).*&lt;/p&gt;
</description>
<category>Discussions</category>
<guid isPermaLink="true">https://coderlegion.com/20402/the-death-smart-contract-audits-why-nexusveritas-hunts-web3-scammers-via-behavioral-dna</guid>
<pubDate>Fri, 12 Jun 2026 12:19:47 +0000</pubDate>
</item>
<item>
<title>The OrbitFlare SDK: One Rust Crate Solana Transport</title>
<link>https://coderlegion.com/17783/the-orbitflare-sdk-one-rust-crate-solana-transport</link>
<description>&lt;h2 id=&quot;the-orbitflare-sdk-one-rust-crate-solana-transport&quot;&gt;The OrbitFlare SDK: One Rust Crate Solana Transport&lt;/h2&gt;
&lt;div id=&quot;tc-div&quot;&gt;
   &lt;h4&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/h4&gt;
   &lt;div id=&quot;tc-list&quot;&gt;
      &lt;ol&gt;
         &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#intro&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
         &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#challenge&quot;&gt;Developer Challenges&lt;/a&gt;&lt;/li&gt;
         &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#solution&quot;&gt;How to Solve Them&lt;/a&gt;&lt;/li&gt;
         &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
      &lt;/ol&gt;
   &lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;/h3&gt;
&lt;p&gt;Software development is full of real-world challenges, especially when building systems that rely on reliability and correctness. Even small mistakes can break execution flow or cause unexpected behavior.&lt;/p&gt;
&lt;div class=&quot;div-purple&quot;&gt;
Note: Most developer challenges actually improve debugging skills and system thinking over time.
&lt;/div&gt;
&lt;p&gt;Why does this matter?&lt;/p&gt;
&lt;p&gt;Because writing code is easy — but writing &lt;em&gt;safe and predictable systems&lt;/em&gt; is where real engineering starts.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-developer-challenges&quot;&gt;2. Developer Challenges&lt;/h3&gt;
&lt;h4 id=&quot;a-division-by-zero&quot;&gt;a. Division by Zero&lt;/h4&gt;
&lt;p&gt;A very common runtime issue:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;int total = 50;
int number = 0;
int result = total / number;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This throws &lt;code&gt;ArithmeticException&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;b-null-object-access&quot;&gt;b. Null Object Access&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String username = null;
System.out.println(username.length());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leads to &lt;code&gt;NullPointerException&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;c-invalid-array-index&quot;&gt;c. Invalid Array Index&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;int[] marks = {70, 80, 90};
System.out.println(marks[5]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This triggers &lt;code&gt;ArrayIndexOutOfBoundsException&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;div class=&quot;div-pink&quot;&gt;
Caution: Unhandled errors like these can crash apps and break user experience instantly.
&lt;/div&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-how-to-solve-them&quot;&gt;3. How to Solve Them&lt;/h3&gt;
&lt;h4 id=&quot;a-safe-division&quot;&gt;a. Safe Division&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;try {
   int result = total / number;
} catch (ArithmeticException e) {
   System.out.println(&quot;Division by zero not allowed&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;b-null-checks&quot;&gt;b. Null Checks&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;if(username != null) {
   System.out.println(username.length());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;c-array-validation&quot;&gt;c. Array Validation&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;if(index &amp;lt; marks.length) {
   System.out.println(marks[index]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-conclusion&quot;&gt;4. Conclusion&lt;/h3&gt;
&lt;p&gt;In systems like OrbitFlare SDK or any real-world transport layer, these small mistakes can become critical failures.&lt;/p&gt;
&lt;p&gt;So the key is simple:&lt;/p&gt;
&lt;p&gt; validate inputs&lt;br&gt;
 handle exceptions&lt;br&gt;
 write defensive code&lt;/p&gt;
&lt;p&gt;The more you deal with these issues, the more stable your systems become.&lt;/p&gt;
&lt;p&gt;Happy coding &lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/17783/the-orbitflare-sdk-one-rust-crate-solana-transport</guid>
<pubDate>Thu, 14 May 2026 05:55:09 +0000</pubDate>
</item>
<item>
<title>How to Run Multi-Wallet Buy Pressure on Pump.fun</title>
<link>https://coderlegion.com/10253/how-to-run-multi-wallet-buy-pressure-on-pump-fun</link>
<description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Single-wallet buying looks repetitive. Multi-wallet buy pressure creates organic-looking activity from multiple addresses. Run parallel Buy Bot instances – each with its own wallet – to simulate real market demand and make your chart pump look natural.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-multi-wallet-matters&quot;&gt;Why Multi-Wallet Matters&lt;/h3&gt;
&lt;p&gt;When traders analyze a Pump.fun token, they check who's buying.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Single wallet buying:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;
Wallet A bought 0.1 SOL
Wallet A bought 0.1 SOL
Wallet A bought 0.1 SOL
Wallet A bought 0.1 SOL
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-wallet buying:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Wallet A bought 0.12 SOL
Wallet B bought 0.08 SOL
Wallet C bought 0.15 SOL
Wallet D bought 0.1 SOL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which looks more like real demand? Multi-wallet activity signals &lt;strong&gt;multiple buyers&lt;/strong&gt; interested in your token – not one wallet spamming buys.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;single-vs-multi-wallet-comparison&quot;&gt;Single vs Multi-Wallet Comparison&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Aspect &lt;/th&gt;&lt;th&gt;Single Wallet &lt;/th&gt;&lt;th&gt;Multi-Wallet&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Appearance&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Repetitive, obvious &lt;/td&gt;&lt;td&gt;Organic, natural&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Trader perception&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&quot;One wallet botting&quot; &lt;/td&gt;&lt;td&gt;&quot;Multiple buyers&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Transaction diversity&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Same source &lt;/td&gt;&lt;td&gt;Different addresses&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Setup complexity&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Simple &lt;/td&gt;&lt;td&gt;Requires multiple wallets&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Lower (one bot) &lt;/td&gt;&lt;td&gt;Higher (multiple bots)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Effectiveness&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Chart pumps &lt;/td&gt;&lt;td&gt;Chart pumps + looks real&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;how-multi-wallet-buy-bot-works&quot;&gt;How Multi-Wallet Buy Bot Works&lt;/h3&gt;
&lt;p&gt;Jumpbit Buy Bot runs from a single connected wallet. For multi-wallet buying:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Run multiple Buy Bot instances in parallel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
Instance 1: Wallet A → Buy Bot running
Instance 2: Wallet B → Buy Bot running
Instance 3: Wallet C → Buy Bot running
Instance 4: Wallet D → Buy Bot running
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Each instance operates independently with its own:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wallet address&lt;/li&gt;
&lt;li&gt;Buy amount settings&lt;/li&gt;
&lt;li&gt;Buy rate configuration&lt;/li&gt;
&lt;li&gt;SOL balance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Four different wallets buying your token simultaneously.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;setting-up-multi-wallet-buy-pressure&quot;&gt;Setting Up Multi-Wallet Buy Pressure&lt;/h3&gt;
&lt;h4 id=&quot;step-1-prepare-multiple-wallets&quot;&gt;Step 1: Prepare Multiple Wallets&lt;/h4&gt;
&lt;p&gt;Create or use 3-5 separate Solana wallets.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Purpose &lt;/th&gt;&lt;th&gt;Suggested Balance&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Wallet A &lt;/td&gt;&lt;td&gt;Primary buyer &lt;/td&gt;&lt;td&gt;3-5 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wallet B &lt;/td&gt;&lt;td&gt;Secondary buyer &lt;/td&gt;&lt;td&gt;2-3 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wallet C &lt;/td&gt;&lt;td&gt;Tertiary buyer &lt;/td&gt;&lt;td&gt;2-3 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wallet D &lt;/td&gt;&lt;td&gt;Small buyer &lt;/td&gt;&lt;td&gt;1-2 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Total needed:&lt;/strong&gt; 8-13 SOL across all wallets&lt;/p&gt;
&lt;h4 id=&quot;step-2-fund-each-wallet&quot;&gt;Step 2: Fund Each Wallet&lt;/h4&gt;
&lt;p&gt;Transfer SOL to each wallet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Buy amounts you'll execute&lt;/li&gt;
&lt;li&gt;Platform fees (0.0005 SOL per buy)&lt;/li&gt;
&lt;li&gt;Gas fees (~0.000005 SOL per transaction)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;step-3-open-multiple-browser-tabs-windows&quot;&gt;Step 3: Open Multiple Browser Tabs/Windows&lt;/h4&gt;
&lt;p&gt;For each wallet:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open new browser tab&lt;/li&gt;
&lt;li&gt;Go to &lt;a rel=&quot;nofollow&quot; href=&quot;https://jumpbit.io/en/solana/pumpfun-tools/pumpfun-buy-bot&quot;&gt;Jumpbit Buy Bot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Connect that wallet&lt;/li&gt;
&lt;li&gt;Enter your token address&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;step-4-configure-each-instance-differently&quot;&gt;Step 4: Configure Each Instance Differently&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Key:&lt;/strong&gt; Vary settings across wallets to look organic.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Buy Amount &lt;/th&gt;&lt;th&gt;Buy Rate &lt;/th&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;A &lt;/td&gt;&lt;td&gt;0.1-0.15 SOL &lt;/td&gt;&lt;td&gt;15/min &lt;/td&gt;&lt;td&gt;Larger, steady&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;B &lt;/td&gt;&lt;td&gt;0.05-0.08 SOL &lt;/td&gt;&lt;td&gt;20/min &lt;/td&gt;&lt;td&gt;Medium, frequent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C &lt;/td&gt;&lt;td&gt;0.08-0.12 SOL &lt;/td&gt;&lt;td&gt;10/min &lt;/td&gt;&lt;td&gt;Medium, slower&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;D &lt;/td&gt;&lt;td&gt;0.03-0.05 SOL &lt;/td&gt;&lt;td&gt;25/min &lt;/td&gt;&lt;td&gt;Small, rapid&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;step-5-stagger-start-times&quot;&gt;Step 5: Stagger Start Times&lt;/h4&gt;
&lt;p&gt;Don't start all bots at the exact same second.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
0:00 - Start Wallet A
0:30 - Start Wallet B
1:00 - Start Wallet C
1:30 - Start Wallet D
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;30-60 second gaps&lt;/strong&gt; make the activity pattern look more natural.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;multi-wallet-strategies&quot;&gt;Multi-Wallet Strategies&lt;/h3&gt;
&lt;h4 id=&quot;strategy-1-the-diverse-crowd-3-4-wallets-&quot;&gt;Strategy 1: The Diverse Crowd (3-4 wallets)&lt;/h4&gt;
&lt;p&gt;Simulate different buyer types.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Role &lt;/th&gt;&lt;th&gt;Amount &lt;/th&gt;&lt;th&gt;Rate&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&quot;Whale&quot; &lt;/td&gt;&lt;td&gt;Big buyer &lt;/td&gt;&lt;td&gt;0.15-0.25 SOL &lt;/td&gt;&lt;td&gt;8-12/min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;Trader&quot; &lt;/td&gt;&lt;td&gt;Active buyer &lt;/td&gt;&lt;td&gt;0.08-0.12 SOL &lt;/td&gt;&lt;td&gt;15-20/min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;Retail&quot; &lt;/td&gt;&lt;td&gt;Small buyer &lt;/td&gt;&lt;td&gt;0.03-0.05 SOL &lt;/td&gt;&lt;td&gt;20-30/min&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Effect:&lt;/strong&gt; Looks like whale + traders + retail all buying&lt;/p&gt;
&lt;h4 id=&quot;strategy-2-the-wave-attack-4-5-wallets-&quot;&gt;Strategy 2: The Wave Attack (4-5 wallets)&lt;/h4&gt;
&lt;p&gt;Staggered waves of buying pressure.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
Wave 1 (0-5 min):   Wallet A + B active
Wave 2 (5-10 min):  Wallet C + D active
Wave 3 (10-15 min): Wallet A + C active
Wave 4 (15-20 min): All wallets active (climax)
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Effect:&lt;/strong&gt; Building momentum with multiple buy waves&lt;/p&gt;
&lt;h4 id=&quot;strategy-3-constant-pressure-3-wallets-&quot;&gt;Strategy 3: Constant Pressure (3 wallets)&lt;/h4&gt;
&lt;p&gt;Sustained multi-source buying.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Amount &lt;/th&gt;&lt;th&gt;Rate &lt;/th&gt;&lt;th&gt;Duration&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;A &lt;/td&gt;&lt;td&gt;0.1 SOL &lt;/td&gt;&lt;td&gt;10/min &lt;/td&gt;&lt;td&gt;Continuous&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;B &lt;/td&gt;&lt;td&gt;0.08 SOL &lt;/td&gt;&lt;td&gt;12/min &lt;/td&gt;&lt;td&gt;Continuous&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C &lt;/td&gt;&lt;td&gt;0.06 SOL &lt;/td&gt;&lt;td&gt;15/min &lt;/td&gt;&lt;td&gt;Continuous&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Effect:&lt;/strong&gt; Steady buying from multiple addresses&lt;/p&gt;
&lt;h4 id=&quot;strategy-4-the-sniper-squad-5-wallets-&quot;&gt;Strategy 4: The Sniper Squad (5+ wallets)&lt;/h4&gt;
&lt;p&gt;Many small wallets, quick bursts.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Setup &lt;/th&gt;&lt;th&gt;Details&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Wallets &lt;/td&gt;&lt;td&gt;5-8 wallets&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Amount each &lt;/td&gt;&lt;td&gt;0.02-0.05 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rate &lt;/td&gt;&lt;td&gt;5-10/min each&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Pattern &lt;/td&gt;&lt;td&gt;Rotate which wallets are active&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Effect:&lt;/strong&gt; Many different addresses appearing in buy history&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;cost-breakdown-multi-wallet-campaigns&quot;&gt;Cost Breakdown: Multi-Wallet Campaigns&lt;/h3&gt;
&lt;h4 id=&quot;3-wallet-setup-budget-&quot;&gt;3-Wallet Setup (Budget)&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Buys &lt;/th&gt;&lt;th&gt;Amount &lt;/th&gt;&lt;th&gt;Platform Fee &lt;/th&gt;&lt;th&gt;Buy Cost &lt;/th&gt;&lt;th&gt;Total&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;A &lt;/td&gt;&lt;td&gt;50 &lt;/td&gt;&lt;td&gt;0.1 SOL &lt;/td&gt;&lt;td&gt;0.025 SOL &lt;/td&gt;&lt;td&gt;5 SOL &lt;/td&gt;&lt;td&gt;5.03 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;B &lt;/td&gt;&lt;td&gt;75 &lt;/td&gt;&lt;td&gt;0.06 SOL &lt;/td&gt;&lt;td&gt;0.038 SOL &lt;/td&gt;&lt;td&gt;4.5 SOL &lt;/td&gt;&lt;td&gt;4.54 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C &lt;/td&gt;&lt;td&gt;100 &lt;/td&gt;&lt;td&gt;0.04 SOL &lt;/td&gt;&lt;td&gt;0.05 SOL &lt;/td&gt;&lt;td&gt;4 SOL &lt;/td&gt;&lt;td&gt;4.05 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;225 &lt;/td&gt;&lt;td&gt;- &lt;/td&gt;&lt;td&gt;0.113 SOL &lt;/td&gt;&lt;td&gt;13.5 SOL &lt;/td&gt;&lt;td&gt;&lt;strong&gt;~13.6 SOL&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;5-wallet-setup-standard-&quot;&gt;5-Wallet Setup (Standard)&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Buys &lt;/th&gt;&lt;th&gt;Amount &lt;/th&gt;&lt;th&gt;Total per Wallet&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;A &lt;/td&gt;&lt;td&gt;40 &lt;/td&gt;&lt;td&gt;0.15 SOL &lt;/td&gt;&lt;td&gt;~6 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;B &lt;/td&gt;&lt;td&gt;60 &lt;/td&gt;&lt;td&gt;0.1 SOL &lt;/td&gt;&lt;td&gt;~6 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C &lt;/td&gt;&lt;td&gt;80 &lt;/td&gt;&lt;td&gt;0.08 SOL &lt;/td&gt;&lt;td&gt;~6.5 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;D &lt;/td&gt;&lt;td&gt;100 &lt;/td&gt;&lt;td&gt;0.05 SOL &lt;/td&gt;&lt;td&gt;~5 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;E &lt;/td&gt;&lt;td&gt;100 &lt;/td&gt;&lt;td&gt;0.03 SOL &lt;/td&gt;&lt;td&gt;~3 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;380 &lt;/td&gt;&lt;td&gt;- &lt;/td&gt;&lt;td&gt;&lt;strong&gt;~26.5 SOL&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;making-it-look-organic&quot;&gt;Making It Look Organic&lt;/h3&gt;
&lt;h4 id=&quot;vary-buy-amounts&quot;&gt;Vary Buy Amounts&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt; Every wallet buys exactly 0.1 SOL&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Wallet A: 0.1 SOL
Wallet B: 0.1 SOL
Wallet C: 0.1 SOL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt; Different amounts per wallet&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Wallet A: 0.12 SOL
Wallet B: 0.07 SOL
Wallet C: 0.15 SOL
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;vary-buy-rates&quot;&gt;Vary Buy Rates&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt; All wallets at 20 buys/min&lt;br&gt;
&lt;strong&gt;Good:&lt;/strong&gt; Mix of 8/min, 15/min, 25/min&lt;/p&gt;
&lt;h4 id=&quot;stagger-timing&quot;&gt;Stagger Timing&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt; All start at exactly 10:00:00&lt;br&gt;
&lt;strong&gt;Good:&lt;/strong&gt; Start at 10:00, 10:00:30, 10:01:15, 10:02:00&lt;/p&gt;
&lt;h4 id=&quot;use-different-session-lengths&quot;&gt;Use Different Session Lengths&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt; All run for exactly 30 minutes&lt;br&gt;
&lt;strong&gt;Good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wallet A: 25 min&lt;/li&gt;
&lt;li&gt;Wallet B: 35 min&lt;/li&gt;
&lt;li&gt;Wallet C: 20 min&lt;/li&gt;
&lt;li&gt;Wallet D: 40 min&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;combining-multi-wallet-with-other-bots&quot;&gt;Combining Multi-Wallet with Other Bots&lt;/h3&gt;
&lt;h4 id=&quot;full-organic-looking-stack&quot;&gt;Full Organic-Looking Stack&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Bot &lt;/th&gt;&lt;th&gt;Wallets &lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Buy Bot &lt;/td&gt;&lt;td&gt;3-5 wallets &lt;/td&gt;&lt;td&gt;Multi-source buy pressure&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bump Bot &lt;/td&gt;&lt;td&gt;1 wallet &lt;/td&gt;&lt;td&gt;Front page visibility&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Holder Bot &lt;/td&gt;&lt;td&gt;Creates 20-50 &lt;/td&gt;&lt;td&gt;Holder count credibility&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;coordinated-campaign&quot;&gt;Coordinated Campaign&lt;/h4&gt;
&lt;p&gt;`&lt;br&gt;
Phase 1 (Setup):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Holder Bot creates 30 holders&lt;/li&gt;
&lt;li&gt;Bump Bot starts at 50 BPM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Phase 2 (Buy Pressure):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wallet A starts buying (large amounts)&lt;/li&gt;
&lt;li&gt;30 sec later: Wallet B starts (medium)&lt;/li&gt;
&lt;li&gt;30 sec later: Wallet C starts (small, frequent)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Phase 3 (Sustained):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All wallets running at varied rates&lt;/li&gt;
&lt;li&gt;Bump Bot maintains visibility&lt;/li&gt;
&lt;li&gt;Chart pumping with organic-looking activity&lt;br&gt;
`&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;multi-wallet-management-tips&quot;&gt;Multi-Wallet Management Tips&lt;/h3&gt;
&lt;h4 id=&quot;tip-1-use-browser-profiles&quot;&gt;Tip 1: Use Browser Profiles&lt;/h4&gt;
&lt;p&gt;Create separate browser profiles for each wallet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Profile 1 → Wallet A permanently connected&lt;/li&gt;
&lt;li&gt;Profile 2 → Wallet B permanently connected&lt;/li&gt;
&lt;li&gt;Profile 3 → Wallet C permanently connected&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No wallet switching needed.&lt;/p&gt;
&lt;h4 id=&quot;tip-2-monitor-all-dashboards&quot;&gt;Tip 2: Monitor All Dashboards&lt;/h4&gt;
&lt;p&gt;Keep all Buy Bot tabs visible (tile windows) to monitor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each wallet's buy count&lt;/li&gt;
&lt;li&gt;SOL remaining per wallet&lt;/li&gt;
&lt;li&gt;Any errors or stops&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;tip-3-pre-calculate-sol-needs&quot;&gt;Tip 3: Pre-Calculate SOL Needs&lt;/h4&gt;
&lt;p&gt;Before campaign:&lt;br&gt;
&lt;code&gt;
Wallet A: 50 buys × 0.15 SOL = 7.5 SOL + fees = ~7.6 SOL
Wallet B: 80 buys × 0.08 SOL = 6.4 SOL + fees = ~6.5 SOL
...
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Fund each wallet with exact amount needed + 10% buffer.&lt;/p&gt;
&lt;h4 id=&quot;tip-4-refill-strategy&quot;&gt;Tip 4: Refill Strategy&lt;/h4&gt;
&lt;p&gt;If running extended campaigns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set alerts when wallets drop below 1 SOL&lt;/li&gt;
&lt;li&gt;Refill from main wallet&lt;/li&gt;
&lt;li&gt;Or pre-fund for full campaign duration&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;common-multi-wallet-mistakes&quot;&gt;Common Multi-Wallet Mistakes&lt;/h3&gt;
&lt;h4 id=&quot;mistake-1-identical-settings&quot;&gt;Mistake 1: Identical Settings&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt; All wallets with same amount and rate&lt;br&gt;
&lt;strong&gt;Why bad:&lt;/strong&gt; Pattern is obviously artificial&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Vary amounts by 20-50% between wallets&lt;/p&gt;
&lt;h4 id=&quot;mistake-2-starting-all-at-once&quot;&gt;Mistake 2: Starting All at Once&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt; Click start on all bots at the same second&lt;br&gt;
&lt;strong&gt;Why bad:&lt;/strong&gt; Synchronized starts look coordinated&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; 30-60 second gaps between starts&lt;/p&gt;
&lt;h4 id=&quot;mistake-3-same-wallet-names-history&quot;&gt;Mistake 3: Same Wallet Names/History&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt; Using wallets that have obvious connections&lt;br&gt;
&lt;strong&gt;Why bad:&lt;/strong&gt; On-chain analysis can link them&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Use fresh wallets or wallets with different histories&lt;/p&gt;
&lt;h4 id=&quot;mistake-4-running-out-of-sol-mid-campaign&quot;&gt;Mistake 4: Running Out of SOL Mid-Campaign&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt; Wallet runs dry, stops buying&lt;br&gt;
&lt;strong&gt;Why bad:&lt;/strong&gt; Sudden stop in activity pattern&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Pre-calculate needs, add 10% buffer&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;multi-wallet-budget-guide&quot;&gt;Multi-Wallet Budget Guide&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Budget &lt;/th&gt;&lt;th&gt;Wallets &lt;/th&gt;&lt;th&gt;Strategy &lt;/th&gt;&lt;th&gt;Expected Impact&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;5-10 SOL &lt;/td&gt;&lt;td&gt;2 &lt;/td&gt;&lt;td&gt;Basic diversity &lt;/td&gt;&lt;td&gt;Moderate&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10-20 SOL &lt;/td&gt;&lt;td&gt;3 &lt;/td&gt;&lt;td&gt;Good diversity &lt;/td&gt;&lt;td&gt;Good&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;20-35 SOL &lt;/td&gt;&lt;td&gt;4-5 &lt;/td&gt;&lt;td&gt;Full simulation &lt;/td&gt;&lt;td&gt;Strong&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;35+ SOL &lt;/td&gt;&lt;td&gt;5-8 &lt;/td&gt;&lt;td&gt;Maximum organic look &lt;/td&gt;&lt;td&gt;Maximum&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;minimum-viable-multi-wallet-2-wallets-8-sol-&quot;&gt;Minimum Viable Multi-Wallet (2 wallets, ~8 SOL)&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Wallet &lt;/th&gt;&lt;th&gt;Amount &lt;/th&gt;&lt;th&gt;Buys &lt;/th&gt;&lt;th&gt;Cost&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;A (main) &lt;/td&gt;&lt;td&gt;0.1 SOL &lt;/td&gt;&lt;td&gt;50 &lt;/td&gt;&lt;td&gt;~5 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;B (support) &lt;/td&gt;&lt;td&gt;0.05 SOL &lt;/td&gt;&lt;td&gt;50 &lt;/td&gt;&lt;td&gt;~2.5 SOL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;100 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;~7.5 SOL&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;quick-start-checklist&quot;&gt;Quick Start Checklist&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;□ Create/prepare 3-5 wallets
□ Calculate SOL needed per wallet
□ Fund each wallet (amount + fees + 10% buffer)
□ Open separate browser tabs for each wallet
□ Connect each wallet to Buy Bot
□ Enter token address on all instances
□ Set DIFFERENT amounts per wallet
□ Set DIFFERENT rates per wallet
□ Stagger start times (30-60 sec apart)
□ Monitor all dashboards
□ Combine with Bump Bot for visibility
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Element &lt;/th&gt;&lt;th&gt;Single Wallet &lt;/th&gt;&lt;th&gt;Multi-Wallet&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Setup &lt;/td&gt;&lt;td&gt;1 bot &lt;/td&gt;&lt;td&gt;3-5 parallel bots&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Appearance &lt;/td&gt;&lt;td&gt;Repetitive &lt;/td&gt;&lt;td&gt;Organic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cost &lt;/td&gt;&lt;td&gt;Lower &lt;/td&gt;&lt;td&gt;2-3x higher&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Effectiveness &lt;/td&gt;&lt;td&gt;Pumps chart &lt;/td&gt;&lt;td&gt;Pumps chart + looks real&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Trader perception &lt;/td&gt;&lt;td&gt;&quot;Botted&quot; &lt;/td&gt;&lt;td&gt;&quot;Real demand&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; Multi-wallet costs more but creates significantly more believable buy pressure. For tokens where organic appearance matters, it's worth the extra setup.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;start-multi-wallet-buy-pressure&quot;&gt;Start Multi-Wallet Buy Pressure&lt;/h3&gt;
&lt;p&gt;Ready to run organic-looking buy pressure?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://jumpbit.io/en/solana/pumpfun-tools/pumpfun-buy-bot&quot;&gt;Launch Buy Bot&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open multiple tabs&lt;/li&gt;
&lt;li&gt;Connect different wallets&lt;/li&gt;
&lt;li&gt;Configure varied settings&lt;/li&gt;
&lt;li&gt;Start with staggered timing&lt;/li&gt;
&lt;li&gt;Monitor all instances&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Create the multi-source buying activity that looks like real market demand.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;related-resources&quot;&gt;Related Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/jumpbit/how-to-create-fomo-on-pumpfun-with-automated-buy-pressure-20b&quot;&gt;How to Create FOMO with Automated Buy Pressure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/jumpbit/pumpfun-buy-bot-strategy-tiny-buys-vs-large-buys-when-to-use-each-510&quot;&gt;Buy Bot Strategy: Tiny Buys vs Large Buys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/jumpbit/how-to-pump-your-pumpfun-chart-with-automated-buys-step-by-step-fh6&quot;&gt;How to Pump Your Chart with Automated Buys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/jumpbit/pumpfun-buy-bot-vs-bump-bot-which-one-moves-your-chart-36ed&quot;&gt;Buy Bot vs Bump Bot: Which Moves Your Chart?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10253/how-to-run-multi-wallet-buy-pressure-on-pump-fun</guid>
<pubDate>Thu, 22 Jan 2026 07:29:53 +0000</pubDate>
</item>
<item>
<title>Securing a Smart Contract Built with Rust for Solana</title>
<link>https://coderlegion.com/1199/securing-a-smart-contract-built-with-rust-for-solana</link>
<description>&lt;p&gt;Smart contracts are the backbone of decentralized applications (dApps) on blockchain platforms like Solana. However, their security is paramount because vulnerabilities in smart contracts can lead to catastrophic financial losses. In this article, we’ll walk you through how to secure a smart contract built with Rust for Solana before minting a new token and deploying it. By following these best practices, you can minimize risks and ensure your project is robust.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Security Matters in Smart Contracts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before diving into the technical details, let’s briefly discuss why securing your smart contract is crucial:&lt;/p&gt;
&lt;p&gt;Immutable Code: Once deployed, smart contracts cannot be easily modified. Any vulnerabilities present at deployment time will persist unless you have a mechanism for upgrades.&lt;/p&gt;
&lt;p&gt;High Stakes: Smart contracts often handle significant amounts of cryptocurrency or tokens. A single exploit can result in millions of dollars in losses.&lt;/p&gt;
&lt;p&gt;Trustless Environment: Users interact with your smart contract without trusting you personally. They rely on the code being secure and bug-free.&lt;/p&gt;
&lt;p&gt;Given these factors, securing your smart contract should be a top priority.&lt;/p&gt;
&lt;p&gt;Step 1: Understand the Basics of Solana Smart Contracts&lt;/p&gt;
&lt;p&gt;Solana smart contracts, also known as &quot;programs,&quot; are typically written in Rust due to its performance and safety features. Before securing your contract, ensure you understand the following:&lt;/p&gt;
&lt;p&gt;Anchor Framework: Anchor is a popular framework for building Solana programs. It simplifies many aspects of development, including account management and error handling.&lt;/p&gt;
&lt;p&gt;Program Derived Addresses (PDAs): PDAs are used to create accounts that are controlled by your program. They play a critical role in ensuring security.&lt;/p&gt;
&lt;p&gt;CPIs (Cross-Program Invocations): Your program may interact with other programs on Solana. Understanding how CPIs work is essential for securing your contract.&lt;/p&gt;
&lt;p&gt;Step 2: Follow Best Practices for Writing Secure Rust Code&lt;/p&gt;
&lt;p&gt;Rust is known for its memory safety and concurrency features, but writing secure code still requires discipline. Here are some best practices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Safe Math Operations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overflow and underflow are common vulnerabilities in smart contracts. Always use safe math libraries or built-in Rust functions to prevent these issues. For example, instead of using + or -, use methods like checked_add() and checked_sub():&lt;/p&gt;
&lt;p&gt;let a = 100;&lt;br&gt;
let b = 200;&lt;/p&gt;
&lt;p&gt;// Safe addition&lt;br&gt;
if let Some(result) = a.checked_add(b) {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Proceed with the operation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;} else {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Handle overflow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Validate Inputs&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Always validate inputs to your smart contract. Malicious users may try to pass invalid data to exploit your program. Use assertions and checks to ensure inputs meet your expectations:&lt;/p&gt;
&lt;p&gt;assert!(amount &amp;gt; 0, &quot;Amount must be greater than zero&quot;);&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Avoid Reentrancy Attacks&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Reentrancy attacks occur when a malicious contract calls back into your contract before the initial call completes. To prevent this, follow the &quot;Checks-Effects-Interactions&quot; pattern:&lt;/p&gt;
&lt;p&gt;Checks: Validate all conditions first.&lt;/p&gt;
&lt;p&gt;Effects: Update the state of your contract.&lt;/p&gt;
&lt;p&gt;Interactions: Interact with external contracts or accounts.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use PDAs Correctly&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PDAs are a powerful feature in Solana, but they must be used correctly to avoid security risks. Ensure that:&lt;/p&gt;
&lt;p&gt;PDAs are derived using a unique seed.&lt;/p&gt;
&lt;p&gt;Only your program can sign for PDAs.&lt;/p&gt;
&lt;p&gt;let (pda, bump_seed) = Pubkey::find_program_address(&amp;amp;[b&quot;my_seed&quot;], &amp;amp;program_id);&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Limit Privileges&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Minimize the privileges of your smart contract. Only allow necessary operations and restrict access to sensitive functions. For example, if only the admin should be able to mint new tokens, ensure that the mint function checks the caller’s authority:&lt;/p&gt;
&lt;p&gt;if *authority.key != admin_pubkey {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return Err(ProgramError::InvalidAccountData);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Step 3: Test Thoroughly&lt;/p&gt;
&lt;p&gt;Testing is a critical part of securing your smart contract. Here are some strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Unit Tests&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Write unit tests for individual functions to ensure they behave as expected. Use the #[test] attribute in Rust to define test cases:&lt;/p&gt;
&lt;h2 id=&quot;-test-&quot;&gt;[test]&lt;/h2&gt;
&lt;p&gt;fn test_safe_addition() {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let a = 100;
let b = 200;
assert_eq!(a.checked_add(b), Some(300));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Integration Tests&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Integration tests simulate real-world scenarios by testing interactions between different parts of your program. Use the Anchor framework’s testing utilities to write integration tests:&lt;/p&gt;
&lt;h2 id=&quot;-tokio-test-&quot;&gt;[tokio::test]&lt;/h2&gt;
&lt;p&gt;async fn test_mint_token() {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let mut context = setup_test_environment().await;
let result = mint_token(&amp;amp;mut context).await;
assert!(result.is_ok());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fuzz Testing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fuzz testing involves feeding random inputs into your program to uncover edge cases. Tools like cargo-fuzz can help you perform fuzz testing on your Rust code.&lt;/p&gt;
&lt;p&gt;Step 4: Conduct a Security Audit&lt;/p&gt;
&lt;p&gt;Even with thorough testing, it’s essential to have your smart contract audited by a third-party security firm. A professional audit can uncover vulnerabilities that you might have missed. During the audit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Provide clear documentation of your code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explain the intended behavior of each function.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Address any issues raised by the auditors.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Step 5: Deploy Safely&lt;/p&gt;
&lt;p&gt;Once your smart contract has been tested and audited, you’re ready to deploy. However, take the following precautions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deploy on Testnet First&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before deploying on the mainnet, test your contract on Solana’s testnet. This allows you to identify any issues in a low-stakes environment.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a Timelock for Upgrades&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If your contract supports upgrades, consider using a timelock mechanism. This ensures that any changes to the contract take effect only after a specified delay, giving users time to react.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Monitor After Deployment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After deploying your contract, monitor its activity closely. Use tools like Solana Explorer or custom dashboards to track transactions and detect anomalies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Securing a smart contract built with Rust for Solana is a multi-step process that involves careful coding, rigorous testing, and professional auditing. By following the best practices outlined in this article, you can significantly reduce the risk of vulnerabilities and ensure that your token minting and deployment go smoothly.&lt;/p&gt;
&lt;p&gt;Remember, security is an ongoing process. Even after deployment, stay vigilant and keep your contract updated to address any emerging threats. With the right approach, you can build a secure and successful project on Solana.&lt;/p&gt;
</description>
<category>Blockchain Sec</category>
<guid isPermaLink="true">https://coderlegion.com/1199/securing-a-smart-contract-built-with-rust-for-solana</guid>
<pubDate>Sat, 22 Feb 2025 03:18:28 +0000</pubDate>
</item>
<item>
<title>Building a Smart Contract in Rust for Solana: Minting and Deploying a New Token</title>
<link>https://coderlegion.com/1165/building-a-smart-contract-in-rust-for-solana-minting-and-deploying-a-new-token</link>
<description>&lt;h2 id=&quot;minting-and-deploying-a-new-token&quot;&gt;Minting and Deploying a New Token&lt;/h2&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Solana is one of the fastest-growing blockchain platforms, renowned for its high throughput and low transaction fees. One of the most exciting features of Solana is its ability to support smart contracts written in Rust, a systems programming language that emphasizes safety, concurrency, and performance. In this article, we will walk you through the process of creating a smart contract in Rust for Solana, minting a new token, and deploying it on the Solana network.&lt;/p&gt;
&lt;p&gt;By the end of this guide, you'll have a fully functional token minted and deployed on Solana's testnet. Let’s get started!&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before diving into the development process, ensure you have the following tools installed:&lt;/p&gt;
&lt;p&gt;Rust: Install Rust by following the instructions on rust-lang.org.&lt;/p&gt;
&lt;p&gt;Solana CLI: Install the Solana Command-Line Interface (CLI) by following the instructions on solana.com.&lt;/p&gt;
&lt;p&gt;Anchor Framework: Anchor is a framework for building Solana programs in Rust. Install it using cargo:&lt;/p&gt;
&lt;p&gt;   cargo install --git &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/project-serum/anchor&quot;&gt;https://github.com/project-serum/anchor&lt;/a&gt; anchor-cli --locked&lt;/p&gt;
&lt;p&gt;Node.js and Yarn: These are required for frontend integration if needed. You can download them from nodejs.org and yarnpkg.com.&lt;/p&gt;
&lt;h2 id=&quot;step-1-setting-up-your-development-environment&quot;&gt;Step 1: Setting Up Your Development Environment&lt;/h2&gt;
&lt;h3 id=&quot;create-a-new-anchor-project&quot;&gt;Create a New Anchor Project&lt;/h3&gt;
&lt;p&gt;To create a new project, use the anchor CLI:&lt;/p&gt;
&lt;p&gt;anchor init my_token_program&lt;br&gt;
cd my_token_program&lt;/p&gt;
&lt;p&gt;This command initializes a new Anchor project with the necessary structure and dependencies.&lt;/p&gt;
&lt;h3 id=&quot;update-the-cargo-toml-file&quot;&gt;Update the Cargo.toml File&lt;/h3&gt;
&lt;p&gt;Navigate to the programs/my_token_program/Cargo.toml file and ensure the dependencies include the Solana Program Library (SPL). The SPL provides utilities for token creation and management.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[dependencies]
anchor-lang = &quot;0.28.0&quot;
anchor-spl = &quot;0.28.0&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-2-writing-the-smart-contract&quot;&gt;Step 2: Writing the Smart Contract&lt;/h2&gt;
&lt;p&gt;The smart contract will define the logic for minting a new token. We'll use the SPL Token program, which is a standard for creating fungible tokens on Solana.&lt;/p&gt;
&lt;h3 id=&quot;define-the-instruction&quot;&gt;Define the Instruction&lt;/h3&gt;
&lt;p&gt;In the programs/my_token_program/src/lib.rs file, define an instruction to mint a new token:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, Token, TokenAccount};

declare_id!(&quot;Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS&quot;);

#[program]
pub mod my_token_program {
    use super::*;

    pub fn mint_token(ctx: Context&amp;lt;MintToken&amp;gt;, amount: u64) -&amp;gt; Result&amp;lt;()&amp;gt; {
        msg!(&quot;Minting {} tokens&quot;, amount);

        // Mint tokens to the associated token account
        token::mint_to(
            CpiContext::new(
                ctx.accounts.token_program.to_account_info(),
                token::MintTo {
                    mint: ctx.accounts.mint.to_account_info(),
                    to: ctx.accounts.destination.to_account_info(),
                    authority: ctx.accounts.authority.to_account_info(),
                },
            ),
            amount,
        )?;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct MintToken&amp;lt;'info&amp;gt; {
    #[account(mut)]
    pub mint: Account&amp;lt;'info, Mint&amp;gt;,
    #[account(mut)]
    pub destination: Account&amp;lt;'info, TokenAccount&amp;gt;,
    /// CHECK: This is the authority of the mint
    pub authority: AccountInfo&amp;lt;'info&amp;gt;,
    pub token_program: Program&amp;lt;'info, Token&amp;gt;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;explanation-of-the-code&quot;&gt;Explanation of the Code&lt;/h3&gt;
&lt;p&gt;Instruction Definition: The mint_token function defines the logic for minting tokens. It takes two parameters: the context (ctx) and the amount of tokens to mint.&lt;/p&gt;
&lt;p&gt;CPI Call: The token::mint_to function is a Cross-Program Invocation (CPI) call to the SPL Token program, which handles the actual minting of tokens.&lt;/p&gt;
&lt;p&gt;Accounts: The MintToken struct specifies the accounts required for the instruction:&lt;/p&gt;
&lt;p&gt;mint: The token mint account.&lt;/p&gt;
&lt;p&gt;destination: The account where the tokens will be minted.&lt;/p&gt;
&lt;p&gt;authority: The authority account that has permission to mint tokens.&lt;/p&gt;
&lt;p&gt;token_program: The SPL Token program.&lt;/p&gt;
&lt;h2 id=&quot;step-3-compiling-the-program&quot;&gt;Step 3: Compiling the Program&lt;/h2&gt;
&lt;p&gt;Compile the program using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;anchor build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command compiles the Rust code into a binary format that can be deployed on the Solana network.&lt;/p&gt;
&lt;h2 id=&quot;step-4-deploying-the-program&quot;&gt;Step 4: Deploying the Program&lt;/h2&gt;
&lt;p&gt;Deploy the compiled program to the Solana testnet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;anchor deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command uploads the program to the Solana testnet and returns the program ID, which is essential for interacting with the program.&lt;/p&gt;
&lt;h2 id=&quot;step-5-minting-a-new-token&quot;&gt;Step 5: Minting a New Token&lt;/h2&gt;
&lt;p&gt;To mint a new token, follow these steps:&lt;/p&gt;
&lt;h3 id=&quot;create-a-mint-account&quot;&gt;Create a Mint Account&lt;/h3&gt;
&lt;p&gt;Use the Solana CLI to create a mint account:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spl-token create-token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command generates a new mint account and outputs the mint address.&lt;/p&gt;
&lt;h3 id=&quot;create-an-associated-token-account&quot;&gt;Create an Associated Token Account&lt;/h3&gt;
&lt;p&gt;Next, create an associated token account for the mint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spl-token create-account &amp;lt;MINT_ADDRESS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace  with the address of the mint account created in the previous step.&lt;/p&gt;
&lt;h3 id=&quot;mint-tokens-using-the-smart-contract&quot;&gt;Mint Tokens Using the Smart Contract&lt;/h3&gt;
&lt;p&gt;Finally, use the anchor CLI or a custom script to invoke the mint_token instruction. Here's an example using the Solana CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana program invoke &amp;lt;PROGRAM_ID&amp;gt; \
--accounts mint=&amp;lt;MINT_ADDRESS&amp;gt; \
destination=&amp;lt;TOKEN_ACCOUNT_ADDRESS&amp;gt; \
authority=&amp;lt;AUTHORITY_KEYPAIR&amp;gt; \
token-program=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \
--args amount=1000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the placeholders with the appropriate values:&lt;/p&gt;
&lt;p&gt;: The ID of your deployed program.&lt;/p&gt;
&lt;p&gt;: The address of the mint account.&lt;/p&gt;
&lt;p&gt;: The address of the associated token account.&lt;/p&gt;
&lt;p&gt;: The keypair of the mint authority.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we walked through the process of creating a smart contract in Rust for Solana, minting a new token, and deploying it on the Solana testnet. By leveraging the power of Rust and the Anchor framework, developers can build efficient and secure smart contracts for decentralized applications.&lt;/p&gt;
&lt;p&gt;Feel free to experiment with additional features, such as transferring tokens, burning tokens, or implementing custom token logic. Happy coding!&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/1165/building-a-smart-contract-in-rust-for-solana-minting-and-deploying-a-new-token</guid>
<pubDate>Thu, 20 Feb 2025 08:49:07 +0000</pubDate>
</item>
</channel>
</rss>