A permissioned market gates specific on-chain actions such as deposit, borrow, and liquidate behind an explicit per-user allowlist. A user without an allowlist entry (or whose entry doesn’t include the action they’re attempting) is rejected by the program. The curator picks which actions are gated and which users are allowed to take them; everything else stays open. The on-chain enforcement is handled by a separate program called kperm.Documentation Index
Fetch the complete documentation index at: https://kamino.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
When to use this
- KYC’d-only depositor base — tie KYC completion to a wallet, then automate whitelisting via the API
- Accredited-investor restrictions — same pattern, gated by attestation
- Internal market for a specific app’s users — your app’s onboarding flow is the gate
- Permissioned borrowers — counterparty agreements that lock borrow access to named entities
How it works
Permissioning is enforced by a cosigner pattern. Every gated action on a permissioned market requires two on-chain signatures: the user’s, plus a co-signature from a kperm-controlled PDA called the Market Permissioner. klend will only execute the action if both are present. The mechanic has two on-chain pieces. The market holds two new fields.permissioning_authority is a pubkey that klend treats as a required co-signer on every gated action; the curator sets it to the kperm-derived Market Permissioner PDA (seeds: ["market", market_address]). permissioned_ops is a u64 bitfield naming which actions on this market are gated. Setting these two fields is what turns a market into a permissioned market.
The kperm program holds the per-user allowlist. For each (market, user) pair authorized to take gated actions, kperm stores a UserPermission account at PDA ["permission", market, user] recording which operations that user can take.
When a user takes a gated action, their wallet does not call klend directly. It builds the klend instruction it wants to execute, then wraps it inside kperm.permissioned_fwd_to_klend(ix_data) and submits the wrap. kperm reads the user’s UserPermission, confirms the requested action is in the allowlist, and CPIs into klend with its Market Permissioner PDA acting as the co-signer. klend sees the required co-signer present and executes the wrapped instruction. If the user has no UserPermission or the requested action is missing from the bitfield, kperm rejects and the entire transaction reverts.
For non-gated actions on the same market (actions whose bit is not set in permissioned_ops, plus withdraw, repay, refresh, and read paths), users call klend directly. Only the gated operations require the wrap.
The operations
The kperm bitfield supports four operation slots:| Bit | Op | Notes |
|---|---|---|
| 0 | DEPOSIT | Gates depositing collateral / supplying liquidity |
| 1 | BORROW | Gates borrowing |
| 2 | LIQUIDATE | Gates liquidating other users’ positions on this market |
| 5 | KEYRING | External-policy bridge. Use this when a user’s actions should be enforced by a separate keyring/policy program (the kperm allowlist still applies as a fallback) |
UserPermission.permissioned_ops is the bitwise OR of the bits they’re allowed to act on (e.g. DEPOSIT | BORROW for a whitelisted depositor-borrower).
Withdraw and repay stay open. The on-chain bitfield doesn’t gate exits — once a user has been allowed to deposit or borrow, they can always close their position. Refresh and read paths are also always open. The design is to screen capital at the entry; not at the exit.
Curator workflow
Decide what to permission
Pick the operations to gate.
DEPOSIT is the most common (KYC’d depositor base). Add BORROW for fully gated lending venues. You can change this later.Switch the market into permissioned mode
Set
permissioning_authority to the Market Permissioner PDA and permissioned_ops to the chosen bitfield. From this point, klend requires the kperm cosigner for every gated action.Whitelist users
Use the SDK, CLI, or REST API (see tabs below). All three issue the same
init_user_permission (first grant) or update_user_permission (subsequent grants) instruction on-chain.- SDK
- API
- Kamino CLI
Configure permissioning via SDK
The kperm-aware methods live in@kamino-finance/klend-sdk alongside the standard KaminoManager.Curator: switch the market into permissioned mode
PermissionedOp.fromString accepts pipe-separated names: 'DEPOSIT', 'DEPOSIT|BORROW', 'DEPOSIT|BORROW|LIQUIDATE', etc.Whitelist a user (initial grant or update)
updatePermissionIx takes an overwrite flag: true replaces the user’s allowed ops with grantedOps; false bitwise-ORs grantedOps into the existing set.Revoke a user
UserPermission account stays on-chain with permissioned_ops = 0. Re-granting later avoids paying rent again.User flow: take a gated action
The standardKaminoAction builders detect when the target market is permissioned and automatically wrap the produced klend instructions with permissioned_fwd_to_klend. Builders integrating against a permissioned market continue to call KaminoAction.buildDepositTxns(...), buildBorrowTxns(...), etc. — the SDK handles the wrap.For instructions built outside of KaminoAction, wrap manually:On-chain accounts
| Account | Program | PDA seeds | Stores |
|---|---|---|---|
LendingMarket | klend | (market account) | permissioning_authority (Market Permissioner PDA), permissioned_ops (u64 bitfield) |
UserPermission | kperm | ["permission", market, user] | market, user, permissioned_ops, cached marketPermissioner, bumps |
| Market Permissioner | kperm | ["market", market] | Authority PDA the kperm program signs as when CPI’ing into klend (signature-only; the PDA stores no data) |
GlobalConfig | kperm | ["global_config"] | globalAdmin, pendingAdmin for the kperm program |
KPermUZsf9tu4cSd9LNcMojCbiHfdbJXv9dr3pAUzz1.
Operational considerations
| Topic | Detail |
|---|---|
| Performance | Permissioned actions add one CPI hop (kperm → klend). Compute-unit cost rises modestly; users may need to bump priority fees on busy slots |
| Multisig | When the curator’s market owner is a multisig, update-lending-market-permission becomes a multisig proposal subject to the timelock, like every other market config change |
| Whitelist authority | The kperm globalAdmin is set when the kperm program is initialized. For most curator markets, a Kamino-controlled admin holds it; the curator delegates whitelisting to the REST API. For curators that want full sovereignty, coordinate with the team to use a curator-owned admin |
| Composability | Permissioning is enforced at the klend-instruction boundary. Programs that integrate with klend by composing instructions (vaults, liquidators, third-party interfaces) must use permissioned_fwd_to_klend to interact with a permissioned market |
| Exit semantics | Withdraw and repay are always open. If you need to throttle exits, layer the withdrawal queue and standard reserve caps on top |
Reference
- Market config reference —
permissioning_authorityandpermissioned_opsfields - Market settings — broader market-level config flow
- Updating reserves — reserves work the same way under a permissioned market
update-lending-market-permission,add-permission,remove-permissionCLI — full flag detail