Skip to content
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.

LiveTestnetReferenceFor Developers, Builders14 min read.md (this page as Markdown)

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 view takes &self. It reads state, changes nothing and runs as a free RPC query, with no transaction and no key. A call takes &mut self and runs in a signed transaction. An init runs once, when the contract is deployed. A private callback is the second half of a cross-contract call, and only the contract itself may call it: near-sdk answers any other caller with Method <name> is private.
  • Who may call: the vault checks the caller before the deposit, so a stranger who attaches nothing gets NotOwner or NotApprover, not RequiresOneYocto. 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 with Method <name> doesn't accept deposit. A view has no such guard.
  • Arguments are one JSON object with the names shown. A U128 or a U64 travels as a decimal string, such as "6000000", and amounts are in the token's base units. A public key is a string such as ed25519:.... A paged view takes from_index, a position counted from 0, and limit, and returns at most 100 items. Mandate, spend, anchor and version ids count from 1.
  • Returns: a Promise or a PromiseOrValue resolves when its receipts finish, and the transaction's result is the value of the last one, such as the callback's SpendResult. Null is JSON null.
  • Events emitted names the NEP-297 events a call logs as EVENT_JSON: lines, the vault's under the standard probarion and the factory's under probarion_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.

MethodKindWho may callDepositArgumentsReturnsEvents emittedErrors
newinitOnce, at deploy. The caller is stored as factory unless it is the vault account itselfNoneowner: AccountId, approvers: Vec<AccountId>, usdc: AccountId, intents: AccountId, allowed_assets: Vec<AccountId>, daily_backstop: U128, held_ttl_ns: U64None. It stores the vault unfrozen, with no agents, no ledger key and no mandatesNoneInvalidInput: 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_configviewAnyoneNoneNoneVaultConfig: owner, approvers, usdc, intents, allowed_assets, daily_backstop, held_ttl_ns, frozen, factory, version, ledger_keyNoneNone
freezecallThe owner, from a full-access key or a function-call key that may call the vaultNoneNoneNone. New spends and approvals are refused until unfreezefrozenNotOwner
unfreezecallThe owner, from a full-access keyExactly 1 yoctoNEARNoneNoneunfrozenNotOwner, RequiresOneYocto
withdrawcallThe owner, from a full-access keyExactly 1 yoctoNEARamount: U128, in USDC base unitsPromise: the USDC ft_transfer to the owner. A failed transfer fails the transactionwithdrawnNotOwner, RequiresOneYocto, InvalidInput for a zero amount
withdraw_intentscallThe owner, from a full-access keyExactly 1 yoctoNEARtoken: AccountId, amount: U128Promise: the NEAR Intents ft_withdraw of amount of token from the vault's balance there to the owner's NEAR accountwithdrawnNotOwner, RequiresOneYocto, InvalidInput for a zero amount
create_mandatecallThe owner, from a full-access keyThe mandate's storage, plus 0.00125 NEAR for a NEAR payee's USDC registration. The excess goes back to the callerinput: MandateInput, with payee, purpose_hash, max_per_payment, max_total, max_uses, expires_at_ns, approval_above, agent_pk, labelu64: the new mandate's id, counting from 1mandate_createdNotOwner, InvalidInput, AssetNotAllowed, InsufficientDeposit
revoke_mandatecallThe owner, from a full-access keyExactly 1 yoctoNEARmandate_id: u64None. Payouts already sent keep their reservation until their callbackmandate_revokedNotOwner, RequiresOneYocto, NoMandate, MandateInactive when it is already revoked
get_mandateviewAnyoneNonemandate_id: u64Option<MandateView>: the input's fields plus id, spent, reserved, uses, status and created_at_ns, or nullNoneNone
list_mandatesviewAnyoneNonefrom_index: u64, limit: u64Vec<MandateView>: up to 100 mandates, from position from_indexNoneNone
add_agentcallThe owner, from a full-access keyExactly 1 yoctoNEARpublic_key: PublicKey, allowance: U128, label: StringNone. The vault adds the key to itself, allowed to call only spend, with allowance yoctoNEAR of gasagent_addedNotOwner, 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_agentcallThe owner, from a full-access keyExactly 1 yoctoNEARpublic_key: PublicKeyNone. The vault deletes the key from its accountagent_removedNotOwner, RequiresOneYocto, InvalidInput when the key is not an agent key
set_ledger_keycallThe owner, from a full-access keyExactly 1 yoctoNEARpublic_key: PublicKey, allowance: U128None. The vault deletes the previous ledger key, then adds this one, allowed to call only anchorledger_key_setNotOwner, RequiresOneYocto, InvalidInput: a zero allowance, or a key that is already an agent key or the ledger key
list_agentsviewAnyoneNoneNoneVec<AgentView>: public_key, label and added_at_ns of every agent keyNoneNone
check_spendviewAnyone. It checks the request as if signer_pk had signed itNonerequest: SpendRequest, signer_pk: PublicKeyVerdict: ok, code and would_holdNoneNone. A refusal comes back as the bare code in code
spendcallAn agent key: the vault account signs with a key add_agent addedNonerequest: SpendRequest, with mandate_id, amount, invoice_hash, ref, decision_hashPromiseOrValue<SpendResult>: held at once, or the payout, which resolves to paid, burned or failedspend_held, or spend_submitted and then, from on_transfer or on_withdraw, spend_paid, spend_burned or spend_failedNotAgent when the call does not come from the vault itself, then the codes of the 14 spend checks
on_transferprivate callbackThe vault itself, after its USDC ft_transfer to a NEAR payeeNonespend_id: u64SpendResult: failed when the transfer failed, else paidspend_paid or spend_failedNone
on_withdrawprivate callbackThe vault itself, after its NEAR Intents ft_withdraw to a Base or Solana payeeNonespend_id: u64SpendResult: failed when the ft_withdraw failed or returned "0", else burned, whatever else it returnedspend_burned or spend_failedNone
get_spendviewAnyoneNonespend_id: u64Option<SpendView>: the request's fields plus id, agent_pk, destination, status, created_at_ns, held_until_ns and memo, or nullNoneNone
list_spendsviewAnyoneNonefrom_index: u64, limit: u64Vec<SpendView>: up to 100 spends, from position from_indexNoneNone
approvecallAn approver, from a full-access keyExactly 1 yoctoNEARspend_id: u64PromiseOrValue<SpendResult>: always the payout, which resolves to paid, burned or failedspend_approved, spend_submitted, and then, from on_transfer or on_withdraw, spend_paid, spend_burned or spend_failedNotApprover, RequiresOneYocto, Frozen, NotHeld, HoldExpired, MandateInactive
rejectcallAn approver, from a full-access keyExactly 1 yoctoNEARspend_id: u64None. It releases the reservation, the use and the invoice hash. The ref stays usedspend_rejectedNotApprover, RequiresOneYocto, NotHeld
expire_heldcallAnyone, once the spend's held_until_ns has passedNonespend_id: u64None. It releases the spend as reject does, and the spend then reads expiredspend_expiredNotHeld, HoldNotExpired
anchorcallThe ledger key: the vault account signs with the key set_ledger_key addedNoneseq: u64, root: String, count: u64None. It stores the anchor with its signing key and the block timeledger_anchoredNotLedgerKey, 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_anchorsviewAnyoneNonefrom_index: u64, limit: u64Vec<AnchorView>: seq, root, count, at_ns and ledger_key of up to 100 anchorsNoneNone

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.

The owner signs this transaction. Probarion never signs it.

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.

An approver signs this transaction. Probarion never signs it.

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.

MethodKindWho may callDepositArgumentsReturnsEvents emittedErrors
newinitOnce, at the factory's deployNoneowner: AccountId, usdc: AccountId, intents: AccountId, allowed_assets: Vec<AccountId>, min_deposit: U128None. It stores the factory with no versions and no vaultsNoneInvalidInput for more than 10 allowed assets
get_configviewAnyoneNoneNoneFactoryConfig: owner, usdc, intents, allowed_assets, min_deposit, and current_version, null before the first versionNoneNone
create_vaultcallAnyone. The caller becomes the new vault's ownerAt least min_deposit, plus the code's storage for an embedded version. All of it goes to the new vaultname: String, approvers: Vec<AccountId>, daily_backstop: U128, held_ttl_ns: U64Promise: it resolves to the new vault's account id, <name>.<factory>, or to null when the batch failed, such as for a taken namevault_created, from on_vault_created, only when the batch succeededInvalidInput: 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_createdprivate callbackThe factory itself, after the create_vault batchNonename: String, owner: AccountId, deposit: U128, version: u32Option<AccountId>: the vault's account id, or null after a failed batch, when it sends deposit back to ownervault_createdNone
list_vaultsviewAnyoneNonefrom_index: u64, limit: u64Vec<VaultRecord>: account_id, owner, version and created_at_ns of up to 100 vaultsNoneNone
vault_versionviewAnyoneNoneaccount_id: AccountIdOption<u32>: the version the factory created that vault from, or null for an account it did not createNoneNone
versionsviewAnyoneNoneNoneVec<VersionView>: index, code_hash, mode, notes and at_ns of every version. The last one is currentNoneNone
store_codecallThe factory owner, from a full-access keyExactly 1 yoctoNEARNone. The call's raw input is the wasmString: the code's base58 sha256, which is its NEAR code hashNoneNotOwner, RequiresOneYocto, InvalidInput for an empty input
add_versioncallThe factory owner, from a full-access keyExactly 1 yoctoNEARcode_hash: String, mode: String, notes: Stringu32: the new version's index, counting from 1. It becomes the current versionversion_addedNotOwner, 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_globalcallThe factory owner, from a full-access keyExactly 1 yoctoNEARNonePromise: it deploys the current version's stored wasm as a global contract, paid from the factory's balanceNoneNotOwner, 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.

The owner signs this transaction. Probarion never signs it.

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:

Shell
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 now

Deployed on testnet#

contracts/deployments/testnet.json records these accounts:

  • vaults.probarion.testnet is the factory. Its owner is probarion-owner.testnet, its min_deposit is 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.testnet is the first vault. Its deploy script ran new as the vault account itself, so its get_config shows factory as null.
  • usdc.probarion.testnet is the test USDC token. base-usdc.probarion.testnet and sol-usdc.probarion.testnet stand in for the Base and Solana assets inside intents-stub.probarion.testnet, the stand-in for NEAR Intents. All of them are subaccounts of probarion.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-ft and intents-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_transfer and storage_deposit on the USDC token, and ft_withdraw on 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.

Built from 4ab41ca · reviewed

Show

Loading the search index