TRENCHFU
leash.trenchfu.com · NEAR testnet · no mainnet deploy

Leash

An agent wallet that cryptographically cannot overspend.

Not a rule the agent is asked to respect. A key it does not have.

the reading

Locked, measured

Both Leash accounts on NEAR testnet hold no keys, so nothing can upgrade the contract or sign around it.

01

The path of a request

Leash is a NEAR contract that exclusively owns a Solana address and will only sign transfers that pass its policy. Agents call the contract. The contract calls the MPC signer. The agent never holds the key.

agent Leash contractpolicy check v1.signerMPC, 11-of-16 Ed25519for Solana calls passes policy fails: refused, no signature exists the agent supplies parameters (recipient, lamports, recent blockhash); the contract builds the transfer message
02

Why the agent cannot go around it

Under NEAR Chain Signatures the foreign key is derived from (predecessor_account_id, path): the immediate caller and a path string, and nothing else. When the contract calls sign(), the contract is the predecessor, so the derived Solana address belongs to the contract’s account. No other account can be the predecessor for it.

The agent never hands over signable bytes. It supplies parameters, and the contract constructs the Solana transfer itself. The agent cannot express a transfer the policy did not authorise.

The derived key follows the account, not the code. The guarantee requires a locked account: zero full-access keys.

README, “The attack on Leash”
03

The policy object

Per agent account. Fields as defined in contract/src/policy.rs, set by the owner with set_agent_policy.

per_tx_lamportsLargest single transfer, in lamports.
window_lamportsLargest total across the rolling window (WINDOW_MS = 24 h).
allowed_recipientsBase58 recipients this agent may pay. Empty means nobody, never everybody.
expires_at_msSession expiry, ms since epoch. 0 means no expiry and is only reachable by an owner who asks for it explicitly.
enabledSwitch for the agent.
spent_in_windowLamports already spent in the current window (contract state).
window_started_msStart of the current window (contract state).

Refusal variants in the contract:

UnknownAgent          AgentDisabled        ZeroAmount
OverPerTxLimit        OverWindowLimit      RecipientNotAllowed
RecipientMalformed    SessionExpired

SPL tokens have a separate per-mint rule set (set_mint_rule), with its own limits and destinations.

04

Testnet proof

contractleash-b0c503d6.testnet0 access keys, 0 FullAccess (block 277685695, 2026-11-14T17:08:04Z)
build (reproducible)458,248 B · 59HB5memEzCQMXoWe6mD7KX3ysvYMZoVBHPXVyt4tr64sha256 3d8dae96c0eea6ee999c333031ae9b6152174c017830046cf7737a1eae91bf11, derived from the bytes; the RPC code_hash agrees (block 277685695)
locked accountleash-locked-7f0c6d.testnet0 access keys, 0 FullAccess (block 277685695); locked-account proof 15/15
Leash Solana addressGqa8HZcVBJ8oHGbUDCxU1DFVfimNKxF1w3jJY9kx5DULderived from (leash-b0c503d6.testnet, solana-1, domain 1) ยท devnet only: do not send mainnet funds to it
landed transferSolana devnet, finalized in 2 s; payee +1,000,000 lamports exactly
block 277685695NEAR testnet · 2026-11-14T17:08:04Z · agent policy: enabled true, expires_at_ms 1795028954412 (2026-11-18T19:09:14Z); both Leash accounts key-less
block 276060489NEAR testnet · 2026-11-03T14:20Z · MPC committee 11-of-16, epoch 27
block 276052031NEAR testnet · v1.signer-prod.testnet.state · domain 1 = Frost / Ed25519 / Sign
block 222869350NEAR mainnet · v1.signer.state read 2026-11-03 · epoch 14, 11-of-16

Block rows are heights as recorded by the build; the source lists no block hashes, so they are not linked.

05

Use it from anywhere

Leash is the spend rail for TrenchFu's own agents: the same contract is the planned rail wherever a TrenchFu product lets an agent move funds.

An agent is a NEAR account the owner has registered. It calls one method with parameters, never bytes. From the repo harness (harness/land_transfer.py):

near contract call-function as-transaction leash-b0c503d6.testnet request_transfer \
  json-args '{"recipient":"<base58>","lamports":"1000000","recent_blockhash":"<blockhash>"}' \
  prepaid-gas '300.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as <agent-account> network-config testnet

A refusal returns a verdict (LEASH_REFUSED) and is written to a bounded ring: read it with get_recent. Also readable: get_agent_policy, get_totals, list_agents, get_solana_address. SPL tokens: request_spl_transfer.

example pending a standalone examples/ for other harnesses and chains does not exist yet.

06

Status

livePolicy core and Solana message builder: 78 unit tests, mutation-checked. Contract on testnet. Live Ed25519 signature from the MPC, verified. Transfer landed on Solana devnet. Refusals proven against the live contract and recorded on chain. Session expiry. Function-call-key layer.
lockedleash-b0c503d6.testnet and leash-locked-7f0c6d.testnet: both 0 keys, 0 FullAccess as of block 277685695. The lock has happened; the contract can no longer be upgraded.
waitsMainnet: being stood up under the owner account trenchfu.near; this page carries the mainnet reading the moment the contract exists. Repo: github.com/trenchfu/leash, public; ./verify.sh rebuilds the deployed bytes and checks both accounts.
not removedTrust moves, it does not vanish: signatures come from the MPC committee, measured 11-of-16.

Where it grew

Every fact on this page comes from one of these. The repo is public at github.com/trenchfu/leash; each source below links to it. The apex lists the wider record.

  • Contract
    The policy object and its refusals, in contract/src/policy.rs.
    live on testnet
  • The path of a request and the attack on Leash.
    public repo
  • Harness
    The script behind the use example, harness/land_transfer.py.
    live on testnet
  • Design notes kept under docs/.
    public repo
  • The block readings and the open items listed under Status.
    public repo