On this page
Contract reference
Every method of the vault and factory contracts: who may call it, the deposit it needs, its arguments and return value, the events it emits and the codes it fails with.
The vault and the factory are the two contracts Probarion ships, written in Rust with near-sdk. Every vault runs a recorded build of the code in contracts/vault/src, and the factory in contracts/factory/src/lib.rs creates vaults from a version of that code. A test reads both sources and fails when a method is added or removed, or when its kind, deposit rule, arguments, return type, events or error codes change without its row, so these tables follow the code in the repository.
How to read the tables#
- Kind: a
viewtakes&self. It reads state, changes nothing and runs as a free RPC query, with no transaction and no key. Acalltakes&mut selfand runs in a signed transaction. Aninitruns once, when the contract is deployed. Aprivate callbackis the second half of a cross-contract call, and only the contract itself may call it: near-sdk answers any other caller withMethod <name> is private. - Who may call: the vault checks the caller before the deposit, so a stranger who attaches nothing gets
NotOwnerorNotApprover, notRequiresOneYocto. Vaults, roles and keys explains each role and each key. - Deposit: "Exactly 1 yoctoNEAR" means any other amount, none included, fails with
RequiresOneYocto. Only a full-access key can attach a deposit, which is why most owner calls need one. A call whose deposit reads None is not#[payable], and near-sdk refuses an attached deposit on it withMethod <name> doesn't accept deposit. A view has no such guard. - Arguments are one JSON object with the names shown. A
U128or aU64travels as a decimal string, such as"6000000", and amounts are in the token's base units. A public key is a string such ased25519:.... A paged view takesfrom_index, a position counted from 0, andlimit, and returns at most 100 items. Mandate, spend, anchor and version ids count from 1. - Returns: a
Promiseor aPromiseOrValueresolves when its receipts finish, and the transaction's result is the value of the last one, such as the callback'sSpendResult. Null is JSONnull. - Events emitted names the NEP-297 events a call logs as
EVENT_JSON:lines, the vault's under the standardprobarionand the factory's underprobarion_factory. An event that a private callback logs, such as a payout's last event, comes in a later receipt of the same transaction, and the cell names that callback. A callback that finds the call before it failed can log another event, or none. Events lists each event's fields. - Errors lists the
PROBARION:<Code>panics a caller can meet, in the order the method checks them. Each code has its own anchor on Errors, such as/docs/build/errors#NotAgent. A panic reverts every change the call made. The factory panics with the vault's codes. A few defensive checks cannot fail once the method's own checks have passed, such as those inside a payout and its callbacks, and the tables leave them out.
Vault methods#
Each row is anchored at vault-<method>, such as vault-spend. The rows run in this order: config, owner controls, mandates, keys, spends, holds and anchors.
| Method | Kind | Who may call | Deposit | Arguments | Returns | Events emitted | Errors |
|---|---|---|---|---|---|---|---|
new | init | Once, at deploy. The caller is stored as factory unless it is the vault account itself | None | owner: AccountId, approvers: Vec<AccountId>, usdc: AccountId, intents: AccountId, allowed_assets: Vec<AccountId>, daily_backstop: U128, held_ttl_ns: U64 | None. It stores the vault unfrozen, with no agents, no ledger key and no mandates | None | InvalidInput: no approvers or more than 10, more than 10 allowed assets, a zero daily_backstop, or a held_ttl_ns of 0 or over 30 days |
get_config | view | Anyone | None | None | VaultConfig: owner, approvers, usdc, intents, allowed_assets, daily_backstop, held_ttl_ns, frozen, factory, version, ledger_key | None | None |
freeze | call | The owner, from a full-access key or a function-call key that may call the vault | None | None | None. New spends and approvals are refused until unfreeze | frozen | NotOwner |
unfreeze | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | None | None | unfrozen | NotOwner, RequiresOneYocto |
withdraw | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | amount: U128, in USDC base units | Promise: the USDC ft_transfer to the owner. A failed transfer fails the transaction | withdrawn | NotOwner, RequiresOneYocto, InvalidInput for a zero amount |
withdraw_intents | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | token: AccountId, amount: U128 | Promise: the NEAR Intents ft_withdraw of amount of token from the vault's balance there to the owner's NEAR account | withdrawn | NotOwner, RequiresOneYocto, InvalidInput for a zero amount |
create_mandate | call | The owner, from a full-access key | The mandate's storage, plus 0.00125 NEAR for a NEAR payee's USDC registration. The excess goes back to the caller | input: MandateInput, with payee, purpose_hash, max_per_payment, max_total, max_uses, expires_at_ns, approval_above, agent_pk, label | u64: the new mandate's id, counting from 1 | mandate_created | NotOwner, InvalidInput, AssetNotAllowed, InsufficientDeposit |
revoke_mandate | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | mandate_id: u64 | None. Payouts already sent keep their reservation until their callback | mandate_revoked | NotOwner, RequiresOneYocto, NoMandate, MandateInactive when it is already revoked |
get_mandate | view | Anyone | None | mandate_id: u64 | Option<MandateView>: the input's fields plus id, spent, reserved, uses, status and created_at_ns, or null | None | None |
list_mandates | view | Anyone | None | from_index: u64, limit: u64 | Vec<MandateView>: up to 100 mandates, from position from_index | None | None |
add_agent | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | public_key: PublicKey, allowance: U128, label: String | None. The vault adds the key to itself, allowed to call only spend, with allowance yoctoNEAR of gas | agent_added | NotOwner, RequiresOneYocto, InvalidInput: a zero allowance, a label over 64 bytes, 16 agents already, or a key that is already an agent key or the ledger key |
remove_agent | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | public_key: PublicKey | None. The vault deletes the key from its account | agent_removed | NotOwner, RequiresOneYocto, InvalidInput when the key is not an agent key |
set_ledger_key | call | The owner, from a full-access key | Exactly 1 yoctoNEAR | public_key: PublicKey, allowance: U128 | None. The vault deletes the previous ledger key, then adds this one, allowed to call only anchor | ledger_key_set | NotOwner, RequiresOneYocto, InvalidInput: a zero allowance, or a key that is already an agent key or the ledger key |
list_agents | view | Anyone | None | None | Vec<AgentView>: public_key, label and added_at_ns of every agent key | None | None |
check_spend | view | Anyone. It checks the request as if signer_pk had signed it | None | request: SpendRequest, signer_pk: PublicKey | Verdict: ok, code and would_hold | None | None. A refusal comes back as the bare code in code |
spend | call | An agent key: the vault account signs with a key add_agent added | None | request: SpendRequest, with mandate_id, amount, invoice_hash, ref, decision_hash | PromiseOrValue<SpendResult>: held at once, or the payout, which resolves to paid, burned or failed | spend_held, or spend_submitted and then, from on_transfer or on_withdraw, spend_paid, spend_burned or spend_failed | NotAgent when the call does not come from the vault itself, then the codes of the 14 spend checks |
on_transfer | private callback | The vault itself, after its USDC ft_transfer to a NEAR payee | None | spend_id: u64 | SpendResult: failed when the transfer failed, else paid | spend_paid or spend_failed | None |
on_withdraw | private callback | The vault itself, after its NEAR Intents ft_withdraw to a Base or Solana payee | None | spend_id: u64 | SpendResult: failed when the ft_withdraw failed or returned "0", else burned, whatever else it returned | spend_burned or spend_failed | None |
get_spend | view | Anyone | None | spend_id: u64 | Option<SpendView>: the request's fields plus id, agent_pk, destination, status, created_at_ns, held_until_ns and memo, or null | None | None |
list_spends | view | Anyone | None | from_index: u64, limit: u64 | Vec<SpendView>: up to 100 spends, from position from_index | None | None |
approve | call | An approver, from a full-access key | Exactly 1 yoctoNEAR | spend_id: u64 | PromiseOrValue<SpendResult>: always the payout, which resolves to paid, burned or failed | spend_approved, spend_submitted, and then, from on_transfer or on_withdraw, spend_paid, spend_burned or spend_failed | NotApprover, RequiresOneYocto, Frozen, NotHeld, HoldExpired, MandateInactive |
reject | call | An approver, from a full-access key | Exactly 1 yoctoNEAR | spend_id: u64 | None. It releases the reservation, the use and the invoice hash. The ref stays used | spend_rejected | NotApprover, RequiresOneYocto, NotHeld |
expire_held | call | Anyone, once the spend's held_until_ns has passed | None | spend_id: u64 | None. It releases the spend as reject does, and the spend then reads expired | spend_expired | NotHeld, HoldNotExpired |
anchor | call | The ledger key: the vault account signs with the key set_ledger_key added | None | seq: u64, root: String, count: u64 | None. It stores the anchor with its signing key and the block time | ledger_anchored | NotLedgerKey, BadSeq unless seq is one above the last, InvalidInput: a root that is not 64 lowercase hex characters, or a count of 0 or below the last one |
list_anchors | view | Anyone | None | from_index: u64, limit: u64 | Vec<AnchorView>: seq, root, count, at_ns and ledger_key of up to 100 anchors | None | None |
The 14 checks behind spend and check_spend are listed in the order they run on How a payment is checked, and Holds and approvals follows a held spend to its end.
spend and anchor are signed with the vault's own function-call keys, the agent key and the ledger key. Neither key may call any other method or attach a deposit.
Owner signs
The owner signs create_mandate, revoke_mandate, add_agent, remove_agent, set_ledger_key, freeze, unfreeze, withdraw and withdraw_intents from their own wallet. Each one needs a full-access key except freeze, which takes no deposit so that the owner can stop the vault fast.
Approver signs
An approver signs approve or reject from their own wallet, with exactly 1 yoctoNEAR attached. One approver is enough, and the owner's signature counts only when the owner is on the approver list.
Factory methods#
The factory creates each vault as <name>.<factory>, such as acme.vaults.probarion.testnet, with no access keys, from its current version. No factory method calls a vault after create_vault, so the factory cannot change, upgrade or take funds from a vault it created. Each row is anchored at factory-<method>, such as factory-create_vault.
| Method | Kind | Who may call | Deposit | Arguments | Returns | Events emitted | Errors |
|---|---|---|---|---|---|---|---|
new | init | Once, at the factory's deploy | None | owner: AccountId, usdc: AccountId, intents: AccountId, allowed_assets: Vec<AccountId>, min_deposit: U128 | None. It stores the factory with no versions and no vaults | None | InvalidInput for more than 10 allowed assets |
get_config | view | Anyone | None | None | FactoryConfig: owner, usdc, intents, allowed_assets, min_deposit, and current_version, null before the first version | None | None |
create_vault | call | Anyone. The caller becomes the new vault's owner | At least min_deposit, plus the code's storage for an embedded version. All of it goes to the new vault | name: String, approvers: Vec<AccountId>, daily_backstop: U128, held_ttl_ns: U64 | Promise: it resolves to the new vault's account id, <name>.<factory>, or to null when the batch failed, such as for a taken name | vault_created, from on_vault_created, only when the batch succeeded | InvalidInput: a name outside ^[a-z0-9][a-z0-9_-]{1,30}$ or not a valid account id, init values the vault's new refuses, or no version yet. Then InsufficientDeposit |
on_vault_created | private callback | The factory itself, after the create_vault batch | None | name: String, owner: AccountId, deposit: U128, version: u32 | Option<AccountId>: the vault's account id, or null after a failed batch, when it sends deposit back to owner | vault_created | None |
list_vaults | view | Anyone | None | from_index: u64, limit: u64 | Vec<VaultRecord>: account_id, owner, version and created_at_ns of up to 100 vaults | None | None |
vault_version | view | Anyone | None | account_id: AccountId | Option<u32>: the version the factory created that vault from, or null for an account it did not create | None | None |
versions | view | Anyone | None | None | Vec<VersionView>: index, code_hash, mode, notes and at_ns of every version. The last one is current | None | None |
store_code | call | The factory owner, from a full-access key | Exactly 1 yoctoNEAR | None. The call's raw input is the wasm | String: the code's base58 sha256, which is its NEAR code hash | None | NotOwner, RequiresOneYocto, InvalidInput for an empty input |
add_version | call | The factory owner, from a full-access key | Exactly 1 yoctoNEAR | code_hash: String, mode: String, notes: String | u32: the new version's index, counting from 1. It becomes the current version | version_added | NotOwner, RequiresOneYocto, InvalidInput: notes over 256 bytes, a hash that is not 32 bytes in base58, a mode other than global or embedded, or embedded code that was never stored |
publish_global | call | The factory owner, from a full-access key | Exactly 1 yoctoNEAR | None | Promise: it deploys the current version's stored wasm as a global contract, paid from the factory's balance | None | NotOwner, RequiresOneYocto, InvalidInput unless the current version is embedded and its code is stored |
Owner signs
The account that calls create_vault becomes the new vault's owner and pays its deposit from its own wallet. The approvers are named in the same call, and no vault method changes them later.
A version's mode trades each vault's deposit against the factory's own cost. An embedded version gives every new vault its own copy of the wasm, so every vault pays for the storage of that copy. A global version points every new vault at one global contract by its code hash, so the factory pays once, when the code is published. A version's life runs store_code, then add_version in embedded mode, and, to go global, publish_global and an add_version in global mode with the same hash. A version applies only to the vaults created after it: a vault keeps the code it was created with.
Read a contract#
The views need no account and no key. With near-cli-rs:
near contract call-function as-read-only vaults.probarion.testnet get_config json-args '{}' network-config testnet now
near contract call-function as-read-only vaults.probarion.testnet versions json-args '{}' network-config testnet now
near contract call-function as-read-only v0.probarion.testnet list_mandates json-args '{"from_index":0,"limit":100}' network-config testnet nowDeployed on testnet#
contracts/deployments/testnet.json records these accounts:
vaults.probarion.testnetis the factory. Its owner isprobarion-owner.testnet, itsmin_depositis 0.5 NEAR, and it creates vaults named<name>.vaults.probarion.testnet. The record lists only embedded versions: there is no global version on testnet.v0.probarion.testnetis the first vault. Its deploy script rannewas the vault account itself, so itsget_configshowsfactoryas null.usdc.probarion.testnetis the test USDC token.base-usdc.probarion.testnetandsol-usdc.probarion.testnetstand in for the Base and Solana assets insideintents-stub.probarion.testnet, the stand-in for NEAR Intents. All of them are subaccounts ofprobarion.testnet, and Testnet and mainnet explains the stand-ins.
No method returns the code hash of its own account: NEAR reports that with the account. To see which code a factory vault was made from, read its version with vault_version, then that version's code_hash in versions. Reproducible builds lists the commit and the code hash of each recorded build of the vault and the factory, from contracts/code-hashes.json, and check f of the verifier compares a vault's code hash with the recorded vault builds and, for a vault whose factory is its network's factory, with that factory's versions. v0.probarion.testnet and the vaults made from the factory's version 1 run two different recorded builds, while the tables on this page describe the source in the repository.
On mainnet, contracts/deployments/mainnet.json records v0.probarion.near, deployed and locked on 2026-11-11, with code hash 3cQXYDvfGLRMveCVAHmh1exiuZKDXWqD8cUhqdEs9MF1. Its owner is probarion.near. Its deploy ran new as the vault account itself, so its get_config shows factory as null. The record also names vaults.probarion.near, the mainnet factory, and records no deploy of it: the factory is not deployed.
What the tables leave out#
- Gas and the contracts' limits: Limits and costs.
- Each event's fields: Events.
- What each code means and what to do next: Errors.
- The CLI commands that print these calls for a wallet to sign: CLI reference.
- The workspace's other contracts,
test-ftandintents-stub: testnet stand-ins for the USDC token and for NEAR Intents, deployed as the accounts above. Testnet and mainnet explains them. - The calls the vault makes to other contracts:
ft_transferandstorage_depositon the USDC token, andft_withdrawon NEAR Intents. Those contracts define them. - The JSON shape of a mandate and of a spend request: Mandates shows every mandate field, and How a payment is checked shows what an agent can ask for.
Related pages#
- Vaults, roles and keys: who holds which key, and why
freezeis the one owner call with no deposit. - Holds and approvals:
approve,rejectandexpire_heldin use. - The ledger and anchors: what
anchorpins on chain. - Verify a vault yourself: the verifier reads these views.
- The sources:
contracts/vault/src(opens in a new tab),contracts/factory/src/lib.rs(opens in a new tab) andcontracts/deployments/testnet.json(opens in a new tab).
Built from 4ab41ca · reviewed
contracts/vault/src/lib.rs(opens in a new tab)contracts/vault/src/admin.rs(opens in a new tab)contracts/vault/src/anchors.rs(opens in a new tab)contracts/vault/src/held.rs(opens in a new tab)contracts/vault/src/keys.rs(opens in a new tab)contracts/vault/src/mandates.rs(opens in a new tab)contracts/vault/src/spend.rs(opens in a new tab)contracts/vault/src/checks.rs(opens in a new tab)contracts/vault/src/types.rs(opens in a new tab)contracts/vault/src/ext.rs(opens in a new tab)contracts/vault/src/errors.rs(opens in a new tab)contracts/vault/src/events.rs(opens in a new tab)contracts/vault/src/validate.rs(opens in a new tab)contracts/factory/src/lib.rs(opens in a new tab)contracts/Cargo.toml(opens in a new tab)contracts/code-hashes.json(opens in a new tab)contracts/deployments/testnet.json(opens in a new tab)contracts/deployments/mainnet.json(opens in a new tab)scripts/testnet/deploy.sh(opens in a new tab)packages/core/src/verify.ts(opens in a new tab)packages/core/src/code-hashes.ts(opens in a new tab)apps/web/src/lib/docs/verifier.ts(opens in a new tab)apps/web/content/docs/build/errors.mdx(opens in a new tab)apps/web/content/docs/concepts/payment-checks.mdx(opens in a new tab)apps/web/content/docs/concepts/vaults-roles-and-keys.mdx(opens in a new tab)docs/evidence/mainnet-v0/README.md(opens in a new tab)