# Smart Contract Architecture

***

## Contract Overview

EcoRound's on-chain logic consists of two contracts. `FactoryMatch` is a singleton registry deployed once. `VaultMatch` is deployed once per match — one fresh contract per esports game.

```mermaid
flowchart TD
    subgraph Actors
        OWNER([👤 Admin / Owner])
        ORACLE([🔮 Chainlink CRE Oracle])
        USER([👥 Users])
    end

    subgraph Contracts["On-Chain — Base (Tenderly Fork)"]
        FM["FactoryMatch 0x9ee1...f582─────────────createMatch() getVault() setOracle()"]

        VM1["VaultMatch #1SEN vs NRG─────────────deposit()lockMatch()resolveMatch()claim()"]

        VM2["VaultMatch #2 C9 vs 100T"]
        VM3["VaultMatch #3 ..."]

        MORPHO["Morpho ERC4626 0x050c...56f0 Yield Vault"]
        USDC["USDC 0x8335...2913 Deposit Token"]
    end

    OWNER -->|createMatch| FM
    FM -->|deploys one per match| VM1
    FM -->|deploys one per match| VM2
    FM -->|deploys one per match| VM3

    USER -->|approve + deposit| VM1
    USER -->|claim payout| VM1

    ORACLE -->|lockMatch resolveMatch| VM1

    VM1 <-->|deposit / redeem| MORPHO
    VM1 <-->|transferFrom / transfer| USDC

    style FM fill:#1a1a3a,stroke:#7B68EE,color:#ccc
    style VM1 fill:#1a2a1a,stroke:#00E6C3,color:#ccc
    style VM2 fill:#1a2a1a,stroke:#00E6C3,color:#ccc
    style VM3 fill:#1a2a1a,stroke:#00E6C3,color:#ccc
    style MORPHO fill:#2a1a2a,stroke:#FF4655,color:#ccc
    style USDC fill:#2a2a1a,stroke:#FFB800,color:#ccc
```

***

## VaultMatch State Machine

Every VaultMatch moves through a strict one-way lifecycle. State transitions are enforced at the contract level — no one can skip a phase or reverse.

```mermaid
stateDiagram-v2
    [*] --> Open : FactoryMatch.createMatch()

    Open --> Locked : oracle → lockMatch() USDC moved to Morpho

    Open --> Cancelled : admin pause + emergencyRefund

    Locked --> Resolved : oracle → resolveMatch(winner) Morpho redeemed + yield split

    Locked --> Cancelled : admin pause + emergencyRefund

    Resolved --> [*] : users call claim() funds fully distributed

    Cancelled --> [*] : all users refunded 100% principal returned
```

***

## How FactoryMatch and VaultMatch Interact

```mermaid
sequenceDiagram
    actor Admin
    participant FM as FactoryMatch
    participant VM as VaultMatch (new)
    participant DB as API Database

    Admin->>FM: createMatch("Sentinels", "NRG")
    FM->>VM: deploy new VaultMatch(matchId, teamA, teamB, oracle)
    VM-->>FM: deployed at 0xabc...
    FM->>FM: vaults[matchId] = 0xabc...
    FM-->>Admin: emit MatchCreated(1, 0xabc..., "Sentinels", "NRG")

    Admin->>DB: POST /admin/matches {vault_address: "0xabc...", on_chain_match_id: 1}
    DB-->>Admin: match record saved
```

***

## Contract Security Model

```mermaid
flowchart LR
    subgraph Modifiers["Access Control"]
        OO["onlyOwner createMatch setOracle pause/unpause emergency fns"]
        OOR["onlyOracle lockMatch resolveMatch ─────────────── oracle EOA owner() Keystone Forwarder"]
        RG["ReentrancyGuard deposit claim"]
        WP["whenPaused emergencyWithdraw emergencyRefund"]
    end

    subgraph Guarantees["Protocol Guarantees"]
        G1["Principal always returned claim() always pays ≥ deposit"]
        G2["One-way state machine no reverting phases"]
        G3["No rug pull owner cannot redirect funds"]
    end

    OO & OOR & RG & WP --> Guarantees

    style OO fill:#1a2a1a,stroke:#00E6C3,color:#ccc
    style OOR fill:#1a1a3a,stroke:#7B68EE,color:#ccc
    style RG fill:#3a1a1a,stroke:#FF4655,color:#ccc
    style WP fill:#2a2a1a,stroke:#FFB800,color:#ccc
```

***

## CRE Report Routing

The Keystone Forwarder is whitelisted directly in `onlyOracle`. When a CRE report arrives, `onReport()` decodes the 4-byte selector and calls the matching public function:

```
Keystone Forwarder
  └─ onReport(metadata, report)          ← IReceiver interface
       └─ _processReport(report)
            ├─ bytes4(report) == lockMatch.selector
            │    └─ lockMatch()           ← same function panel-v2 calls
            └─ bytes4(report) == resolveMatch.selector
                 └─ resolveMatch(winner)  ← ABI-decoded from report[4:]
```

This means both the CRE path (Keystone Forwarder) and the admin path (panel-v2 EOA) execute the exact same `lockMatch()` / `resolveMatch()` logic with no duplication.


---

# Agent Instructions: 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:

```
GET https://eco-round.gitbook.io/eco-round-docs/technical-details/smart-contract-architecture.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
