# BitPatagonia 27 MW — Token de participación en resultados / Profit-share token

[Español](#español) · [English](#english) · [Technical](#technical)

---

## Español

### Qué es

BitPatagonia S.A. construye una central de generación a gas de 27 MW en Río Grande, Tierra del
Fuego, que alimenta un sitio de minería de bitcoin operado en conjunto con un socio tecnológico.
Para financiar los generadores (USD 9.720.000) la compañía emite un **token** en lugar de tomar un
único grupo inversor.

**1 token = USD 1 aportado.** El token replica exactamente la economía de las acciones Categoría B
del modelo financiero: un derecho sobre el flujo mensual de BitPatagonia, nada más y nada menos.

> Este token es un **valor negociable** (security). Sólo pueden tenerlo y transferirlo inversores
> registrados por el emisor tras un proceso de KYC. No hay venta pública ni mercado secundario
> abierto. La estructura legal la define el asesor legal; el código sólo la hace cumplir.

### Cómo se reparte la caja, mes a mes

Cada mes BitPatagonia calcula su **flujo neto distribuible**: lo que cobra (cargo de energía al
JV minero + su participación en la utilidad minera) menos lo que paga (impuestos, gas, O&M,
sueldos, seguros, gastos fijos, overhaul). Sobre ese número se aplica la cascada ("waterfall"):

```
 Flujo neto del mes
        │
        ├─ 5 % ──► Reserva de la compañía (queda en BitPatagonia)
        │
        └─ 95 % ──► POOL de dividendos
                        │
     ┌──────────────────┴──────────────────┐
     │ ¿Los inversores ya recuperaron      │
     │ 1,0× su aporte?                     │
     └──────────┬──────────────┬───────────┘
               NO             SÍ
                │              │
       100 % del pool     Participación fijada × pool ──► inversores
       ──► inversores     el resto ──► BitPatagonia
```

1. **Reserva:** 5 % del flujo positivo queda en la compañía. Si el mes es negativo (por ejemplo el
   overhaul del mes 49) no se paga nada y el negativo **no se arrastra**: lo absorbe la compañía.
2. **Hasta recuperar el capital:** el 100 % del pool va a los inversores, hasta que la suma de lo
   cobrado iguale lo aportado (hurdle 1,0×). Sin intereses, valor nominal.
3. **El ratchet:** en el mes en que se completa el recupero se fija, **una sola vez y para
   siempre**, la participación de los inversores en todo lo que venga después:

   | Mes de recupero | Participación |
   |---|---|
   | 29 o antes | 27,508 % |
   | 30 | 28,579 % |
   | 31 | 29,649 % |
   | 32 | 30,719 % |
   | 33 | 31,789 % |
   | 34 | 32,860 % |
   | 35 | 33,930 % |
   | 36 o después | 35,000 % |

   Es decir: si el proyecto tarda más de 29 meses en devolver el capital, los inversores reciben
   una participación mayor (1,07 puntos por mes de demora, tope 35 %).
4. **Después del recupero:** cada mes los inversores cobran `participación × pool`; el resto es de
   BitPatagonia (Categoría B en especie + Categoría A) y no pasa por el token.

Cada pago se reparte **a prorrata** entre los tenedores según sus saldos al momento del depósito.

### Ejemplo con el caso base (hashprice 0,040 USD/TH/día)

| | |
|---|---|
| Flujo neto mes 1 | USD 323.784 |
| Reserva 5 % | USD 16.189 |
| Pool | USD 307.594 → 100 % a inversores |
| Recupero del capital | mes 29 |
| Participación fijada | 27,508 % |
| Cobrado por inversores en 8 años | USD 19,7 M (2,03× el aporte, sin valor residual) |

Los diez escenarios de hashprice del modelo (0,020 a 0,050) están en `test_vectors/` y el código
los reproduce al centavo.

### Qué pasa en la práctica

- **Suscripción:** durante la ventana, un inversor habilitado envía USDC y recibe tokens 1:1. Si al
  cierre no se llegó al mínimo (USD 9,72 M) se devuelve todo. Se puede recaudar más que el mínimo
  (hasta el máximo configurado): el proyecto se agranda.
- **Cada mes:** BitPatagonia publica un reporte firmado (2 de 3 firmantes, incluido un auditor
  externo), deposita en USDC la parte de los inversores y registra el hash del reporte en el
  contrato. El contrato aplica la cascada y toma una foto de los saldos.
- **Cobro:** cada tenedor reclama su parte cuando quiera; no vence.
- **Transferencias:** sólo entre direcciones habilitadas, con posibles períodos de bloqueo (lock-up)
  y reglas por jurisdicción que fija el emisor. El emisor puede congelar cuentas y ejecutar
  transferencias forzadas ante una orden judicial, siempre con registro público en la cadena.

---

## English

### What it is

BitPatagonia S.A. is building a 27 MW gas-fired power plant in Río Grande, Tierra del Fuego
(Argentina), powering a bitcoin mining site run with a technology partner. To fund the generators
(USD 9,720,000) the company issues a **token** instead of taking a single investor group.

**1 token = USD 1 contributed.** The token replicates exactly the economics of the Category B shares
in the financial model: a claim on BitPatagonia's monthly cash flow, no more and no less.

> This token is a **security**. Only investors registered by the issuer after KYC can hold or
> transfer it. There is no public sale and no open secondary market. Counsel decides the legal
> wrapper; the code only enforces it.

### How cash is split, month by month

Each month BitPatagonia computes its **net distributable cash flow**: what it receives (energy
charge from the mining JV + its share of mining profit) minus what it pays (taxes, gas, O&M,
salaries, insurance, fixed costs, overhaul). The waterfall is applied on that number:

```
 Month's net cash flow
        │
        ├─ 5 % ──► Company reserve (stays with BitPatagonia)
        │
        └─ 95 % ──► Dividend POOL
                        │
     ┌──────────────────┴──────────────────┐
     │ Have investors already recovered    │
     │ 1.0× their contribution?            │
     └──────────┬──────────────┬───────────┘
               NO             YES
                │              │
       100 % of pool      Locked share × pool ──► investors
       ──► investors      the rest ──► BitPatagonia
```

1. **Reserve:** 5 % of a positive month stays in the company. A negative month (e.g. the month-49
   overhaul) pays nothing and **does not carry forward**: the company absorbs it.
2. **Until capital is recovered:** 100 % of the pool goes to investors until cumulative payouts
   equal the amount contributed (1.0× hurdle). Nominal, no interest.
3. **The ratchet:** in the month recovery completes, investors' share of everything afterwards is
   fixed **once and for all**:

   | Recovery month | Share |
   |---|---|
   | 29 or earlier | 27.508 % |
   | 30 | 28.579 % |
   | 31 | 29.649 % |
   | 32 | 30.719 % |
   | 33 | 31.789 % |
   | 34 | 32.860 % |
   | 35 | 33.930 % |
   | 36 or later | 35.000 % |

   In words: if the project takes longer than 29 months to pay back, investors get a larger share
   (1.07 points per month of delay, capped at 35 %).
4. **After recovery:** each month investors receive `share × pool`; the rest belongs to
   BitPatagonia (Category B in kind + Category A) and never touches the token.

Every payout is split **pro rata** among holders by their balances at the moment of deposit.

### Base-case example (hashprice 0.040 USD/TH/day)

| | |
|---|---|
| Net cash flow, month 1 | USD 323,784 |
| 5 % reserve | USD 16,189 |
| Pool | USD 307,594 → 100 % to investors |
| Capital recovered | month 29 |
| Locked share | 27.508 % |
| Investor receipts over 8 years | USD 19.7 M (2.03× contribution, excluding residual value) |

The model's ten hashprice scenarios (0.020 to 0.050) live in `test_vectors/`; the code reproduces
them to the cent.

### In practice

- **Subscription:** during the window a whitelisted investor sends USDC and receives tokens 1:1.
  If the minimum (USD 9.72 M) is not reached by the deadline everything is refunded. More than the
  minimum may be raised (up to the configured cap): the project scales up.
- **Monthly:** BitPatagonia publishes a signed report (2 of 3 signers including an external
  auditor), deposits the investors' share in USDC and records the report hash on-chain. The contract
  applies the waterfall and snapshots balances.
- **Claiming:** each holder claims whenever they like; claims never expire.
- **Transfers:** only between whitelisted addresses, subject to issuer-set lock-ups and
  jurisdiction rules. The issuer can freeze accounts and execute forced transfers under a court
  order, always with a public on-chain record.

---

## Technical

### Layout

```
params.json                 economic parameters (source of truth, from the Excel model)
deploy/params.units.json    integer form (USDC units, bps, WAD) consumed by contracts — generated
model/                      Excel model v7
test_vectors/               month-by-month expected payouts: base case + 10 hashprice scenarios
reference/waterfall.py      Python reference: exact-decimal (Excel) and integer (Solidity) modes
reference/tests/            pytest: vectors, workbook at full precision, property tests
contracts/                  Foundry project
  src/libraries/Waterfall.sol   the business math (pure library) — mirrored by waterfall.py
  src/ComplianceRegistry.sol    KYC whitelist, freeze, lock-up, jurisdiction tables
  src/BPToken.sol               permissioned ERC-20, 6 dp, block checkpoints, pause, forceTransfer
  src/Subscription.sol          USDC in, 1:1 mint, soft/hard cap, refunds
  src/Distribution.sol          monthly deposit + report hash, waterfall, snapshot, claims
  script/                       DeployRaise (phase 1) · DeployDistribution (phase 2, after close)
  test/                         vectors fed from the CSVs, unit, fuzz, end-to-end
reporting/report.py         monthly CLI: signed report → distributable → deposit amount + hash → ledger
dashboard/                  static page (ethers.js) — raise status, months, claimable, claim
deploy/                     chain configs, local dry run, deployment records
```

### Run the tests

```bash
uv sync --group dev --group reporting && uv run pytest -v
```

```bash
cd contracts && forge test -vv
```

```bash
deploy/local-dry-run.sh      # anvil: both deploy phases, a raise, month 1 via the CLI, claims
```

### Precision

- USDC amounts: integer units (6 dp), floor division. Dust (< 1 unit per holder per month) stays in
  `Distribution` and is reported by `unclaimed()`.
- Shares: 18-decimal fixed point (WAD). `base_share = 275083875385142000` — basis points would
  drift ~8 USD/month from the model. The ratchet is computed as
  `base + (max − base) × k / 7` with `k = clamp(month − 29, 0, 7)`, exact at both ends.
- Hurdle: `raise × 1.0`, where `raise` is the token supply actually sold, read on-chain at
  `Distribution` construction. If more than USD 9.72 M is raised, re-derive `investor_base_share`
  in `params.json` (it is `raise / post-money`) before deploying phase 2; the script refuses
  otherwise.

### Roles

| Role | Holder | Can |
|---|---|---|
| `DEFAULT_ADMIN_ROLE` | 48 h `TimelockController` (issuer Safe proposes/executes) | grant/revoke roles |
| `ISSUER_ROLE` (token) | issuer Safe | pause, unpause, forceTransfer |
| `REGISTRAR_ROLE` (registry) | KYC operations key | whitelist, freeze, lock-ups, jurisdiction tables |
| `REPORTER_ROLE` (distribution) | 2-of-3 Safe incl. auditor | monthly deposit |
| `minter` (token) | `Subscription`, set once | mint during the raise, burn on refund, finalize |

No proxies, no upgrade path, no owner-only escape hatches. Migration = new deployment + snapshot.

### Deploy

1. Copy `deploy/config.example.json` → `deploy/config.base.json`, fill the Safe/registrar/treasury
   addresses, window, caps.
2. `uv run python -m reference.params_units` (regenerates `deploy/params.units.json` if
   `params.json` changed).
3. Phase 1: `cd contracts && DEPLOY_CONFIG=../deploy/config.base.json forge script script/DeployRaise.s.sol --rpc-url $RPC --broadcast --verify`
4. Whitelist investors (`ComplianceRegistry.setHolders`), run the raise, `Subscription.close()`.
5. Phase 2: `DEPLOY_CONFIG=../deploy/config.base.json forge script script/DeployDistribution.s.sol --rpc-url $RPC --broadcast --verify`
6. Publish `deploy/deployment.<chainId>.json` and the ledger next to `dashboard/index.html`.

### Monthly operation

```bash
uv run python -m reporting.report compute reports/2027-01.json
```

Prints the deposit amount and report hash, verifies the 2-of-3 EIP-191 signatures over the report
hash, appends to the public ledger. The reporter Safe then approves USDC and calls
`Distribution.deposit(month, distributable, usdcAmount, reportHash)`; the contract recomputes the
waterfall and rejects any other amount.
