> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trustgated.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Gate by capability (Sui)

> Require the non-transferable capability object before a wallet can act. Trust enforced onchain.

## What this does

On Sui, a wallet's standing can be expressed as a capability object it holds. Because the object cannot be transferred, simply holding it is proof the wallet earned its standing, nobody can buy, borrow, or pass it along. Your code requires the capability to run a gated action, and the check happens onchain.

This is how TrustGate's own gated pool works, and you build your own gate the same way.

## The pieces

A few onchain objects are involved.

<CardGroup cols={2}>
  <Card title="The capability" icon="key">
    A non-transferable object held by wallets that meet the required standing. Holding it is the proof.
  </Card>

  <Card title="The score registry" icon="cube">
    Where reads live onchain, so standing can be referenced by contracts directly.
  </Card>
</CardGroup>

## How gating works

<Steps>
  <Step title="Require the capability in your function">
    Write your gated action to take the capability. If the caller does not hold one, the call cannot succeed.
  </Step>

  <Step title="Holding it is the check">
    Because the object is non-transferable, you do not need to trust anything off-chain. Reaching the body of the function already means the caller earned a valid capability.
  </Step>

  <Step title="Standing is issued, not bought">
    A wallet receives the capability by meeting the required standing through its onchain behavior. The bar is set by the trust system, and the capability is the onchain expression of clearing it.
  </Step>
</Steps>

```move theme={null}
// Require the capability to run a gated action.
// Holding it is proof of standing, because it cannot be transferred.
public fun do_gated_action(
    cap: &TrustedAgentCap,
    ctx: &TxContext,
    // ... your own arguments
) {
    trusted_agent_cap::assert_standard_valid(cap, ctx);
    // reaching this line means the caller holds a valid, unexpired capability
}
```

For elite-only actions, substitute `TrustedAgentCapElite` and call `assert_elite_valid` instead. The guard sequence is the same: the non-transferable object ensures possession, and the assert rejects expired caps.

## Onchain reference

```text theme={null}
Network          Sui testnet
Package ID       0x3f06bb8ed79aecdaeecb97feafba276689fcc0fda706953a83718e5a68d4a41a
ScoreRegistry    0x02d2ee0f4d0f8aabd79ed10ee02ddb98ce31823fa84757245509b960ddd99c22
Gated pool       0x5dca7b3bda58a5ac3596bf1dd67b88af2aa89226ac4f82d9eb01675d3fae92eb
Standard cap     <package>::trusted_agent_cap::TrustedAgentCap
Elite cap        <package>::trusted_agent_cap::TrustedAgentCapElite
```

Where `<package>` is the Package ID above. Full type strings for wallet queries:

```text theme={null}
0x3f06bb8ed79aecdaeecb97feafba276689fcc0fda706953a83718e5a68d4a41a::trusted_agent_cap::TrustedAgentCap
0x3f06bb8ed79aecdaeecb97feafba276689fcc0fda706953a83718e5a68d4a41a::trusted_agent_cap::TrustedAgentCapElite
```

## Good to know

The gate is enforced onchain, so there is no off-chain trust step you have to wire up. It is non-transferable by design, which is the whole reason holding it means something. And it is on testnet today, so treat standing as a testnet signal. The required bar is set by the trust system and is not a public number, which keeps the gate honest without exposing how it is drawn.

## Next

<CardGroup cols={2}>
  <Card title="Gated Pools product page" icon="lock" href="/products/gated-pools">
    The concept, and why reputation makes a good door.
  </Card>

  <Card title="The Sui network page" icon="link" href="/networks/sui">
    What is Sui-specific, and the onchain reference.
  </Card>
</CardGroup>
