New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@aifinpay/wallet

Package Overview
Dependencies
Maintainers
2
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aifinpay/wallet

Derive an AiFinPay agent wallet (Solana + EVM + NEAR + Aptos) with four tiny crypto deps — no viem, no @solana/web3.js, ~4.5 MB. The light way to give an agent a wallet where the full SDK will not install.

latest
Source
npmnpm
Version
1.5.0
Version published
Weekly downloads
382
29.05%
Maintainers
2
Weekly downloads
 
Created
Source

@aifinpay/wallet

Derive an AiFinPay agent wallet — Solana, EVM, NEAR and Aptos addresses from one seed — with four tiny crypto dependencies and nothing else.

npx @aifinpay/wallet new
Generated strong passphrase and saved to ~/.aifinpay/.env

Your agent's addresses — the EVM one is the same on every EVM chain:

  EVM     0x…
  Solana  …

With --plain the first line reads Created ~/.aifinpay/agent.json (mode 600). instead.

Using an unindexed wallet with @aifinpay/mcp or @aifinpay/agent? In the default (standard) mode this package derives the Solana key from a domain-separated hash of the seed and stores that key in agent.json. @aifinpay/mcp and AiFinPayAgent.fromSolanaSecret read only that stored key and derive the EVM key from it, so they use a different EVM address from the one this CLI prints. For an unindexed wallet, use --legacy-solana for matching addresses. Indexed wallets retain the recovery seed and index, so the wallet CLI, MCP and full SDK derive the same addresses regardless of derivation mode.

Why this exists

@aifinpay/agent is the full SDK — it derives keys and signs transactions, so installing it pulls viem and @solana/web3.js: ~142 packages, ~157 MB. In a constrained agent sandbox that install does not merely bloat, it fails.

Making a wallet needs none of that. This package has four dependencies (~4.5 MB) — @noble/curves, @noble/hashes, bs58, tweetnacl — and installs in seconds. For an unindexed wallet, legacy-solana mode derives the same Solana and EVM addresses as @aifinpay/agent's fromSeed; indexed wallets match the full SDK in either mode. The division of labour:

installuse for
@aifinpay/wallet~4.5 MBcreate a wallet, anywhere
@aifinpay/agent / @aifinpay/mcp~157 MBpay — only when you actually settle on-chain

The keystore this writes is ~/.aifinpay/agent.json (or $AIFINPAY_HOME/agent.json), the file @aifinpay/mcp reads. See the note above about which derivation mode MCP can use.

CLI

npx @aifinpay/wallet new                    create an encrypted keystore (refuses to overwrite an existing one)
npx @aifinpay/wallet new --plain            create an unencrypted keystore (not recommended)
npx @aifinpay/wallet new --legacy-solana    derive Solana from the raw seed (the full SDK's and MCP's derivation)
npx @aifinpay/wallet new --index 0         create indexed wallet 0
npx @aifinpay/wallet show                   print the addresses
npx @aifinpay/wallet show --index 1         show child wallet 1 without changing the keystore
npx @aifinpay/wallet export                 print the seed to back up
npx @aifinpay/wallet --help                 usage

A command is required: npx @aifinpay/wallet on its own exits with "command required".

Indexed wallets

Pass the same 32-byte recovery seed with an index to derive deterministic siblings. Index 0 is the first wallet; 1, 2, and so on derive distinct children. Each chain derives from its own versioned domain: for example, EVM = SHA-256("aifinpay:evm:v1\0" || decimalIndex || recoverySeed) and Solana = Ed25519(SHA-256("aifinpay:solana:v1\0" || decimalIndex || recoverySeed)). The index is decimal UTF-8 text immediately after the domain's NUL separator. Indices are integers from 0 through 4294967295. Omitting the index preserves the existing derivation exactly.

import { walletFromSeed } from "@aifinpay/wallet";

const wallet0 = walletFromSeed(recoverySeed, { index: 0 });
const wallet1 = walletFromSeed(recoverySeed, { index: 1 });

The CLI stores the recovery seed, derivation mode, and selected index as optional keystore metadata. show --index N derives another child from that same stored recovery seed without changing the keystore. MCP reads the stored index by default, or AIFINPAY_WALLET_INDEX can select another child from the same seed. Back up both the recovery seed and its index; export prints the seed only.

Encrypted keystore (default). New wallets are encrypted with scrypt-aes-256-gcm.

  • If AIFINPAY_WALLET_PASSPHRASE is set, it is the passphrase. It must be at least 16 characters and contain a lower-case letter, an upper-case letter, a digit and one of !@$.^*_+=-.
  • If it is not set, the CLI generates a passphrase and saves it to ~/.aifinpay/.env and ~/.aifinpay/secrets/passphrase (both mode 600). It does not prompt.
  • show needs AIFINPAY_WALLET_PASSPHRASE in the environment to open an encrypted keystore; the CLI does not read .env itself. @aifinpay/mcp needs the same variable in its env. The seed itself is stored encrypted (seedEnc) — no plaintext key material is written to the keystore.

The bugs from the coverage pass (AiFinPay/sdk#96) are fixed and pinned by tests: the seed is stored only encrypted, export of an encrypted keystore requires the passphrase, generated passphrases always pass validation, and show/export read a keystore written by npx @aifinpay/mcp init. One intentional difference remains: an unindexed default-mode wallet's addresses are not the ones MCP would derive (see the note at the top).

Plain keystore. --plain writes an unencrypted keystore, protected only by file mode 600.

Local development

When working from the source tree (without publishing to npm):

cd wallet/
npm ci
npm run build

node dist/cli.js new
node dist/cli.js show
node dist/cli.js export
node dist/cli.js new --plain

Non-interactive use with your own passphrase:

export AIFINPAY_WALLET_PASSPHRASE='Correct-Horse-Battery-9'   # ≥16 chars, upper, lower, digit, special
node dist/cli.js new
node dist/cli.js show

Library

import { deriveWallet, newWallet, walletFromSeed } from "@aifinpay/wallet";

const w = await newWallet();
w.evmAddress; // 0x… (same on every EVM chain)
w.solanaAddress; // base58
w.nearAddress; // hex Ed25519 public key
w.aptosAddress; // 0x… authentication key
w.keys.seedHex; // 32-byte seed — THE thing to back up
w.keys.evmPrivateKey; // for building your own transactions
w.keys.solanaSecretKeyB58; // tweetnacl 64-byte secret, base58

deriveWallet(w.keys.seedHex); // same seed → same wallet, deterministic

Deprecated Casper compatibility

Casper is no longer supported and is not printed by new or show. DerivationDomain.CASPER, casperAddress, casperPublicKey and keys.casperSecretSeedHex remain available with @deprecated annotations. Their values and derivation are unchanged in both modes, so existing consumers and legacy key recovery continue to work. No keystore migration is required.

Derivation modes

standard (the default) derives the Solana key from SHA-256("aifinpay:solana:v1\0" || seed). legacy-solana derives it from the raw seed for unindexed wallets. Indexed wallets derive each chain key from its own domain, index and recovery seed in either mode, matching @aifinpay/agent and @aifinpay/mcp. EVM, NEAR and Aptos are the same in both modes, as is the deprecated Casper material.

import { newWallet, walletFromSeed } from "@aifinpay/wallet";

// Create a wallet with the full SDK's Solana derivation
const legacyWallet = await newWallet({ mode: "legacy-solana" });

// Or recover from an existing seed in that mode
const recovered = walletFromSeed(seedHex, { mode: "legacy-solana" });

Programmatic CLI usage

import { createWalletCLI } from "@aifinpay/wallet";

// Encrypted keystore with the full SDK's Solana derivation
await createWalletCLI("new", ["node", "wallet", "--legacy-solana"]);

// Unencrypted keystore
await createWalletCLI("new", ["node", "wallet", "--plain"]);

createWalletCLI calls process.exit on its error paths (for example, when a keystore already exists), as the CLI does.

Recovery

The derivation is not BIP-39/BIP-44 — no standard wallet (MetaMask, Phantom) can recover this from a phrase. The 32-byte seed is the backup. Keep ~/.aifinpay/agent.json, or npx @aifinpay/wallet export and store the seed.

What it does not do

Sign or send anything. It returns addresses and raw keys. To pay, use @aifinpay/agent — that is when the heavier install earns its size.

MIT.

Keywords

aifinpay

FAQs

Package last updated on 10 Oct 2026

Related posts