|
| 1 | +# COINPAPRIKA_STATE |
| 2 | + |
| 3 | +The Coinpaprika State adapter streams **state_price** for supported pairs via **Server-Sent Events (SSE)** streaming. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Environment Variables |
| 8 | + |
| 9 | +| Variable | Description | Type | Required | Default | |
| 10 | +| :---------------------: | ---------------------------------------------------- | :----: | :------: | :-------------------------------------------------: | |
| 11 | +| `API_KEY` | Coinpaprika API key (sent as `Authorization` header) | string | ✅ | — | |
| 12 | +| `API_ENDPOINT` | Coinpaprika streaming endpoint (POST) | string | | `https://chainlink-streaming.dexpaprika.com/stream` | |
| 13 | +| `BACKGROUND_EXECUTE_MS` | Background loop interval for pair set evaluation | number | | `3000` | |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Endpoint |
| 18 | + |
| 19 | +**Name:** `coinpaprika-state` (alias: `state`) |
| 20 | + |
| 21 | +### Input Parameters |
| 22 | + |
| 23 | +| Name | Required | Aliases | Description | Type | Example | |
| 24 | +| :--------: | :------: | -------------- | ------------------ | ------ | :---------------------------: | |
| 25 | +| `base` | ✅ | `coin`, `from` | Base asset symbol | string | `LUSD`, `ALETH`, `CBETH` | |
| 26 | +| `quote` | ✅ | `market`, `to` | Quote asset symbol | string | `USD`, `ETH` | |
| 27 | +| `endpoint` | | | Endpoint selector | string | `coinpaprika-state` / `state` | |
| 28 | + |
| 29 | +### Example Requests |
| 30 | + |
| 31 | +**Using the primary endpoint `coinpaprika-state`** |
| 32 | + |
| 33 | +```bash |
| 34 | +curl -X POST http://localhost:8080 \ |
| 35 | + -H "Content-Type: application/json" \ |
| 36 | + -d '{"data":{"base":"LUSD","quote":"USD","endpoint":"coinpaprika-state"}}' |
| 37 | +``` |
| 38 | + |
| 39 | +**Using the alias `state`** |
| 40 | + |
| 41 | +```bash |
| 42 | +curl -X POST http://localhost:8080 \ |
| 43 | + -H "Content-Type: application/json" \ |
| 44 | + -d '{"data": {"base": "LUSD", "quote": "USD", "endpoint": "state"}}' |
| 45 | +``` |
| 46 | + |
| 47 | +**Without endpoint (uses default)** |
| 48 | + |
| 49 | +```bash |
| 50 | +curl -X POST http://localhost:8080 \ |
| 51 | + -H "Content-Type: application/json" \ |
| 52 | + -d '{"data": {"base": "LUSD", "quote": "USD"}}' |
| 53 | +``` |
| 54 | + |
| 55 | +### Example Response |
| 56 | + |
| 57 | +```json |
| 58 | +{ |
| 59 | + "data": { |
| 60 | + "result": 1.000979, |
| 61 | + "timestamp": 1758888503 |
| 62 | + }, |
| 63 | + "statusCode": 200, |
| 64 | + "result": 1.000979, |
| 65 | + "timestamps": { |
| 66 | + "providerDataRequestedUnixMs": 1758888508939, |
| 67 | + "providerDataReceivedUnixMs": 1758888508939, |
| 68 | + "providerIndicatedTimeUnixMs": 1758888503000 |
| 69 | + }, |
| 70 | + "meta": { |
| 71 | + "adapterName": "COINPAPRIKA_STATE", |
| 72 | + "metrics": { |
| 73 | + "feedId": "{\"base\":\"lusd\",\"quote\":\"usd\"}" |
| 74 | + } |
| 75 | + } |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +## Streaming Data |
| 82 | + |
| 83 | +### Streaming Method Selection: Multiple Assets via POST (Sessionless) |
| 84 | + |
| 85 | +Per the “EA Requirements – Coinpaprika State” doc, Coinpaprika offers: |
| 86 | + |
| 87 | +1. **Single Asset via GET** — simple but requires one connection per pair |
| 88 | +2. **Multiple Assets via POST (Sessionless)** — ✅ **SELECTED APPROACH** |
| 89 | +3. **Multiple Assets via Session** — requires session management overhead |
| 90 | + |
| 91 | +### Streaming Data Response |
| 92 | + |
| 93 | +> Numeric values may arrive as **strings**; the adapter coerces them to numbers and skips malformed JSON frames. |
| 94 | +
|
| 95 | +The adapter receives real-time data from Coinpaprika in the following format: |
| 96 | + |
| 97 | +```text |
| 98 | +data:{ |
| 99 | + "block_time":1758892511, |
| 100 | + "send_timestamp":1758892514, |
| 101 | + "base_token_symbol":"ALETH", |
| 102 | + "quote_symbol":"USD", |
| 103 | + "volume_7d_usd":190502.190952, |
| 104 | + "market_depth_plus_1_usd":0.000000, |
| 105 | + "market_depth_minus_1_usd":0.000000, |
| 106 | + "state_price":3835.519084 |
| 107 | +} |
| 108 | +event:t_s |
| 109 | +
|
| 110 | +data:{ |
| 111 | + "block_time":1758892487, |
| 112 | + "send_timestamp":1758892514, |
| 113 | + "base_token_symbol":"EURA", |
| 114 | + "quote_symbol":"USD", |
| 115 | + "volume_7d_usd":36039.253665, |
| 116 | + "market_depth_plus_1_usd":0.000000, |
| 117 | + "market_depth_minus_1_usd":0.000000, |
| 118 | + "state_price":1.158675 |
| 119 | +} |
| 120 | +event:t_s |
| 121 | +
|
| 122 | +data:{ |
| 123 | + "block_time":1758892511, |
| 124 | + "send_timestamp":1758892515, |
| 125 | + "base_token_symbol":"LUSD", |
| 126 | + "quote_symbol":"USD", |
| 127 | + "volume_7d_usd":23434.612065, |
| 128 | + "market_depth_plus_1_usd":0.000000, |
| 129 | + "market_depth_minus_1_usd":0.000000, |
| 130 | + "state_price":1.000883 |
| 131 | +} |
| 132 | +event:t_s |
| 133 | +``` |
| 134 | + |
| 135 | +--- |
| 136 | + |
| 137 | +## Architecture |
| 138 | + |
| 139 | +### Transport |
| 140 | + |
| 141 | +`CoinpaprikaStateTransport` (extends framework `SubscriptionTransport`) |
| 142 | + |
| 143 | +- **Single SSE connection** for all active pairs |
| 144 | +- **Dynamic pair batching**; reconnects when the pair set changes |
| 145 | +- **Malformed event tolerance** (skips bad JSON frames, keeps last good value) |
| 146 | +- **Numeric coercion** for `state_price` & `block_time` (string → number) |
| 147 | +- **Error mapping**: `401/400/429` passthrough, `500 → 502`, **no data → 504** |
| 148 | +- **Graceful shutdown** + reconnect backoff with jitter |
| 149 | + |
| 150 | +### Data Flow |
| 151 | + |
| 152 | +1. **Background Handler** monitors requested pairs and manages SSE connection |
| 153 | +2. **SSE Parser** handles chunked event streams (`src/transport/sse.ts`) |
| 154 | +3. **Processing** (`src/transport/coinpaprika-state.ts`) normalizes symbols, coerces numbers, validates payloads, and writes to the response cache |
| 155 | +4. **Serving requests** returns the latest cached tick for the requested pair |
| 156 | + |
| 157 | +### Error Handling |
| 158 | + |
| 159 | +| Provider Status | Adapter Status | Description | |
| 160 | +| :-------------: | :------------: | :-------------------------------------- | |
| 161 | +| `401` | `401` | Unauthorized | |
| 162 | +| `400` | `400` | Bad Request | |
| 163 | +| `429` | `429` | Rate Limited | |
| 164 | +| `500` | `502` | Bad Gateway - Provider error | |
| 165 | +| No data yet | `504` | Foreground fallback when cache is empty | |
| 166 | + |
| 167 | +--- |
| 168 | + |
| 169 | +## Development |
| 170 | + |
| 171 | +### Build |
| 172 | + |
| 173 | +```bash |
| 174 | +yarn workspace @chainlink/coinpaprika-state-adapter build |
| 175 | +``` |
| 176 | + |
| 177 | +### Start |
| 178 | + |
| 179 | +```bash |
| 180 | + API_KEY="your-api-key-here" yarn start coinpaprika-state |
| 181 | +``` |
| 182 | + |
| 183 | +### Test |
| 184 | + |
| 185 | +```bash |
| 186 | +# Integration |
| 187 | +yarn test packages/sources/coinpaprika-state/test/integration/adapter.test.ts |
| 188 | + |
| 189 | +# Unit |
| 190 | +yarn test packages/sources/coinpaprika-state/test/unit/sse.test.ts |
| 191 | +``` |
| 192 | + |
| 193 | +--- |
| 194 | + |
| 195 | +## Notes |
| 196 | + |
| 197 | +- **First-tick latency**: Until the first valid tick is cached, foreground requests may return `504`. |
| 198 | +- **Symbol normalization**: `base`/`quote` are uppercased; stick to canonical symbols. |
| 199 | +- **Numeric coercion**: Provider may send numerics as strings; invalid numerics are dropped. |
0 commit comments