# Networks and configuration (/developers/concepts/networks-and-configuration)



A network is one configuration file. Everything network specific lives in it: every address,
script hash, policy id, endpoint, reference UTxO and protocol parameter.

Nothing in the codebase branches on the network name to decide behaviour. Moving to a new
network is a new configuration file plus a deployment, never a code change.

## There is no default network [#there-is-no-default-network]

`NETWORKS` is `["mainnet", "preprod", "preview"]` and `parseNetwork` throws with the accepted
set when given anything else.

Every entry point demands the network explicitly:

* Every `cardano-swap` command requires `--network`, or `CARDANO_SWAP_NETWORK` in the
  environment.
* The web build reads `VITE_CARDANO_SWAP_NETWORK` and throws a named error when it is unset:
  "There is no default network."

Preprod and mainnet policy ids, script hashes and addresses differ completely. A silent
default would mix them.

## Where the configuration is found [#where-the-configuration-is-found]

`resolveConfigDir` looks in this order:

1. The `configDir` argument, when a caller passes one.
2. The `CARDANO_SWAP_CONFIG_DIR` environment variable.
3. A `config` directory found by walking up from the module, containing `preprod.json` or
   `mainnet.json`.

If none resolves, it throws and names the environment variable to set.

The browser build passes a virtual directory holding the bundled configuration files, so the
same loader runs in the browser and on the command line, and the two agree on the asset set by
construction.

`config/` ships `mainnet.json` and `preprod.json`.

## What loading validates [#what-loading-validates]

`loadNetworkConfig(network)` does four things, and any one of them failing throws rather than
producing a partly trusted configuration.

<Steps>
  <Step>
    ### Parses the file [#parses-the-file]

    A file that is not valid JSON throws naming the path.
  </Step>

  <Step>
    ### Validates against the schema [#validates-against-the-schema]

    The whole file is checked against a Zod schema. Hex fields must be lower case hex of the
    right length, out refs must be `txHash#index`, addresses must be bech32 with the right prefix.
    Failures print every issue.
  </Step>

  <Step>
    ### Confirms the file is for the network it was loaded as [#confirms-the-file-is-for-the-network-it-was-loaded-as]

    `config/preprod.json` declaring `"network": "mainnet"` throws.
  </Step>

  <Step>
    ### Recomputes every asset fingerprint [#recomputes-every-asset-fingerprint]

    For each asset, the CIP-14 fingerprint is recomputed from the policy id and the asset name
    and compared with the recorded value. A single altered character in a policy id throws at
    load rather than producing a wrong quote later.

    Duplicate asset keys and duplicate symbols also throw.
  </Step>
</Steps>

The result is cached per directory and network.

## Null means "not deployed here" [#null-means-not-deployed-here]

A value that can only be known after a deployment on a given network is present in the schema
and set to `null`.

Reading one goes through `requireDeployed`, which throws a message naming the key and the
network:

> `settlement.address` is not set for mainnet. It is filled by the deployment on that network;
> there is no fallback to another network's value.

That is the point. Borrowing another network's value silently would submit a transaction
against the wrong script.

The same applies to venues. A venue whose `poolScriptHash` is null on a network is skipped
during router construction with the reason `not deployed on <network>`, and the skip is
reported rather than swallowed.

## Secrets are named, never inlined [#secrets-are-named-never-inlined]

The configuration holds the **name** of the environment variable that carries a credential,
never the credential.

```json
"koios": {
  "baseUrl": "https://preprod.koios.rest/api/v1",
  "bearerTokenEnv": "KOIOS_BEARER_TOKEN"
}
```

`requireEnv(varName)` reads it and throws naming the variable when it is unset. It never
returns an empty string.

## Adding a network [#adding-a-network]

<Steps>
  <Step>
    ### Write `config/<network>.json` [#write-confignetworkjson]

    Copy the shape of an existing file. Fill in the assets with correct fingerprints, the venues
    that are deployed there, and the provider endpoints. Set every value that needs a deployment
    to `null`.
  </Step>

  <Step>
    ### Deploy what needs deploying [#deploy-what-needs-deploying]

    `cardano-swap deploy settlement --network <network> --submit` publishes the settlement
    validator and prints the script hash, script address and reference UTxO.
  </Step>

  <Step>
    ### Fill the nulls [#fill-the-nulls]

    Write the printed values into `settlement.validatorHash`, `settlement.address`,
    `settlement.referenceScript` and `settlement.deploymentTx`.
  </Step>

  <Step>
    ### Verify [#verify]

    `cardano-swap config show --network <network>` prints the resolved configuration.
    `cardano-swap footprint check --network <network>` resolves every declared identifier on
    chain.
  </Step>
</Steps>

## Related [#related]

<Cards>
  <Card title="Configuration reference" href="/developers/reference/configuration" />

  <Card title="Command line" href="/developers/reference/command-line" />

  <Card title="Footprint and measurement" href="/developers/verification/footprint" />
</Cards>
