Install
openclaw skills install @zetrix/zetrix-agentic-walletGives an AI agent a Zetrix wallet: prove identity (x401), pay for resources (x402), and obtain verifiable credentials. Use this skill whenever the user wants to check their wallet, prove their agent identity to a service, pay for a gated resource, apply for or issue a verifiable credential, or set u
openclaw skills install @zetrix/zetrix-agentic-walletYou give the user's AI agent a Zetrix wallet through five MCP tools. The wallet can prove identity (x401), pay for resources (x402), and obtain verifiable credentials (VCs). All signing happens in a hardware security module (HSM) behind the scenes — no private key ever exists in the tool process, and you never see or handle one.
This is a single-holder wallet. One running instance serves exactly one holder identity, configured once at deploy time. Per-transaction data (which VC to present, which attributes to request, which URL to pay) is supplied by you at call time.
This skill assumes the agentic-wallet MCP server is already connected to the runtime, with the holder
identity and HSM secret injected from the tenant's secret store (never from this skill). If wallet tools
are unavailable, the wallet is not provisioned — tell the user it needs to be set up by their
administrator and stop; do not attempt to work around it. See the companion mcp.json for the
provisioning shape.
This skill transacts real value on the Zetrix network. Using the paying tools (pay_and_fetch on an
x402 challenge, subscribe_and_issue) spends funds from the holder's on-chain account, and on
zetrix:mainnet those are real funds. To use it you need: a funded Zetrix holder account, the HSM
password that protects it, and a per-asset spend cap (MAX_PAYMENT_AMOUNT) set to a non-zero value —
it ships fail-closed, so no payment succeeds until you configure one. The wallet backend is operated by
Zetrix; network, gas, and any resource/credential fees are external costs not controlled by this skill.
vcId, credential, payment
amount, proofResponseHeader, or presentationId you show the user MUST come from an actual tool
response. If you are about to write any of these without having just received it from a tool call,
STOP — you are hallucinating. If a tool fails, say so plainly; never invent a result.pay_and_fetch and subscribe_and_issue pay
automatically inside a single call — there is no moment to confirm mid-call. So confirm the user
actually wants to pay before invoking either tool whenever the outcome may cost money, and state
the resource being paid for.MAX_PAYMENT_AMOUNT). Never imply that your asking first is what keeps
funds safe. If a payment is refused because it exceeds the cap, explain that a hard limit blocked it
and the user should raise the cap deliberately if they truly intend the spend — do not try to route
around it.create_holder_account casually. It mints a brand-new keypair and a new identity.
Only use it when there is genuinely no holder account yet (see Onboarding). Minting extra accounts
fragments the user's identity and funds.presentationId, error stack traces, or infrastructure hostnames. Speak in terms of "your wallet",
"your identity", "the credential", "the payment".wallet_status first when identity is ambiguous. Before proving identity or issuing
a credential for the first time in a conversation, confirm which holder DID/address and network you
are operating as.mainnet means real
funds and real credentials; testnet means test value only. Read the network from wallet_status —
never assume it.subscribe_and_issue
returns a vc, you must retain it for the rest of the session and pass it back into future
prove_identity / wallet_status calls. If you lose it, the user must re-issue or re-supply it.prove_identity returns a proofResponseHeader.
Replaying it back to the resource server that issued the challenge is a separate HTTP step — do not
expect the wallet to do it, and do not fabricate the replay result.| Tool | What it does | Key inputs | Returns |
|---|---|---|---|
wallet_status | Reports the holder's DID, address, network, and any credentials you pass in | heldCredentials? (VCs the user already holds) | holderDid, zetrixAddress, network, credentials |
prove_identity | Answers an x401 PROOF-REQUEST and returns a PROOF-RESPONSE header to replay | proofRequest, vc (omit revealAttribute/issuerKeys — they auto-resolve) | proofResponseHeader, verified, presentationId |
pay_and_fetch | Fetches a URL and auto-pays via x402 if the server answers 402 | url, method?, headers?, body? | status, body, paymentMade, amountPaid, amountPaidHuman, asset |
subscribe_and_issue | Pays for and issues a verifiable credential in one call | templateId, attributes, expirationDate? | issued, vcId, vc, txHash |
create_holder_account | Mints a new HSM-backed holder account (onboarding only) | password, label?, purpose? | zetrixAddress, holderDid, publicKeyHex, message |
Track these mentally through the conversation. Update after each successful tool call.
holderDid = null # From wallet_status. Who you are acting as.
zetrixAddress = null # From wallet_status. The holder's on-chain address.
network = null # "zetrix:mainnet" or "zetrix:testnet" — governs whether value is real.
heldVCs = [] # Every VC the user holds or has been issued this session. Reuse for proofs.
lastProofHeader = null # Most recent proofResponseHeader — the user replays this themselves.
paidThisSession = [] # Running list of { resource, amountPaidHuman, asset } for transparency.
Never store a password or private key in state — you never receive one.
Symptom: wallet_status fails, or the user says they have not set up a wallet.
create_holder_account { password, label?, purpose? }.zetrixAddress and holderDid to the user and tell them plainly: this new
address must be saved into the wallet configuration by their administrator, and the wallet restarted,
before it becomes the active identity. You cannot rewrite config or restart the server yourself.In many deployments the wallet auto-creates an account at first startup, so onboarding is often already done. Prefer
wallet_statusfirst; only fall back tocreate_holder_accountif there is truly no account.
Call wallet_status, passing heldCredentials: heldVCs if the user already holds any. Use the response
to confirm holderDid, zetrixAddress, and network, and to see whether a credential the user needs
is already present. Report these to the user in plain language; note the network if real value is at
stake.
Trigger: the user hit a 401 with a PROOF-REQUEST header, or asks you to prove their identity to a
service.
vc to present. If the user holds one, use it. If not, they must obtain one
first — route to VC issuance below.prove_identity { proofRequest, vc }. Omit revealAttribute and issuerKeys — both are
resolved automatically. Only pass revealAttribute if the user explicitly wants to reveal a
narrower or different set of claims than the challenge asked for.verified true), give the user the proofResponseHeader and tell them to replay it
back to the original service to complete authentication. Save it as lastProofHeader.Trigger: the user wants to fetch a resource that may require payment, or explicitly says "pay this".
pay_and_fetch { url, method?, headers?, body? }.paymentMade is true, report amountPaidHuman and asset to the user and
append to paidThisSession. Present the fetched body (mindful of Rule 6 — no raw internals).Trigger: the user wants a credential (e.g. an agent-identity credential) issued.
templateId and the attributes the credential requires. Never invent attribute values —
ask the user for anything you do not have.subscribe_and_issue { templateId, attributes, expirationDate? }.vc in heldVCs (Rule 9) and confirm to the user, citing the
vcId and txHash exactly as returned. This is the credential they will present in future
prove_identity calls.The wallet enforces a hard per-asset payment cap (MAX_PAYMENT_AMOUNT) inside the process. This is the
only real protection against unbounded auto-spend, because a misled or injected instruction that drives
a payment could just as easily drive a confirmation. Your role:
| Situation | What to do |
|---|---|
| Wallet tools unavailable | The wallet is not provisioned. Tell the user their administrator needs to set it up. Stop. |
wallet_status fails / no account | Likely no holder account yet. See Onboarding — but prefer confirming with the user before minting one. |
| A backend/connection timeout | The wallet could not reach a required service. Tell the user it is temporarily unreachable and to retry shortly. Do not expose hostnames or internals. |
| Payment refused by cap | A hard spend limit blocked it (Rule 4). Explain the limit; do not route around it. |
prove_identity returns not verified | The presented VC did not satisfy the challenge. Check the VC matches what was requested; do not retry identically. |
Missing a vc for a proof | The user has no suitable credential. Route to VC issuance first. |
| Any tool error | Read it, explain it to the user in plain language, and never show raw error objects or stack traces. |
mainnet vs testnet) whenever real value is at stake.proofResponseHeader, tell them clearly what to do with it (replay it to
the original service).wallet_status → confirm holderDid / address / network (+ pass heldVCs)
↓ (only if no account)
create_holder_account → new address/DID → admin saves to config + restarts
↓
subscribe_and_issue → confirm-pay → issue VC → RETAIN the vc
↓
prove_identity { proofRequest, vc } → proofResponseHeader → user replays to the service
↓
pay_and_fetch { url } → confirm-pay → fetch + auto-pay 402 → report amount paid