Reference
Contract reference
Every public method and view of the Bound contract: arguments, caller, deposit and errors. Plus the mock USDC token.
Contract bound-v3.boundproto-nh26.testnet, near-sdk 5.30.1, source near/contracts/bound/src/lib.rs. Amounts are U128 decimal strings in mock USDC base units (6 decimals); times are unix seconds. A panic message starts with the error code, for example FloatExceeded: amount 500000000 > float 9000000 (the 1 yoctoNEAR guard reads Requires attached deposit of exactly 1 yoctoNEAR).
- Roles are checked with
predecessor_account_id, never the signer. - Every mutating method needs exactly 1 yoctoNEAR or its storage deposit, except
pay,ft_on_transferand the private callback. - No admin setters: the configuration is fixed at init.
new(owner, token, treasury, arbiter, config)is the#[init]method, called in the same transaction as the deploy.
Storage and money
storage_deposit
storage_deposit(account_id?: AccountId)
- Caller
- anyone (registers account_id, default the caller)
- Deposit
- >= 0.01 NEAR; excess, or all of it if already registered, is refunded
- Returns
- { total, available }
- Does
- Registers an internal balance. Deposits are not refundable in this version.
- Errors
StorageDepositTooSmallStorageNotCovered
ft_on_transfer
ft_on_transfer(sender_id, amount: U128, msg: String)
- Caller
- the configured token only (via ft_transfer_call)
- Deposit
- none
- Returns
- unused amount: all of it when the beneficiary is not registered, else 0
- Does
- Credits the sender, or
account_idfor acreditmsg, then runs the msg action. Any parse error or failed action panics, so the token refunds the whole transfer. - Errors
UnknownTokenInvalidAmountInvalidMsgplus the errors of the msg action
withdraw
withdraw(amount: U128)
- Caller
- any registered account (its own balance)
- Deposit
- exactly 1 yoctoNEAR, at least 30 Tgas
- Returns
- Promise (token ft_transfer, then on_withdraw)
- Does
- Debits first, then sends the tokens. The private on_withdraw callback re-credits if the transfer fails (for example the caller is not registered on the token).
- Errors
NotEnoughGasInvalidAmountNotRegisteredInsufficientBalance
Auditor stake
stake
stake(amount: U128)
- Caller
- auditor (its own balance)
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Moves internal balance to free stake. The same happens with ft_transfer_call msg {"stake":{}}.
- Errors
InvalidAmountNotRegisteredInsufficientBalance
unstake
unstake(amount: U128)
- Caller
- auditor
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Moves free stake (never allocated stake) back to the internal balance.
- Errors
InvalidAmountInsufficientFreeStake
Certificates
publish
publish(agent, bound: U128, reserve: U128, expires_at: u64, auditor, float_cap: U128, allowlist?: AccountId[], premium?: U128)
- Caller
- operator (registered)
- Deposit
- >= 0.05 NEAR; excess refunded
- Returns
- cert_id: u64
- Does
- Creates a Pending certificate. A premium is escrowed from the operator's balance and paid at attest. expires_at is unix seconds.
- Errors
PublishDepositTooSmallNotRegisteredInvalidAgentInvalidAccountInvalidAuditorInvalidAmountInvalidFloatCapInvalidExpiryInvalidAllowlistInsufficientBalanceStorageNotCovered
accept
accept(cert_id: u64)
- Caller
- the certificate's agent
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Pending to Accepted; makes this the agent's current certificate.
- Errors
NoSuchCertNotAgentInvalidStatusCertExpiredAgentHasLiveCert
fund_reserve
fund_reserve(cert_id: u64, amount: U128)
- Caller
- operator
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Moves internal balance into reserve_locked. Pending, Accepted or Verified. Also via msg {"reserve":{"cert_id":N}}.
- Errors
InvalidAmountNoSuchCertNotOperatorInvalidStatusInsufficientBalance
attest
attest(cert_id: u64, allocation: U128)
- Caller
- the named auditor
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Locks allocation of free stake behind the certificate, pays the escrowed premium (protocol_fee_bps to the treasury, the rest to the auditor), Accepted to Verified.
- Errors
NoSuchCertNotAuditorNotAcceptedCertExpiredReserveUnfundedAllocationBelowMinStakeInsufficientFreeStake
release_reserve
release_reserve(cert_id: u64)
- Caller
- operator
- Deposit
- 1 yoctoNEAR
- Returns
- U128 released
- Does
- Before attestation: at any time, also refunding an escrowed premium. Verified or Invalid: from the settlement deadline on. Returns reserve_locked plus float and marks the certificate Released.
- Errors
NoSuchCertNotOperatorCertFrozenLockedNothingToRelease
release_allocation
release_allocation(cert_id: u64)
- Caller
- the certificate's auditor
- Deposit
- 1 yoctoNEAR
- Returns
- U128 released
- Does
- From the settlement deadline on, with no open window: the remaining allocation goes back to free stake.
- Errors
NoSuchCertNotAuditorCertFrozenLockedNothingToRelease
Spending
fund_float
fund_float(cert_id: u64, amount: U128)
- Caller
- operator
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Tops up the float, never above float_cap. Accepted or Verified. Also via msg {"float":{"cert_id":N}}.
- Errors
InvalidAmountNotOperatorInvalidStatusFloatCapExceededInsufficientBalance
pay
pay(cert_id: u64, to: AccountId, amount: U128, memo?: String)
- Caller
- the certificate's agent (pay-only function-call key)
- Deposit
- none (not payable, so a function-call key can call it)
- Returns
- ()
- Does
- Moves amount from the float to to's internal balance, meters spent and pay_count, emits a pay event. See How it works for the order of checks.
- Errors
NotAgentCertNotVerifiedCertFrozenSettlementDeadlinePassedNotCurrentCertCertHaltedInvalidAmountInvalidRecipientRecipientNotAllowedRecipientNotRegisteredFloatExceededMemoTooLong
halt / resume
halt(cert_id: u64), resume(cert_id: u64)
- Caller
- operator
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Stops or restarts pay. A settled (Invalid) certificate cannot pay whatever this flag says.
- Errors
NoSuchCertNotOperator
clawback
clawback(cert_id: u64)
- Caller
- operator
- Deposit
- 1 yoctoNEAR
- Returns
- U128 returned
- Does
- Takes the unspent float back to the operator's balance.
- Errors
NoSuchCertNotOperator
Claims and settlement
challenge
challenge(cert_id: u64, proof: Proof, victim?: AccountId, bond: U128)
- Caller
- anyone except the operator, agent and auditor
- Deposit
- >= 0.01 NEAR; excess refunded
- Returns
- challenge_id: u64
- Does
- Posts the bond. A false trustless predicate is rejected at once (bond to the treasury); otherwise opens or joins the claim window and freezes the certificate.
- Errors
ChallengeDepositTooSmallNoSuchCertNotChallengeableConflictedChallengerSettlementDeadlinePassedBondTooSmallConflictedVictimNotRegisteredInsufficientBalanceInvalidAmountEvidenceUriTooLongWindowFullDuplicateClaimStorageNotCovered
resolve_by_arbiter
resolve_by_arbiter(challenge_id: u64, proven: bool, harm: U128)
- Caller
- the arbiter
- Deposit
- 1 yoctoNEAR
- Returns
- ()
- Does
- Decides a Harm claim. Proven: 0 < harm <= claimed, capped at coverage. Rejected: bond to the treasury and the window slot freed.
- Errors
NotArbiterNoSuchChallengeNotArbitrableAlreadyResolvedNoOpenWindowInvalidHarm
close_window
close_window(cert_id: u64)
- Caller
- anyone
- Deposit
- 1 yoctoNEAR
- Returns
- Settlement | null
- Does
- Settles every claim in the window atomically: the waterfall (fraud) or the hygiene bounty. Null when nothing was admitted.
- Errors
NoSuchCertNotChallengeableNoOpenWindowWindowOpenArbiterGrace
ft_transfer_call msg
Send mock USDC with ft_transfer_call to bound-v3.boundproto-nh26.testnet. An empty msg credits the sender. The sender (or the credited account) must already be registered on Bound.
"" credit the sender
{"credit":{"account_id":"x.testnet"}} credit another registered account
{"stake":{}} credit, then stake all of it
{"reserve":{"cert_id":0}} credit, then fund that reserve
{"float":{"cert_id":0}} credit, then fund that floatViews
| View | Returns | Notes |
|---|---|---|
verify(agent) | CertView | null | the agent's current (last accepted) certificate |
get_cert(cert_id) | CertView | null | one certificate by id; ids above u32::MAX return null |
list_certs(from_index?, limit?) | CertView[] | a page of certificates; limit at most 50 |
cert_count() | u64 | number of certificates |
challenge_count() | u64 | number of challenges |
get_challenge(challenge_id) | ChallengeView | null | challenger, victim, proof, bond, filed_at, adjudicated, proven, harm, verdict |
get_window(cert_id) | WindowView | null | the open window: opened_at, closes_at, claims |
get_config() | Config | the immutable configuration |
get_accounts() | { owner, token, treasury, arbiter } | the fixed accounts |
get_owner() | AccountId | owner set at init |
balance_of(account_id) | U128 | internal balance (0 if unregistered) |
get_stake(auditor) | { free, allocated } | an auditor's stake |
storage_balance_of(account_id) | { total, available } | null | registration check |
CertView
cert_id, status, deal, operator, agent, auditor, bound, reserve_promised, reserve_locked, allocation, coverage, premium, float, float_cap, spent, post_expiry_spent, pay_count, allowlist, expires_at, settlement_deadline, halted, window_closes_at, open_claims, settlement, now. See statuses.
Settlement
mode (fraud or hygiene), settled_at, admitted, payable, reserve_draw, victim_paid, fee_paid, slash, slash_to_victims, to_treasury, auditor_returned (the allocation left unslashed, which stays locked until release_allocation; the name predates that rule) and hygiene_bounty_paid.
Challenge verdicts
Pending, Rejected (bond to the treasury), Unadjudicated (half the bond back), Cured (bond back), Upheld (settled, bond back).
Configuration on testnet
| Field | Value | Meaning |
|---|---|---|
claim_window_secs | 90 | length of a claim window (production would be 72 h) |
post_expiry_secs | 300 | expires_at + this = settlement deadline (production 7 d) |
grace_secs | 60 | post-expiry spend inside this is not counted (production 24 h) |
min_stake | 10000000 | minimum allocation (10 mUSDC) |
min_challenge_bond | 10000000 | minimum bond (10 mUSDC) |
challenger_fee_bps | 1000 | challenger fee, bps of proven harm |
de_minimis_bps | 10 | ExpiredSpend threshold, bps of bound |
hygiene_bounty | 10000000 | flat bounty from the reserve (10 mUSDC) |
protocol_fee_bps | 1000 | treasury share of the premium |
Limits: 16 claims per window, 16 allowlist entries, 64-byte memo, 256-byte evidence URI, 50 certificates per list_certs page. Storage: 0.01 NEAR to register, 0.05 NEAR per publish, 0.01 NEAR per challenge; each method measures the bytes it writes and panics with StorageNotCovered if the deposit does not cover them.
Events
NEP-297 logs with standard bound, version 1.0.0: register, deposit, withdraw, withdraw_failed, stake, unstake, publish, accept, fund_reserve, fund_float, attest, pay, halt, resume, clawback, challenge, challenge_rejected, resolve, window_closed, settle, release_reserve, release_allocation.
EVENT_JSON:{"standard":"bound","version":"1.0.0","event":"pay","data":[{"cert_id":1,"agent":"bound-agent2-mwfnc6q8.testnet","to":"bound-service-mwfnc6q8.testnet","amount":"1000000","memo":"mcp tool call","spent":"1000000"}]}Calling it
near contract call-function as-read-only bound-v3.boundproto-nh26.testnet get_config json-args '{}' network-config testnet now
near contract call-function as-read-only bound-v3.boundproto-nh26.testnet verify json-args '{"agent":"bound-agent2-mwfnc6q8.testnet"}' network-config testnet nowMock USDC token
usdc.boundproto-nh26.testnet, source near/contracts/mock-usdc/src/lib.rs. A plain NEP-141 / NEP-145 / NEP-148 token built on near-contract-standards: name "Bound Mock USDC (testnet play money)", symbol mUSDC, 6 decimals.
mint(account_id, amount)is open: anyone can mint up to 1,000,000 USDC per call to any account, and it registers the account on the token if needed. It is play money, not Circle USDC.- The standard
ft_transfer,ft_transfer_call,ft_balance_of,ft_total_supply,ft_metadata,storage_deposit,storage_withdraw,storage_unregister,storage_balance_boundsandstorage_balance_ofare the near-contract-standards ones. withdrawon Bound fails and re-credits if the caller is not registered on the token; call the token'sstorage_depositand withdraw again.
Unit tests live in src/tests.rs; Security maps the checklist to them.