> For the complete documentation index, see [llms.txt](https://docs.sectoral.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sectoral.xyz/under-the-hood/contracts.md).

# Smart Contracts

Every Sectoral account is built directly on the protocol's confidential token contract on Robinhood Chain, an ERC-20 wrapper with encrypted balances that follows the Zether approach. The EVM has no built-in confidential transfer, so Sectoral wrote this layer itself; it is open source and verified on-chain. Sectoral runs no shadow ledger and no private system of record alongside it. Once you understand the token contract, you understand exactly how balances and transfers work.

***

## What the contract stores

`ConfidentialToken` wraps a plain ERC-20 (USDG on Robinhood Chain) and keeps each registered account's balance as an ElGamal ciphertext on the alt\_bn128 curve. An account calls `register` once with its ElGamal public key and from that point carries a single two-point ciphertext:

```solidity
struct Ciphertext {
    AltBn128.Point c1;
    AltBn128.Point c2;
}

mapping(address => AltBn128.Point) internal _publicKey; // ElGamal key the balance encrypts under
mapping(address => bool) public registered;
mapping(address => Ciphertext) internal _balance;       // encrypted balance, readable via encryptedBalanceOf
uint256 public totalWrapped;                            // public total of the underlying asset held
```

The balance is ciphertext. It can be opened only with the matching ElGamal private key (your view key, derived from your account key). For everyone else, Sectoral included, it is indistinguishable from noise.

Value enters through `deposit(amount)`, which wraps the underlying asset into your encrypted balance, and leaves through `withdraw(amount, proof, publicSignals)`, which unwraps against a proof that the encrypted balance covers the amount. Both of those amounts are public, because the ERC-20 transfers on either side of them are public anyway.

***

## What a transfer submits

A confidential transfer never states its amount. The sender's client builds two encrypted deltas and a proof, and sends them as calldata:

```solidity
function confidentialTransfer(
    address to,
    Ciphertext calldata senderDelta,     // -amount, encrypted to the sender's key
    Ciphertext calldata recipientDelta,  // +amount, encrypted to the recipient's key
    bytes calldata proof,
    uint256[] calldata publicSignals     // circuit public inputs, passed through to the verifier
) external;
```

In that same transaction, the contract asks its verifier (`IConfidentialTransferVerifier.verifyTransfer`) to confirm that both deltas encrypt one identical, non-negative amount and that the sender stays solvent. Only then does it apply each delta to the matching balance by point addition. The verifier is a separately deployed Groth16 contract generated from the protocol's circuits, and it sits behind `setVerifier` so the proof system can be upgraded without moving a single stored balance. Robinhood Chain settles to Ethereum through the rollup's fraud proofs, so the verifier's verdict is ultimately backed by Ethereum's security. The proofs reveal validity and nothing more.

***

## Fees

`FeeSchedule` is the protocol's single price list, and the contracts that move value call its `quoteFee` view to price a transfer. The fee is flat: 0.10% of the amount, never more than 5 USDG. There are no tiers and no discounts. The schedule's authority can retune the rate and the cap with `setSchedule(baseFeeBps, feeCap)`, and the role changes hands through a two-step `beginAuthorityTransfer` / `acceptAuthority` handoff.

***

## The off-chain indexer

A PostgreSQL index built from contract event streams exists only so the interface is quick and searchable. It contains:

* Mappings from addresses to `@handle`s
* Transaction metadata that is already public on-chain: the two addresses, the timestamp, and the hash
* Webhook subscriptions and their delivery status

It contains no decrypted balances and no decrypted amounts. Readable figures live on your device alone; everywhere else, including the chain, they stay encrypted.

***

## How agent accounts work on-chain

Agents spend through `AgentController`. Each agent gets an internal vault inside that contract and a dedicated `agentSigner` key held by whatever system runs it. That key can do exactly one thing: spend from its own vault, in a single nominated token, within the spend policy its owner wrote (per-transaction limit, daily limit, recipient allowlist, and approval threshold). It cannot withdraw, re-key itself, or widen its own limits. A spend outside the policy is rejected by the contract itself; client-side checks catch it sooner, but the on-chain rule is what keeps the limit in force even if the client is compromised. This is how autonomous software gets genuine spending power with bounded exposure. See [Security and Threat Model](/under-the-hood/threat-model.md).

***

## Deployed addresses

The contracts are live on Robinhood Chain testnet. Every address links to the block explorer, where you can follow each transaction the contracts have processed.

| Contract            | Testnet address                                                                                                                                 |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `ProtocolAuthority` | [`0xde0cc85F9F168576eC429D8E023871c623580F96`](https://explorer.testnet.chain.robinhood.com/address/0xde0cc85F9F168576eC429D8E023871c623580F96) |
| `AccountRegistry`   | [`0x7d14b198B7D4Cf50287209d102cCE39388A861b0`](https://explorer.testnet.chain.robinhood.com/address/0x7d14b198B7D4Cf50287209d102cCE39388A861b0) |
| `AgentController`   | [`0x1458062e466128791044bE256eD7A866f3825Af7`](https://explorer.testnet.chain.robinhood.com/address/0x1458062e466128791044bE256eD7A866f3825Af7) |
| `RequestLedger`     | [`0xa365489ee4aAdA03BF4135c342e61cc8399ef004`](https://explorer.testnet.chain.robinhood.com/address/0xa365489ee4aAdA03BF4135c342e61cc8399ef004) |
| `DisclosureLog`     | [`0xf397327d4FD2Ff1B527be56D682Ba4E2b95B88A2`](https://explorer.testnet.chain.robinhood.com/address/0xf397327d4FD2Ff1B527be56D682Ba4E2b95B88A2) |
| `ConfidentialToken` | [`0x75C62a67f543045D3A6C1229628Af5fAf0097633`](https://explorer.testnet.chain.robinhood.com/address/0x75C62a67f543045D3A6C1229628Af5fAf0097633) |
| Transfer verifier   | [`0xd641b9D71ABBbA5D51c0a4dF7167f77a8Dc3E95C`](https://explorer.testnet.chain.robinhood.com/address/0xd641b9D71ABBbA5D51c0a4dF7167f77a8Dc3E95C) |
| USDG (testnet)      | [`0xCDF02eC32cd2A6ad7610A2e6a8fd95A9DeC98d16`](https://explorer.testnet.chain.robinhood.com/address/0xCDF02eC32cd2A6ad7610A2e6a8fd95A9DeC98d16) |

Testnet has no official USDG, so the testnet deployment settles in a six-decimal stand-in token with no real value.

***

## Related pages

* [Architecture Overview](/under-the-hood/system-design.md)
* [Security and Threat Model](/under-the-hood/threat-model.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sectoral.xyz/under-the-hood/contracts.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
