---
# System prepended metadata

title: Ethereum API endpoints

---

# Ethereum API endpoints

## The goal

- Take the backend part of staking widget into a dedicated project and take it for support.
- Add additional pools APR endpoints.
- Ensure continuous and user-friendly work with the endpoints.
- Make the solution scalable to other teams/blockchains.
- Have documentation on the process of writing and deploying new endpoints.

## Requirements

- Available for internal use without restrictions
- Available for external teams
- Can handle a large number of concurrent requests
- Has docs and an OpenAPI Specification
- Has versioning of endpoints for backward compatibility
- Provides monitoring and alerting for:
    - the application work
    - work of third-party services
    - data correctness

## Endpoints

In the first iteration, it's suggested that only ethereum endpoints be put into a separate project. In the next iteration, we can do the same for the Terra endpoints. 

- [Protocol APRs](#Protocol-APRs)
- [Pool APRs](#Pool-APRs)
- [Token prices](#Token-prices)
- [Token TWAPs](#Token-TWAPs)
- [Token stats](#Token-stats)

### Protocol APRs

- Ethereum APR. Implementations: [previous](https://github.com/lidofinance/staking-widget-ts/blob/develop/pages/api/apr.ts), [current](https://github.com/lidofinance/staking-widget-ts/blob/main/pages/api/eth-apr.ts)
- stETH APR. [Current implementation](https://github.com/lidofinance/staking-widget-ts/blob/main/pages/api/steth-apr.ts)

:::spoiler URLs example
```
/v1/protocol/eth/apr
/v1/protocol/steth/apr
```
:::

:::spoiler Response example
```json
{
    data: [
        {
            APR: 5.1,
            timeUnix: 1643800000
        }
    ],
    meta: {
        symbol: "stETH",
        address: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84",
        chainId: 1
    }
}
```
:::
 

Since it's supposed to store historical data, it's worth making it possible to retrieve it for a certain period. It is proposed to add the possibility to specify the start and end time of the sampling for most of the endpoints.

:::spoiler Query parameters example

```
/v1/protocol/eth/apr?startTime=1643800000&endTime=1643900000
```
:::
 

Since there may be a lot of data, it is worth providing some limits or pagination. For the first iteration we can limit the period to 30 days
 

### Pool APRs

There is no current implementation for pools APRs. Endpoints are supposed to be used for the new section in the staking widget, similar to the [solana widget](https://solana.lido.fi/defi). It would be useful to have in the response: TVL, daily trading volume, detailed information about incentives.


- 1inch v2
- Balancer v2
- Curve
- SushiSwap

:::spoiler URLs example
```
/v1/pool/1inch/steth-eth/apr
/v1/pool/balancer/wsteth-weth/apr
/v1/pool/curve/steth-dai/apr
/v1/pool/sushi-swap/wsteth-dai/apr
```
:::

:::spoiler Quiery parameters example

```
/v1/pool/1inch/steth-eth/apr?startTime=1643800000&endTime=1643900000
```
:::

:::spoiler Response example
```json
{
    data: [
        {
            totalAPR: 12.345,
            totalAPY: 12.456,
            totalValueLockedInUsd: 1234567.89,
            dayTradingVolume: 10000,
            incentives: [
                {
                    id: 1,
                    type: 'steth',
                    active: true,
                    apr: 2.3
                },
                {
                    id: 2,
                    type: 'fees',
                    active: true,
                    apr: 0.1
                },
                {
                    id: 3,
                    type: 'rewards',
                    active: true,
                    apr: 2.48
                },
                // ...
            ],
            timeUnix: 1643800000,
        }
    ],
    meta: {
        pool: {
            address: "0xDC24316b9AE028F1497c275EB9192a3Ea0f67022",
            lpToken: {
                name: "Curve.fi ETH/stETH",
                symbol: "steCRV",
                address: "0x06325440d014e39736583c165c2963ba99faf14e",
            },
            tokens: [
                {
                    symbol: "ETH",
                    address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
                },
                {
                    name: "Liquid staked Ether 2.0",
                    symbol: "stETH",
                    address: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84"
                }
            ],
        },
        links: [
            // Not sure about this section, 
            // probably it's the responsibility of the UI
            {
                url: "https://curve.fi/steth",
                type: 'swap',
            },
            {
                url: "https://curve.fi/steth/deposit",
                type: 'deposit',
            }
        ],
        incentives: {
            1: {
                 token: {
                    name: "Lido DAO Token",
                    symbol: "LDO",
                    address: "0x5a98fcbea516cf06857215779fd812ca3bef1b32"
                }
            }
        },
        chainId: 1,
    }
}
```
:::
 

Useful links:
- The calculations can be taken from [Dune dashboard](https://dune.xyz/LidoAnalytical/Integration-monitor-dashboard)
- [Incentives for LPs](https://www.notion.so/D2110INV-Incentives-for-LPs-Dashboard-fd415f29e58541088a761715bd5604bd)
- [Liquidity pools contracts](https://docs.lido.fi/deployed-contracts#liquidity-pools)
- [Reward program contracts](https://docs.lido.fi/deployed-contracts#reward-programs)

:::warning
There may be a situation where the reward program has finished, but has not yet started. Since the results are supposed to be cached, such a case should be handled carefully.
:::

### Token prices

Current implementation: https://replit.com/@irinalido/TWAPhourly#main.py

In current implementation we use third-party service (api.coingecko.com) to get the data. This is ok for the first version, but later it is worth getting the data directly from the blockchain.

:::spoiler URLs example
```
/v1/token/steth/price
/v1/token/ldo/price
```
:::

:::spoiler Response example
```json
{
    data: [
        {
            priceUSD: 2.01,
            timeUnix: 1643800000
        }
    ],
    meta: {
        symbol: "stETH",
        address: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84",
        chainId: 1
    }
}
```
:::

### Token <abbr title="Time-weighted average price">TWAP</abbr>s

See [Token prices](#Token-prices) section

:::spoiler URLs example
```
/v1/token/steth/twap
/v1/token/ldo/twap
```
:::

:::spoiler Response example
```json
{
    data: [
        {
            priceUSD: 2.01,
            timeStartUnix: 1643800000,
            timeEndUnix: 1644404800
        },
        {
            priceUSD: 2.1,
            timeStartUnix: 1643800000,
            timeEndUnix: 1646392000
        }
    ],
    meta: {
        symbol: "stETH",
        address: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84",
        chainId: 1
    }
}
```
:::



### Token stats

Detailed information about Lido tokens. In current implementation we use third-party service (api.ethplorer.io) to get the data. This is ok for the first version, but later it is worth getting the data directly from the blockchain.

- stETH. Implementations: [current](https://github.com/lidofinance/staking-widget-ts/blob/main/pages/api/lidostats.ts), [short](https://github.com/lidofinance/staking-widget-ts/blob/main/pages/api/short-lido-stats.ts)
- LDO. [Current implementation](https://github.com/lidofinance/staking-widget-ts/blob/main/pages/api/ldo-stats.ts)

:::spoiler URLs example
```
/v1/token/steth/stats
/v1/token/ldo/stats
```
:::

:::spoiler Response example
https://stake.lido.fi/api/lidostats
https://stake.lido.fi/api/ldo-stats
:::


## Implementation

The implementation is supposed to be based on the [API template](https://github.com/lidofinance/lido-api-template). The template was designed to our requirements and our infrastructure and already contains most of the necessary modules:
- JSON logs
- Prometheus metrics
- Swagger
- Versioning of endpoints
- Throttling
- CORS headers
- Response caching

### Instances

It's suggested that one application be deployed in two instances. One copy for internal use, and one copy for external use. For public use, request throttling will be enabled. Internal service is closed with API keys. 

For the first iteration we can have only one instance with throttling.

### Data availability

#### Results storage

Since in some cases the calculations may take a long time or the data provider may not be available at all, it's suggested to separate the calculations and the server response. The results of the calculations should be placed in the DB and read from there when requested. This approach will also allow us to have access to historical data.

#### Proposed design

```sequence
    Cron job-->API Provider: Request required data
    API Provider->Cron job: Result
    Note over Cron job: Calculating
    Cron job->Database: Store calculating result
    Controller-->Database: Request last\ncalculation result
    Database->Controller: Result
```

It was discussed for Solana that it would be useful to be able to set pools APRs manually. In case we use the database, in an emergency situation, we can correct the record.

There can be two solutions here:
1. Implement endpoints to add and delete a custom value.
2. Add UI to the database, with HTTP authorization. We can use [Adminjs](https://adminjs.co/) for this.

When using a custom value, an alert should be triggered.

#### Fetching

Most of the data can be retrieved directly from the blockchain using services such as Infura. Since from time to time we have problems with availability of certain API providers, it's assumed that we have a fallback provider to which we switch if the first one is unavailable. For this we already have a [fetcher with fallbacks and retries](https://github.com/lidofinance/lido-nestjs-modules/tree/main/packages/fetch).

### Data correctness

In order to track anomalies in the results of calculations, it's assumed that we provide these values as metrics and track minor and major changes with alerts.

### Tests

It's suggested that at least the calculations be covered by tests to be sure that the result is in the acceptable range of values.

### Networks

It's suggested that the app is integrated into our infrastructure with the standard deploy scheme:

```flow
testnet=>operation: Testnet
staging=>operation: Staging
mainnet=>operation: Mainnet

testnet(right)->staging(right)->mainnet
```

For the testnet we can use Goerli and the single [liquidity pool](https://docs.lido.fi/deployed-contracts/#reward-programs-1).
