Skip to content

Commit

Permalink
Merge pull request #80 from nimiq/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
onmax authored Dec 13, 2024
2 parents b0dc460 + e18e42b commit cfefd7a
Show file tree
Hide file tree
Showing 26 changed files with 6,278 additions and 188 deletions.
143 changes: 61 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,75 @@
<h1 align="center">Nimiq Validators</h1>

<p align="center">
<a href="https://validators-api-mainnet.pages.dev">
<img src="./public/favicon.svg" alt="Nimiq Validators" width="64" />
<a id="README" href="#README" href="https://github.com/nimiq/core-rs-albatross/blob/albatross/README.md">
<img src="https://raw.githubusercontent.com/nimiq/developer-center/refs/heads/main/assets/images/logos/validators-API.svg" alt="Nimiq PoS Albatross Repository" width="600" />
</a>
</br>
</br>

[![Sync Mainnet](https://github.com/nimiq/validators-api/actions/workflows/sync-mainnet.yml/badge.svg)](https://github.com/nimiq/validators-api/actions/workflows/sync-mainnet.yml) [![Sync Testnet](https://github.com/nimiq/validators-api/actions/workflows/sync-testnet.yml/badge.svg)](https://github.com/nimiq/validators-api/actions/workflows/sync-testnet.yml)

<p align="center">
Details of validators in the Nimiq Blockchain and their scores, calculated using Nimiq's VTS algorithm.
<p>
The Nimiq Validators API enables staking pools, based on single validators, to integrate with the Nimiq Wallet and other applications. This helps stakers make informed decisions when choosing where to stake their funds.

[![Sync Mainnet](https://github.com/nimiq/validators-api/actions/workflows/sync-mainnet.yml/badge.svg)](https://github.com/nimiq/validators-api/actions/workflows/sync-mainnet.yml)
[![Sync Testnet](https://github.com/nimiq/validators-api/actions/workflows/sync-testnet.yml/badge.svg)](https://github.com/nimiq/validators-api/actions/workflows/sync-testnet.yml)
**Validators and Staking Pools**:
A validator can operate as a staking pool, allowing multiple users to stake. Pools must provide detailed information such as fees, payout schedules, and contact details to ensure trust and transparency.

## Add your validator information
Stakers can evaluate a validator’s reliability using the Validator Trust Score (VTS) and review staking pool details like payout schedules to select the best option.

If you run your own validator and want it to be recognized, you can add a name, logo and other publicly available fields. For example, the Nimiq Wallet will use this information to display your validator to users.
## Add your Validator Information

In order to do so, follow these steps:
If you operate a staking pool and want to be displayed in the Nimiq Wallet, follow these steps:

1. [Fork this repository](https://github.com/nimiq/validators-api/fork).
2. Create a new file in the [validators folder](./public/validators/main-albatross).
3. Read the [Recommendations for Writing Your Validator Information](#recommendations-for-your-validator-information)
4. Learn about the [JSON schema](#validator-json-schema)
5. Submit a PR to this repo. Someone in the team will review it.
6. Once the PR is submitted, check that the [API endpoint](https://validators-api-mainnet.nuxt.dev/api/v1) is returning your information. It can take a few minutes.
2. Add your Validator File:
- Create a new JSON file in the `public/validators/main-albatross` directory.
- Use the provided example template in the directory to structure your data.
3. Review the [Description Guidelines](#recommendations-for-your-validator-information).
4. Learn about the [JSON Schema](#validator-json-schema).
5. Submit a PR to this repository. A Nimiq team member will review your submission within 3 days.
6. Once the PR is submitted, check that the [API endpoint](https://validators-api-mainnet.nuxt.dev/api/v1) returns your information. This process may take a few minutes.

> [!WARNING]
> Nimiq reserves the right to make minor adjustments to the content submitted by validator owners, if deemed necessary.
> Nimiq reserves the right to make minor adjustments to the content submitted by validator owners if necessary.
### Recommendations for Your Validator Information
### Recommendations for your Validator Description

#### Description

This information will be displayed in mainly the wallet to help stakers decide which pool they want to stake in. Use this opportunity to make a great impression:

- **Length**: Keep it short and to the point - 1-2 sentences, ideally 20-40 words.
- **Be concise and clear**: Highlight what makes your pool stand out. Focus on stakeholder values such as reliability, transparency or low fees.
- **Play to your strengths**: Mention features such as high uptime, low fees, strong community support or environmentally friendly practices.
- **Avoid financial advice**: Refrain from promising potential returns or financial outcomes.
- **Use a Friendly Tone**: Make your message approachable and welcoming, while maintaining professionalism.

##### Good Example

> "Our pool offers 99.9% uptime, low fees, and strong security, ensuring a seamless staking experience. Join us for a reliable, transparent, and staker-focused service."
##### Bad Example

> "Stake with us for unmatched rewards and the highest profits! Don’t miss your chance to earn big — this is the ultimate opportunity for stakers!"
#### Payout Schedule

- **Use simple and clear language**: Avoid technical terms like "epoch" or "batch."
- **Keep it short**: Aim for 5-8 words.

##### Good Example
This information will be displayed in the wallet to help stakers decide which pool they want to stake in. Providing clear and concise information helps stakers make informed decisions. For complete guidelines and suggestions, check our [Staking Pools Handbook](https://forum.nimiq.community/t/staking-pools-handbook/2169).

> "Every 12 hours"
- **Length**: Aim for 1-2 sentences (20-40 words).
- **Clarity**: Highlight unique aspects of your pool, such as reliability, transparency or low fees.
- **Strengths**: Mention features like high uptime, low fees, strong community support or eco-friendly practices.
- **Tone**: Keep a friendly and professional tone.

##### Bad Example

> "Every 2 epochs"
#### Logo

- **Shape**: It is preferred that the logo follows the Nimiq hexagon shape. For reference, please refer to the bottom of the 'Colours' section of our [Nimiq Style Guide on Figma](<https://www.figma.com/design/GU6cdS85S2v13QcdzW9v8Tav/NIMIQ-Style-Guide-(Oct-18)?node-id=0-1&node-type=canvas&t=mNoervj6Kgw0KhKL-0>).
- **Background**: Do not add a background colour to the image.
- **Format**: Prefer to use SVG. File size isn't an issue as we will optimise and serve the best performing version (e.g. PNG, JPG, SVG) for each validator.
**Good Example**: "Our pool offers 99.9% uptime, low fees, and strong security, ensuring a seamless staking experience. Join us for a reliable, transparent, and staker-focused service."
**Bad Example**: "Stake with us for unmatched rewards and the highest profits! Don’t miss your chance to earn big — this is the ultimate opportunity for stakers!"

### Validator JSON schema

You can use the [example JSON](./public/validators/.example.json) as a template.
Use the following schema to create your validator information file. You can start by copying this [example JSON template](./public/validators/main-albatross/.example.json). When you add your validator information, you'll need to include specific keys in your JSON file. Below is an explanation of each key and its possible values.

When you add your validator information, you'll need to include certain keys in your JSON file. Below is an explanation of each key and its possible values:
**Required Keys**:

- `address` (required): The address of the validator in the format `NQXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX`.
- `fee` (required): A number between 0 and 1 representing the fee percentage charged by your validator. For example, 0.05 represents a 5% fee.
- `payoutType` (required): The method used to pay out validator rewards. Possible values are:
- `name`: The name of your validator. If you don’t provide a name, your validator address will be used by default.
- `description`: A short description of your validator. Use this to highlight what makes your validator unique or appealing to stakers.
- `address`: The address of the validator in this format `NQXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX`.
- `fee`: Use either static or dynamic fees:
- For static fees, use `fee` with a percentage between 0 and 1 (0.05 represents a 5% fee).
- For dynamic fees, use the following 3 values:
- `feeLowest`: The minimum possible fee.
- `feeHighest`: The maximum possible fee.
- `feeDescription`: Outline the conditions for various fees.
- `payoutType`: The method used to payout the rewards. Possible values are:
- `restake`: Rewards are automatically restaked.
- `direct`: Rewards are paid directly into the staker's wallet and are not automatically restaked.
- `direct`: Rewards are paid directly into the staker's wallet and are not automatically restaked. Requires:
- `payoutAddress`: Provide address you will payout from.
- `payoutSchedule`: Specifiy the frequency of payouts using the [cron job format](https://crontab.guru/). Example: `0 */6 * * *` for payouts every 6 hours.
- `none`: No rewards will be paid out.
- `payoutSchedule` (optional): A string to indicate the payout schedule. This could be helpful for users to know when to expect rewards. Any string is valid. e.g: 'Daily', 'Every 12 hours'...
- `name` (optional): The name of the validator. If not specified, the address of the validator is used by default.
- `description` (optional): A short description of your validator.
- `website` (optional): The URL of your validator's website.
- `logo` (optional): An SVG logo representing your pool, encoded in base64 format.
- `accentColor` (optional). Required if `logo` is set. An optional color to align with the validator's branding, defaulting to the identicon background color if left blank. Needs to be in hexadecimal. e.g. '#1f2348'.
- `contact` (optional). An optional field allowing validators to share contact details so users can easily get in touch. The structure would look like this:
- `email` (optional)
- `custom`: Custom payout scheme. Requires:
- `payoutScheme`: A description of the custom payout method (e.g., "Pays 50% of rewards every 1st of the month").
- `website`: The URL of your validator's website or any similar source of information (Telegram pinned message, Discord...)
- `logo`: A logo in SVG or PNG format (min size: 224x224px) with a transparent background, encoded in Base64 to represent your validator. Background colors should be avoided unless they ensure clear contrast.
- `contact`: At least one contact allowing validators to share contact details so users can easily get in touch.
- `email`
- `telegram` (optional). e.g. `@nimiq`
- `twitter` (optional). e.g. `@nimiq`
- `discordInvitationUrl` (optional). A URL to your Discord invitation.
Expand All @@ -99,20 +82,23 @@ When you add your validator information, you'll need to include certain keys in

## Validator Trustscore

- [Read the docs](https://nimiq.com/developers/learn/validator-trustscore).
The VTS is a metric designed to help stakers evaluate the performance and reliability of validators. The VTS provides a transparent way to assess validator behavior, empowering stakers to make informed decisions when choosing where to stake their funds.

The VTS is displayed in the Nimiq Wallet, allowing stakers to compare validators and select the one that best meets their needs.

- [Read the docs](https://nimiq.com/developers/learn/validator-trustscore)
- [See implementation](./packages/nimiq-validators-trustscore/)

## Validators API

| Endpoint | Description |
The Validators API provides endpoints to retrieve validator information for integration with tools, dashboards, and other applications.
| Endpoint | Description |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [/api/v1/validators](https://validators-api-mainnet.pages.dev/api/v1/validators) | Retrieves the validator list. See [query params](./server/utils/schemas.ts#L54) |

## Validators Dashboard

https://validators-api-mainnet.pages.dev/

The dashboard is a simple Nuxt application that displays all validators and their scores.
The Validators Dashboard is a simple Nuxt application that displays all validators along with their trust scores. You can access the dashboard here: https://validators-api-mainnet.pages.dev/

## Development

Expand All @@ -121,22 +107,15 @@ pnpm install
pnpm dev
```

> [!Note]
> We use [Nuxt Hub](https://hub.nuxt.dev) which uses Cloudflare Pages + Cloudflare D1 databases. The database is a sqlite instance and currently the database is remote for both development and production. You can change this behavior in nuxt.config.ts.
We use Drizzle to access the database.

### Calculating the score using Nitro Tasks
### Score Calculation with Nitro Tasks

To calculate the score, we need to run two processes: the fetcher and the score calculator. We do this using a Nitro Task, which is currently an experimental feature of Nitro. Nitro Task is a feature that allows you to trigger an action in the server programmatically or manually from the Nuxt Dev Center(go to tasks page).
To calculate the score, we need to run two processes: the fetcher and the score calculator. We do this using a Nitro Task, which is currently an experimental feature of Nitro. Nitro Task is a feature that allows you to trigger an action in the server programmatically or manually from the Nuxt Dev Center (go to tasks page). Read more about the process of computing the score in the [nimiq-validators-trustscore](./packages/nimiq-validators-trustscore/README.md) package.

Read more about the process of computing the score in the [nimiq-validators-trustscore](./packages/nimiq-validators-trustscore/README.md) package.

#### Database
### Database

As well as storing the [Validator Details](#validator-details), we also store the data produced by the fetcher in a sqlite database. This data is then used in the score calculator to compute the score. You can see the file [schema.ts](./server/database/schema.ts).

## Development
#### Development

Once it is cloned and installed the dependencies, you must run:

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"dev:mainnet:prod": "pnpm run dev:packages && nuxi dev --remote=production --dotenv .env.mainnet",
"dev": "pnpm run dev:packages && nuxi dev --remote --dotenv .env.testnet",
"dev:local": "pnpm run dev:packages && nuxi dev --dotenv .env.local",
"dev:packages": "pnpm --filter=./packages/* --parallel run dev",
"build": "nuxi build",
"dev:packages": "pnpm --filter=./packages/* run dev",
"build": "pnpm --filter=./packages/* run build && nuxi build",
"generate": "nuxi generate",
"preview": "npx nuxthub preview",
"postinstall": "nuxi prepare",
Expand Down
49 changes: 49 additions & 0 deletions packages/nimiq-albatross-policy/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,

// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},

// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
],

// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"css",
"less",
"scss",
"pcss",
"postcss"
]
}
17 changes: 17 additions & 0 deletions packages/nimiq-albatross-policy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Nimiq Albatross Policy

The constants and formulas used to calculate the rewards for staking NIM.

## Installation

```bash
npm install nimiq-albatross-policy
```

## Usage

```ts
import { } from 'nimiq-albatross-policy'

console.log('Rewards:', rewards)
```
12 changes: 12 additions & 0 deletions packages/nimiq-albatross-policy/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
entries: [
'./src/index',
],
declaration: true,
clean: true,
rollup: {
emitCJS: true,
},
})
5 changes: 5 additions & 0 deletions packages/nimiq-albatross-policy/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import antfu from '@antfu/eslint-config'

export default antfu({

})
65 changes: 65 additions & 0 deletions packages/nimiq-albatross-policy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "nimiq-albatross-policy",
"type": "module",
"version": "0.0.1",
"packageManager": "[email protected]",
"description": "The Nimiq Albatross Policy",
"license": "MIT",
"homepage": "https://github.com/nimiq/validators-api#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/nimiq/validators-api.git"
},
"bugs": "https://github.com/nimiq/validators-api/issues",
"keywords": [],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"typesVersions": {
"*": {
"*": [
"./dist/*",
"./dist/index.d.ts"
]
}
},
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
"prepare": "pnpm run build",
"prepublishOnly": "nr build",
"release": "bumpp && npm publish",
"start": "esno src/index.ts",
"typecheck": "tsc --noEmit",
"test": "vitest",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"devDependencies": {
"@antfu/eslint-config": "catalog:",
"eslint": "catalog:",
"esno": "catalog:",
"lint-staged": "catalog:",
"simple-git-hooks": "catalog:",
"typescript": "catalog:",
"unbuild": "catalog:",
"vite": "catalog:"
},
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"
},
"lint-staged": {
"*": "eslint --fix"
}
}
Loading

0 comments on commit cfefd7a

Please sign in to comment.