> 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/deployment.md).

# Deployment

Trilobyte contracts are deployed to Stellar with a TypeScript script that drives the `stellar` CLI (`@stellar/stellar-sdk` is used for keypair/address handling).

## Full Protocol Deployment

The main deployment script is `scripts/deploy-protocol.ts`. It deploys the four governance/registry contracts and runs post-deploy initialisation. (The **CollateralEscrow** is deployed separately, per RWA-collateral lender — it is not part of the core protocol deploy.)

### Step 1 — Deploy Globals

```
Globals(governor, treasury, security_admin, operations_admin)
```

Globals is deployed first. `governor` becomes the OZ admin; `security_admin` and `operations_admin` are granted their roles in the constructor.

### Step 2 — Deploy Timelock

```
Timelock(min_delay, proposers, executors, admin: None)
```

Self-administered. `min_delay` is in **ledgers**. Proposers are also granted the canceller role; an empty executor list means anyone can execute.

### Step 3 — Upload Vault WASM

The compiled vault WASM is uploaded (`stellar contract upload`), returning a WASM hash used by the Factory to deploy vault instances.

### Step 4 — Deploy Factory

```
Factory(governor, globals_address, vault_wasm_hash)
```

### Step 5 — Register the Factory in Globals (MANDATORY)

```
globals.set_factory(factory_address)
```

{% hint style="danger" %}
**This step is required.** Globals gates `lock_collateral`, `increment_outstanding`, and `register_vault` on the call coming from the registered Factory. Until `set_factory` has been called, `create_vault` fails when it tries those cross-contract calls — no vault can be created. `set_factory` is `#[only_admin]`, so it must run **before** admin is transferred to the Timelock.
{% endhint %}

### Step 6 — Whitelist Assets

```
globals.whitelist_asset(asset)
```

{% hint style="info" %}
Must be done **before** transferring Globals admin to the Timelock, since it requires direct admin access.
{% endhint %}

### Step 7 — Approve Initial Managers

```
globals.approve_pool_manager(manager_address, caller, max_credit)
```

A single call both registers and approves a manager (there is no separate `add_pool_manager`). `caller` must hold the `ops_adm` role.

### Step 8 — Transfer Globals Admin to the Timelock

Globals uses the OZ **two-step** admin transfer:

```
globals.transfer_admin_role(timelock_address, live_until_ledger)   // current admin initiates
globals.accept_admin_transfer()                                     // the Timelock accepts
```

`live_until_ledger` bounds when the pending transfer expires (`0` cancels it). After acceptance, all admin-gated operations on Globals must go through the Timelock's governance process.

{% hint style="warning" %}
**This step is effectively irreversible.** Once admin is the Timelock, direct admin access is gone. Ensure `set_factory`, asset whitelisting, and manager approval are all complete first.
{% endhint %}

{% hint style="danger" %}
**Deploy-script discrepancy (verify before running).** As of this writing `scripts/deploy-protocol.ts` calls a single `transfer_admin` (one-step) for step 8. The deployed Globals contract exposes only the OZ two-step `transfer_admin_role` / `accept_admin_transfer` — there is no `transfer_admin` function. The single call will fail. Use `transfer_admin_role(new_admin, live_until_ledger)` followed by `accept_admin_transfer()`.
{% endhint %}

## Running the Deployment

```bash
# Build all contracts (WASM target wasm32v1-none)
stellar contract build

# Deploy the full protocol
npx ts-node scripts/deploy-protocol.ts
```

## Configuration

All deployment parameters are configured via environment variables. See `.env.example`:

| Variable                   | Description                                               |
| -------------------------- | --------------------------------------------------------- |
| `SOROBAN_NETWORK`          | Network to deploy to (`testnet` / `mainnet`)              |
| `NETWORK_RPC_URL`          | Soroban RPC endpoint                                      |
| `NETWORK_PASSPHRASE`       | Network passphrase                                        |
| `NETWORK_HORIZON_URL`      | Horizon endpoint                                          |
| `WASM_TARGET_DIR`          | Build output dir (default `target/wasm32v1-none/release`) |
| `SOURCE_SECRET_KEY`        | Secret key for the deploying account                      |
| `GOVERNOR_ADDRESS`         | Initial governor (root admin of Globals)                  |
| `TREASURY_ADDRESS`         | Protocol treasury address                                 |
| `SECURITY_ADMIN_ADDRESS`   | Security admin address                                    |
| `OPERATIONS_ADMIN_ADDRESS` | Operations admin address                                  |
| `TIMELOCK_MIN_DELAY`       | Minimum delay for timelocked operations (ledgers)         |
| `TIMELOCK_PROPOSERS`       | Comma-separated proposer addresses (≥ 1 required)         |
| `TIMELOCK_EXECUTORS`       | Comma-separated executor addresses (empty ⇒ anyone)       |
| `WHITELIST_ASSETS`         | Comma-separated asset addresses to whitelist              |
| `INITIAL_MANAGERS`         | Comma-separated manager addresses to approve              |
| `MANAGER_CREDIT_LIMIT`     | Credit limit applied to initial managers (7-decimal)      |
| `STELLAR_CLI_PATH`         | (optional) Absolute path override for the `stellar` CLI   |

{% hint style="info" %}
The deployer secret is passed to the CLI via the `STELLAR_ACCOUNT` / `STELLAR_SIGN_WITH_KEY` environment variables (never on argv), and the `stellar` CLI path is resolved on a sanitised PATH to prevent PATH-hijack.
{% endhint %}

## Output

Deployment results are saved to `.soroban/contract-ids.json`:

```json
{
  "network": "testnet",
  "deployedAt": "2026-02-27T12:00:00Z",
  "contracts": {
    "globals": "CABC...",
    "timelock": "CDEF...",
    "factory": "CGHI..."
  },
  "vaultWasmHash": "abc123..."
}
```
