Capital · coordination · constructionCareers

Technical · 10 min · reviewed September 2026

Auditing a wallet SDK before you build the agent that uses it

A per-agent spending cap looks like a policy decision. It is also an integration question: does the SDK the agent’s wallet runs on enforce one at all? The answer is usually no, and finding that out costs a day if you look before you build, and a production incident if you don’t.

The question a wallet SDK rarely answers

An agent that can sign a transaction can, by construction, spend. Most wallet SDKs handle the mechanics of that well — key management, chain abstraction, transaction construction, sometimes a policy engine with a set of denial codes. What the majority leave unanswered is narrower and more important: what stops one agent from spending more than a human actually authorized, on a day nobody happened to be watching? That is not a defect in the SDK. It is a scope boundary, and the distinction matters for what you build next — a workaround bolted onto the SDK, or a real enforcement point in front of it.

A readiness assessment, not a demo

The instinct under a deadline is to build against the SDK’s quickstart and discover the gaps in production, one incident at a time. A readiness assessment inverts the order: read every module the SDK publishes, write down what each one actually does rather than what the docs imply, and compare that list against what the agent you are building actually needs. Run it in a day, dated, before a line of the agent’s own code exists. The output is not a slide — it is a table with a verdict in every row.

  • Read the whole surface, not the modules you expect to needA staking gap, a missing chain, an unimplemented signing method — the modules least related to today’s feature are exactly the ones nobody re-checks later.
  • Write the verdict down, datedAn SDK moves. A finding with no date reads as current a year after it stopped being true, and a team building against it inherits an assumption instead of a fact.
  • Separate “not built yet” from “not planned”The two look identical from outside the vendor’s roadmap and require opposite responses — wait, or build the gap yourself.

Done honestly, this step produces uncomfortable rows. That is the point: a readiness assessment that finds nothing missing was not read closely enough, or the SDK genuinely has no gaps worth building around — and either conclusion is worth having in writing before the commercial conversation, not after.

What bounding a run means for a wallet

Bounding a run — a cost ceiling, a loop detector, failing closed on stale data — is usually discussed for inference spend or task loops. A wallet is the same problem with sharper edges, because the ceiling is real money rather than a compute bill you can dispute after the fact. The bound has to be structural: an allowlist of what an agent may touch (which chains, which assets, which destinations), a cap on any single transaction, a cap on the running total for the day, and a threshold under which nobody needs to be woken up. None of that is a wallet SDK’s job to design for you — it is domain-specific to the organisation running the agent, which is exactly why so few SDKs ship it as a default.

The enforcement point most SDKs leave out

The fix is a policy-checked service sitting between the agent’s proposal and the wallet’s own send call — one place that reads the bound, grades the proposed spend against it, and returns a verdict before a key is ever touched. Kept small, it looks like this:

policy · grading a proposed spendone enforcement point, before any key is touched
function grade(envelope, spend, ledger) {
  if (!envelope.assets.includes(spend.asset)) return deny("ASSET_NOT_PERMITTED");
  if (!envelope.destinations.includes(spend.destination)) return deny("DESTINATION_NOT_PERMITTED");
  if (spend.amount > envelope.perTxMax) return deny("PER_TX_CAP");
  if (ledger.usedToday() + spend.amount > envelope.dailyMax) return deny("DAILY_CAP");
  if (spend.amount <= envelope.autoApproveMax) return allow();
  return escalate(); // a human decides; nothing signs until they do
}

Everything in that function reads state; nothing writes it. Reserving the spend against the daily cap happens only after an ALLOW, and is the caller’s job — which keeps the grading function safe to call speculatively, to preview a verdict in a UI, without a side effect to undo if the human says no. The amounts are integers in base units end to end. A cap compared as a floating-point number degrades silently once the value crosses the point where floating-point arithmetic stops being exact, and it degrades in exactly the direction that makes a cap stop capping.

Verdicts, not booleans

A boolean allowed-or-not throws away the case that matters operationally: inside the policy, but above the ceiling under which nobody needs to be asked. That case is not a denial and it is not a silent approval — it is an escalation threshold crossed, and it needs a named owner and a record, the same as a reconciliation break does. Three verdicts, each with a reason, is the minimum vocabulary that lets a refusal be read by a person and by a log line and mean the same thing in both places.

What survives the SDK’s next release

An SDK will add features, deprecate others, and change its own policy primitives — that is what "not built yet" becoming "built" looks like from outside. The enforcement point above should depend on the SDK at exactly one seam: the call that actually sends. Everything else — the envelope, the ledger, the grading function — is domain logic that outlives any particular vendor’s release notes, and a design that keeps that boundary explicit is the difference between an SDK upgrade being a version bump and it being a rewrite.

Terms used here

Author

Name pending · engineering, agent infrastructure practice. Reviewed by the practice lead.

Cite

MLG Blockchain, “Auditing a wallet SDK before you build the agent that uses it,” 2026. TechArticle, machine-readable. https://mlgblockchain.com/insights/agent-infrastructure/auditing-a-wallet-sdk-before-you-build-on-it

Prints cleanly, with URL and date in the running head.