Data Flow

This page explains how data moves through the NMT platform, from a user clicking "Deposit" to seeing their position value update.

Transaction Flow: Safe Mode (Writing to Blockchain)

When a delegate executes a DeFi strategy through a user's Safe:

1. Delegate clicks "Deposit $1,000 into Aave" in the frontend
        |
2. Frontend builds an array of BundlerCalls
   (approve USDC + supply USDC, encoded via DeFi adapters)
        |
3. Frontend reads nonce + EIP-712 domain from DelegateBundler contract
        |
4. Delegate signs an EIP-712 typed message:
   { callsDataHash, nonce, deadline }
        |
5. Frontend encodes DelegateBundler.execute(delegate, deadline, calls, signature)
        |
6. Frontend sends the encoded calldata to Gelato Relay API
   (server-side, using GELATO_API_KEY via Next.js server action)
        |
7. Gelato's relayer (0xC4E7...6888) submits the tx on-chain
   and PAYS THE GAS — the delegate/user pays nothing
        |
8. On-chain: DelegateBundler.execute() runs:
   a) Verifies the delegate's EIP-712 signature
   b) Checks nonce (replay protection) and deadline (expiry)
   c) Loops through each call in the bundle:
      → AaveModule._checkPermission(safe, delegate, "APPROVE")
      → AaveModule._checkPermission(safe, delegate, "DEPOSIT")
      → Each module calls Safe.execTransactionFromModule()
        |
9. Blockchain emits events (Supply, Transfer, etc.)
        |
10. Backend workers detect the events and update PostgreSQL
        |
11. Frontend reads updated position from DB on next page load

Where Gelato Fits

Gelato is an off-chain transaction relay service. It is NOT a smart contract in the execution path. Its role:

  • Receives the fully-encoded transaction calldata from the frontend (via relay.sponsoredCall())
  • Submits it on-chain from Gelato's own relayer address
  • Pays gas on behalf of the user (NMT's Gelato account covers the cost)
  • Reports status back to the frontend (ExecSuccess, ExecReverted, Cancelled)

The frontend polls Gelato's task status API every 3 seconds (up to 15 attempts) to confirm execution.

Frontend (browser)
    |
    | 1. encodeExecute() → raw calldata
    v
Next.js Server Action (server-side)
    |
    | 2. GelatoRelay.sponsoredCall(calldata, GELATO_API_KEY)
    v
Gelato Relay Network (off-chain)
    |
    | 3. Submits tx from relayer address, pays gas
    v
Blockchain → DelegateBundler.execute() → Modules → Safe

Transaction Flow: EOA Mode (Writing to Blockchain)

When a user trades directly from their wallet (no Safe):

1. User clicks "Withdraw from Aave" in the frontend
        |
2. Frontend encodes the withdraw calldata via DeFi adapter
        |
3. walletClient.sendTransaction({ to: aavePool, data: ... })
   User signs directly and pays their own gas
        |
4. Transaction lands on-chain (no bundler, no modules, no permissions)
        |
5. Blockchain emits events → Backend indexes → DB updated

Data Indexing Flow (Reading from Blockchain)

The backend continuously monitors the blockchain for relevant events:

Blockchain (Base, Ethereum, Arbitrum, Optimism)
        |
        | WebSocket subscription (Alchemy WSS)
        | + Periodic RPC polling (dRPC HTTPS)
        v
Backend Workers
        |
        |--- DefiWorkerPool: per-protocol pool services
        |    (fetches pool metadata, TVL, APY)
        |    (every 30 min for most, every 2 min for Uniswap V3/V4)
        |
        |--- PositionCoordinator:
        |    |--- LogListener: real-time WebSocket events
        |    |--- LogProcessor: parses events, stores positions
        |    |--- GapFiller: backfills missed blocks + valuation recalcs (every 24h)
        |
        |--- PriceFetcher: on-demand token prices (CoinGecko)
        |    (called by other workers as needed, not a background worker)
        |
        v
PostgreSQL
        |
        |--- nmt_pool: pool-level data (APY, TVL, tokens)
        |--- nmt_position: user positions (status, amounts)
        |--- nmt_position_valuation: USD value snapshots
        |--- price: token price history
        |--- apy_history: historical APY data

Frontend Data Sources

The frontend pulls data from multiple sources depending on the use case:

Data Type Source Method Why
User settings, Safe configs PostgreSQL Prisma (server components) Fast, no API hop needed
Pool listings, APYs Backend API HTTP REST (/api/v1/pools) Aggregated by backend workers
Token balances Blockchain Viem RPC calls Real-time accuracy
Portfolio history Zerion API HTTP REST Rich historical data
Token prices CoinGecko / Backend HTTP REST Price feeds
Chat messages CometChat WebSocket SDK Real-time messaging

Update Frequencies

Data Update Interval Source
Pool metadata (most protocols) Every 30 minutes Backend workers
Pool metadata (Uniswap V3/V4) Every 2 minutes Backend workers
Position valuations Every 24 hours Backend workers
Token prices On-demand + cached CoinGecko API
Subscription status Every 1 hour Backend workers
User balances Real-time on page load Blockchain RPC

EOA Position Tracking

EOA (direct wallet) positions are not tracked by the backend workers. The backend's position detection relies on events emitted by NMT's custom protocol modules (PositionOpened, PositionClosed, etc.), which only fire during Safe-based execution via the DelegateBundler.

For EOA users, the frontend relies on Zerion API to provide portfolio data — token balances, DeFi positions, and transaction history. Zerion independently indexes all major DeFi protocols and returns position data for any Ethereum address.

Mode Position Source Valuation Source
Safe (delegate) Backend workers (on-chain events → PostgreSQL) Backend workers (periodic valuation snapshots)
EOA (direct wallet) Zerion API Zerion API

This means EOA positions do not appear in the nmt_position table and are not included in backend-computed analytics. The frontend bridges this gap at the display layer by merging data from both sources.

results matching ""

    No results matching ""