🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@moneolabs/wallet

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@moneolabs/wallet

An account per AI agent, with keys the model never sees.

Source
npmnpm
Version
0.2.1
Version published
Weekly downloads
175
-46.48%
Maintainers
1
Weekly downloads
 
Created
Source

@moneolabs/wallet

An account per AI agent, with keys the model never sees.

npm install @moneolabs/wallet

Agents leak. They paste their context into logs, into tools, into other models. So this package is built on the assumption that anything the agent can read is already public: the wallet holds a handle to a signer, and the signing happens somewhere the agent cannot reach.

Use

import { createWallet, localSigner, memoryRail } from "@moneolabs/wallet";

const wallet = await createWallet({
  agent: "research-agent-01",
  signer: localSigner(),
  rail: memoryRail(),
  asset: "USD",
  funding: "$500",
});

wallet.address; // "0x4a91...c7d2", safe to log and to share
await wallet.balance(); // $500.00
await wallet.pay({ to: "x402:api.pricefeed.dev/quote", amount: "$0.04" });
await wallet.sweep({ to: "treasury", leave: "$50" });

There is no field anywhere on the wallet that returns key material.

Attach a policy

A wallet with no limits is a liability. Pass a guard and every payment is checked before it is signed.

import { createGuard } from "@moneolabs/guard";

const guard = createGuard({
  perTransaction: { max: "$25" },
  rolling24h: { max: "$100" },
  counterparties: "allowlist-only",
  allow: ["x402:*"],
});

const wallet = await createWallet({ agent: "a", signer, rail, guard, funding: "$500" });

await wallet.pay({ to: "0xstranger", amount: "$5" });
// throws PolicyDeniedError: counterparty 0xstranger is not on the allowlist

Ask first without paying:

const decision = await wallet.preflight({ to: "vendor:acme", amount: "$400" });
decision?.verdict; // "block"
decision?.reason; // "$400.00 exceeds the $25.00 per-transaction limit"

balance() is what the rail holds. available() subtracts anything the guard has reserved but not yet settled, which is usually the number you want before promising to spend.

Custody

Signer is an interface. Two implementations ship:

localSigner(); // real Ed25519, key stays in this process
localSigner({ seed }); // deterministic, for tests
remoteSigner({ address, sign }); // an enclave, an MPC quorum, your own KMS

remoteSigner sends a digest out and gets a signature back. Nothing about the key crosses into your process, so there is nothing in it worth stealing.

const signer = remoteSigner({
  address: "0x4a91...c7d2",
  custody: "tee",
  async sign(digest) {
    const res = await fetch("https://enclave.internal/sign", {
      method: "POST",
      body: JSON.stringify({ digest }),
    });
    return res.json(); // { value, algorithm }
  },
});

Rails

Rail is where value actually moves: a chain, a card processor, an internal ledger. memoryRail is a complete double-entry ledger that happens to live in memory. Balances go down on the sender and up on the receiver, overdrafts are refused, and every transfer gets a reference.

const rail = memoryRail({
  fee: (amount) => scaleMoney(amount, 0.001), // 10 basis points
  balances: { treasury: { USD: money("10000", "USD") } },
});

Implement transfer, balance, and optionally credit to connect a real one. Everything above the interface stays the same.

Agent toolkit

Tool definitions in the shapes model APIs expect, with handlers wired to the wallet.

import { toolkit } from "@moneolabs/wallet";

const tools = toolkit(wallet, { guard });

tools.anthropic; // [{ name, description, input_schema }]
tools.openai; // [{ type: "function", function: { ... } }]
await tools.handle("pay", { to: "x402:api.dev", amount: "$0.04" });

Five tools: get_balance, preflight_payment, pay, get_spending_limits, list_payments. Restrict them with include.

The important detail is what a refusal looks like:

{
  "ok": false,
  "refused": true,
  "reason": "$900.00 exceeds the $25.00 per-transaction limit",
  "rule": "perTransaction",
  "hint": "This limit is set by the wallet owner. Ask them to raise it rather than retrying."
}

A result, not an exception. A model that receives a stack trace retries until the loop gives up. A model that receives this stops and tells the user.

Failure handling

If the rail refuses or the signer fails, the guard reservation is released rather than left stuck. Budgets do not leak from failed payments.

await wallet.pay({ to: "v", amount: "$50" }); // rail throws InsufficientFundsError
(await guard.usage()).budgets[0].used; // $0.00

License

MIT

Keywords

ai-agents

FAQs

Package last updated on 24 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts