> For the complete documentation index, see [llms.txt](https://docs.trilobyte.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trilobyte.finance/technical-documentation/common-types-and-events.md).

# Common Types and Events

Two things every contract in the protocol shares: a single crate of cross-contract types, and one consistent event schema. Both exist to make the indexer (and any other off-chain consumer) buildable against a frozen, unambiguous contract surface.

## The `common-types` crate

Soroban has no built-in way for one contract to "import" another contract's `#[contracttype]` definitions — each contract only ships its own compiled WASM plus an XDR spec. Before this crate existed, every contract that needed to decode a cross-contract call result (e.g. the Factory calling `Globals::get_global_settings`) hand-copied the relevant struct definitions into its own source. Soroban's struct encoding is a map keyed by field name, and it traps at runtime — with no compiler help — the moment a caller's hand-copied struct has a different *set* of fields than the real one.

That is exactly what happened on testnet: the Factory's hand-mirrored `GlobalSettings` drifted from the real, growing struct in Globals, and every call that decoded it (including the Factory's own `upgrade`) began trapping. See [Testnet Deployment](/technical-documentation/testnet-deployment.md) for the incident and [Governance](/protocol-mechanics/governance.md) for the upgrade-path rule that came out of it.

`common-types` now holds the single, canonical definition of every cross-contract type — `GlobalSettings`, `Manager`, `ManagerCollateral`, `Pledge`/`PledgeState`, `VaultParams` — plus `#[contractclient]` traits (`GlobalsClient`, `CollateralEscrowClient`, `ComplianceGateClient`) so Factory, Vault, and CollateralEscrow all call each other through the same generated client code rather than hand-declared, driftable copies. A CI check (`scripts/check-type-drift.sh`) guards against a hand-mirrored composite type reappearing anywhere in the workspace.

{% hint style="warning" %}
This crate does **not** by itself prevent every drift-shaped bug — an upgrade or admin-recovery path that decodes even the *shared*, correctly-imported composite type is still unsafe, because that type can still grow a field between when a contract was deployed and when it's asked to decode a fresher one. That's why upgrade paths specifically read only primitive-shaped values (`is_timelock_admin_required() -> bool`, `get_timelock() -> Option<Address>`) instead. See the Upgrade-path rule in [Governance](/protocol-mechanics/governance.md).
{% endhint %}

## Event schema

Every state-changing function across every contract emits exactly one event, generated from that contract's `events.rs`. All events share the same topic shape:

```
("trilo", <event_name: Symbol>, <schema_version: u32>, ...any other #[topic] fields)
```

`schema_version` starts at `1` and increments only on a breaking change to that event's data struct — an indexer can therefore key its parser on `(event_name, schema_version)` and know exactly what shape to expect, even across a contract upgrade.

### globals

| Event                        | Topic fields | Data fields                                          |
| ---------------------------- | ------------ | ---------------------------------------------------- |
| `RoleUpdated`                | `role`       | `new_address`                                        |
| `ProtocolPaused`             | —            | `paused`                                             |
| `ManagerApproved`            | `manager`    | —                                                    |
| `ManagerRemoved`             | `manager`    | —                                                    |
| `AssetWhitelisted`           | `asset`      | —                                                    |
| `AssetRemoved`               | `asset`      | —                                                    |
| `CollateralAssetWhitelisted` | `asset`      | —                                                    |
| `CollateralAssetRemoved`     | `asset`      | —                                                    |
| `FeeUpdated`                 | —            | `new_fee`                                            |
| `SettingsUpdated`            | `caller`     | `protocol_fee`, `min_loan_amount`, `max_loan_amount` |
| `CollateralDeposited`        | `manager`    | `token`, `amount`, `total_staked`                    |
| `CollateralWithdrawn`        | `manager`    | `amount`, `total_staked`                             |
| `CollateralLocked`           | `manager`    | `amount`, `total_locked`                             |
| `CollateralReleased`         | `manager`    | `amount`, `total_locked`                             |
| `CollateralSlashed`          | `manager`    | `amount`, `remaining_staked`                         |
| `ManagerMarkedDelinquent`    | `manager`    | `delinquency_count`                                  |
| `ManagerDelinquencyCleared`  | `manager`    | —                                                    |
| `ManagerCreditLimitSet`      | `manager`    | `max_credit`                                         |
| `ManagerOutstandingUpdated`  | `manager`    | `outstanding_principal`                              |
| `BorrowerOutstandingUpdated` | `borrower`   | `outstanding_principal`, `total_outstanding`         |
| `ComplianceGateSet`          | —            | `gate: Option<Address>`                              |

### factory

| Event             | Topic fields                   | Data fields                                                                  |
| ----------------- | ------------------------------ | ---------------------------------------------------------------------------- |
| `VaultDeployed`   | `vault`, `manager`, `borrower` | `principal`, `loan_term`, `interest_rate`, `leverage_ratio`, `related_party` |
| `WasmHashUpdated` | —                              | `old_hash`, `new_hash`                                                       |

### vault

| Event                          | Topic fields | Data fields                                                                                                                                                                                   |
| ------------------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VaultCreated`                 | `borrower`   | `principal`, `loan_term`, `interest_rate`, `leverage_ratio`, `junior_target`, `senior_target`, `related_party`                                                                                |
| `InvestorDeposited`            | `investor`   | `tranche`, `amount`, `junior_raised`, `senior_raised`                                                                                                                                         |
| `InvestorWithdrew`             | `investor`   | `tranche`, `amount`                                                                                                                                                                           |
| `JuniorLocked`                 | —            | `junior_raised`, `junior_target`                                                                                                                                                              |
| `VaultFullyFunded`             | —            | `total_funded`                                                                                                                                                                                |
| `LoanDisbursed`                | `borrower`   | `amount`                                                                                                                                                                                      |
| `PhaseTransition`              | —            | `from`, `to`                                                                                                                                                                                  |
| `PaymentReceived`              | `payer`      | `amount`, `reserve_paid`, `senior_interest_paid`, `senior_principal_paid`, `junior_interest_paid`, `junior_principal_paid`, `residual`, `outstanding_s`, `outstanding_j`, `schedule_advanced` |
| `YieldClaimed`                 | `investor`   | `tranche`, `amount`                                                                                                                                                                           |
| `CashWithdrawn`                | `borrower`   | `amount`                                                                                                                                                                                      |
| `LateFeeApplied`               | —            | `fee`, `fee_senior`, `fee_junior`, `total_late_fees`, `missed_payments`                                                                                                                       |
| `VaultDefaulted`               | `borrower`   | `outstanding_s`, `outstanding_j`, `missed_payments`                                                                                                                                           |
| `RecoveryDistributed`          | —            | `senior_recovery_pool`, `junior_recovery_pool`, `manager_residual`, `borrower_residual`                                                                                                       |
| `RecoveryClaimed`              | `investor`   | `tranche`, `amount`                                                                                                                                                                           |
| `RenegotiationProposed`        | `manager`    | `new_interest_rate`, `new_loan_term`                                                                                                                                                          |
| `RenegotiationFinalized`       | —            | `manager`, `borrower`, `new_interest_rate`, `new_loan_term`, `new_installment`                                                                                                                |
| `RenegotiationRejected`        | `caller`     | —                                                                                                                                                                                             |
| `ProtocolFeeCollected`         | `treasury`   | `fee_amount`, `source`                                                                                                                                                                        |
| `ProtocolFeeClamped`           | —            | `configured_fee`, `charged_fee`                                                                                                                                                               |
| `InvestorAllowlisted`          | `investor`   | —                                                                                                                                                                                             |
| `InvestorRemovedFromAllowlist` | `investor`   | —                                                                                                                                                                                             |
| `VaultFundingExpired`          | —            | `deadline`, `pending_refund`                                                                                                                                                                  |
| `VaultApprovalExpired`         | —            | `deadline`, `pending_refund`                                                                                                                                                                  |
| `RefundClaimed`                | `investor`   | `tranche`, `amount`                                                                                                                                                                           |
| `ReportReceived`               | —            | `reported_at`                                                                                                                                                                                 |
| `ReportingOverdue`             | —            | `last_report_at`, `checked_at`                                                                                                                                                                |

### collateral-escrow

| Event            | Topic fields | Data fields                                  |
| ---------------- | ------------ | -------------------------------------------- |
| `PledgeLocked`   | `borrower`   | `pledge_id`, `token`, `amount`, `controller` |
| `PledgeReleased` | —            | `pledge_id`, `amount`                        |
| `PledgeSeized`   | `to`         | `pledge_id`, `amount`                        |

### compliance-allowlist

| Event              | Topic fields | Data fields         |
| ------------------ | ------------ | ------------------- |
| `AllowlistUpdated` | `who`        | `action`, `allowed` |

{% hint style="info" %}
Every event's `schema_version` field is also present in the data payload, not just the topic tuple — so a consumer that only inspects data (not topics) can still branch on it.
{% endhint %}

*As of September 2026.*
