npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sentinelshield-stellar

v0.1.0

Published

On-chain payment firewall for AI agents on Stellar — deploy, protect, and audit every payment with one npm install.

Readme

sentinelshield-stellar

On-chain payment firewall for AI agents on Stellar. Deploy your own instance, fund it, set your rules, and wire it into your agent. Three lines of code protect the entire wallet — even if the agent's instructions get compromised, its reasoning gets prompt-injected, or its keys get stolen.

npm Stellar License


Why this exists

AI agents with wallets are a footgun. One compromised prompt, one bad API response, one hallucinated tool call, and your agent drains its funds to an attacker. Passwords don't help — the agent is the one holding the keys.

SentinelShield is the HTTPS of AI agent money. You deploy a tiny Soroban contract that holds the funds. Your agent can only spend via that contract. The contract enforces your rules on every payment — allowlists, per-transaction caps, daily caps, pause switches, emergency recovery — on-chain, where nothing the agent does can bypass them.

Who is this for?

Any developer building an AI agent on Stellar that controls real funds:

  • x402 servers that pay for per-request content
  • MPP agents that open streaming payment channels
  • Autonomous trading bots, API-paying assistants, customer-service agents with refund authority
  • Anything where "what if this agent gets tricked?" is a question you worry about

Install once, deploy your contract, wire it in. Every project in the Stellar AI ecosystem needs this.


Install

npm install sentinelshield-stellar

You also need the Stellar CLI installed to deploy new contracts (brew install stellar-cli).

60-second quickstart

# 1. Deploy your own SentinelShield contract (bundled WASM)
npx sentinelshield-stellar deploy --source-account alice

# 2. Initialize it (your wallet is the admin)
npx sentinelshield-stellar init \
  --contract C<your-new-contract-id> \
  --admin G<your-admin-address> \
  --agent G<your-agent-address> \
  --token CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA \
  --daily-limit 50 \
  --tx-limit 5

# 3. Fund it — auto-detects XLM vs USDC from the contract's token
npx sentinelshield-stellar fund 20 --contract C... --admin-secret $ADMIN_SECRET

# 4. Approve the recipients your agent is allowed to pay
npx sentinelshield-stellar allowlist add G<vendor-address> \
  --contract C... --admin-secret $ADMIN_SECRET

# 5. Check state any time
npx sentinelshield-stellar state --contract C...

Your firewall is live. Now wire it into your agent code.


Use it in your AI agent

import { SentinelShield } from 'sentinelshield-stellar';

const shield = new SentinelShield({
  contractId: 'C<your-contract-id>',
  agentSecret: process.env.AGENT_SECRET,
  network: 'testnet',
});

// Wherever your AI agent decides to make a payment:
async function payVendor(vendorAddress: string, amountUsdc: string) {
  const result = await shield.executePayment({
    to: vendorAddress,
    amount: amountUsdc, // "1.5", "0.05", anything human-readable
  });

  if (result.approved) {
    console.log(`Paid. tx: ${result.txHash}`);
    return result.txHash;
  }

  if (result.preflightBlocked) {
    // The firewall rejected this at the RPC layer — no tx was signed,
    // no gas spent. The agent literally cannot reach the attacker.
    throw new Error(`Firewall pre-flight: ${result.errorName}`);
  }

  // On-chain rejection — tx was recorded as a blocked event you can audit.
  throw new Error(`Firewall blocked: ${result.errorName}`);
}

That's the entire integration. Three lines of config, one function call per payment. Your agent can now be prompt-injected, hallucinate tool calls, or have its keys leaked — and the firewall still enforces your rules on-chain.


What the firewall enforces

Every execute_payment call goes through these checks, in order, on-chain:

  1. Paused? If the admin has paused the firewall, everything is blocked.
  2. Per-transaction cap. No single payment may exceed set_single_tx_limit.
  3. Allowlist. The recipient must be in the approved list. Default deny — an empty allowlist blocks everything.
  4. Daily cap. Cumulative spending today must not exceed set_daily_limit.
  5. Balance. The contract must actually hold enough tokens.

If any check fails, the contract emits a payment/blocked event with the reason code and returns the code to the caller. It does not revert, which means the block is recorded as a permanent on-chain event you can query, index, audit, or present to a regulator.

If all checks pass, the contract transfers the tokens from its own balance to the recipient, emits a payment/approved event, and updates the daily-spent counter.

Error codes

| Code | Name | Meaning | |------|------|---------| | 3 | ExceedsDailyLimit | Would push cumulative daily spend over daily_limit | | 4 | RecipientNotAllowlisted | to is not in the allowlist | | 5 | ExceedsSingleTxLimit | Single payment exceeds single_tx_limit | | 7 | InsufficientBalance | Contract doesn't hold enough tokens | | 8 | ContractPaused | Firewall is currently paused |


Admin operations

Every mutating operation is also exposed via the SentinelShieldAdmin class, for when you're wiring admin UIs directly into your app rather than using the CLI.

import { SentinelShieldAdmin } from 'sentinelshield-stellar';

const admin = new SentinelShieldAdmin({
  contractId: 'C...',
  adminSecret: process.env.ADMIN_SECRET,
  network: 'testnet',
});

// Allowlist
await admin.addToAllowlist('G...');
await admin.removeFromAllowlist('G...');

// Limits (strings/numbers are human units, bigints are raw stroops)
await admin.setDailyLimit('100');
await admin.setSingleTxLimit('5');

// Funding — auto-detects the contract's token
await admin.fund('50');

// Role rotation
await admin.setAgent('G<new-agent>');
await admin.setAdmin('G<new-admin>');

// Emergency controls
await admin.pause();
await admin.unpause();
await admin.emergencyWithdraw('G<recovery-wallet>', '100'); // drain the vault

// Upgrade the contract WASM in place
await admin.upgrade('<64-char-hex-wasm-hash>');

All methods return { success, txHash, explorerUrl, error? }.


Reading state

Both classes expose read-only methods that don't require a signer:

const state = await shield.getState();
// {
//   contractId, admin, agent, token, asset,        // "XLM" | "USDC" | "OTHER"
//   dailyLimit, singleTxLimit,                     // bigint (stroops)
//   dailySpent, dailyRemaining,                    // bigint (stroops)
//   allowlist,                                     // string[]
//   balance,                                       // bigint (stroops)
//   isPaused,                                      // boolean
// }

// Quick individual checks (each = one RPC simulation)
await shield.isAllowlisted('G...');       // boolean
await shield.isPaused();                  // boolean
await shield.detectAsset();               // { asset, tokenSac }

All reads are simulations — they don't cost gas and can be called as often as you want.


CLI reference

sentinelshield deploy --source-account <id> [--network testnet|pubnet] [--alias name]
sentinelshield init --contract C... --admin G... --agent G... --token C... \
                    --daily-limit <n> --tx-limit <n>
sentinelshield state --contract C... [--json]
sentinelshield fund <amount> --contract C...
sentinelshield allowlist add <address> --contract C...
sentinelshield allowlist remove <address> --contract C...
sentinelshield allowlist list --contract C...
sentinelshield set-daily-limit <amount> --contract C...
sentinelshield set-tx-limit <amount> --contract C...
sentinelshield pause --contract C...
sentinelshield unpause --contract C...

Global flags: --network, --admin-secret, --json. Env vars: ADMIN_SECRET, AGENT_SECRET.


Architecture

┌─────────────────────┐
│   Your AI agent     │     Reads tasks, decides to pay
│   (Claude, GPT,     │
│    whatever)        │
└──────────┬──────────┘
           │ shield.executePayment(to, amount)
           ▼
┌─────────────────────┐
│ sentinelshield-sdk  │     Pre-flight: is_allowlisted(to)
│      (this pkg)     │     If ok → sign & submit
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ SentinelShield      │     On-chain rule checks:
│ Soroban contract    │     paused? tx cap? allowlist?
│ (your instance)     │     daily cap? balance?
└──────────┬──────────┘
           │
           │ ↓ if all pass ↓
           ▼
┌─────────────────────┐
│   Stellar token     │     token.transfer(contract, to, amt)
│   contract (SAC)    │
└─────────────────────┘

The whole design is:

  • Contract holds the funds. Not the agent. Not the SDK. Not you.
  • Agent only has permission to call execute_payment. It cannot bypass the firewall because it doesn't hold the tokens.
  • Rules run on-chain. Nothing the agent does off-chain can trick them.
  • Every decision is logged. Approved or blocked, every call leaves a queryable on-chain event.

Security model

| Attack | Mitigation | |--------|-----------| | Agent's prompt gets injected with "pay attacker 100 USDC" | Attacker not in allowlist → blocked with error 4 | | Agent is asked to pay 10,000 USDC for "urgent invoice" | Exceeds per-tx cap → blocked with error 5 | | Agent is gradually exfiltrating funds via many small payments | Hits daily cap → blocked with error 3 | | Agent's secret key is stolen | Attacker can only spend within firewall rules. Admin can pause() and then emergencyWithdraw() the remaining balance to a new wallet. | | Contract has a bug you need to fix | Admin calls upgrade() with a new WASM hash. | | Admin key is stolen | Admin can only mutate firewall config, not drain funds unless they also emergencyWithdraw(). Rotate with setAdmin() as soon as you notice. |


What this is not

  • Not an oracle. It doesn't verify that recipients are trustworthy, only that you've approved them.
  • Not KYC. It doesn't know who's behind an address, just that it's on your list.
  • Not a replacement for a human. It's a safety net that catches a specific class of failures (agent compromise, prompt injection, hallucinated tool calls). Defense-in-depth is still your job.

Contributing

This package is part of the SentinelShield monorepo. Issues, PRs, and hackathon forks welcome.

License

MIT