Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: [Mintlify] Add Slinky Docs #257

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: 'build-docs'
on:
push:
branches: ['main']
pull_request:
branches: ['main']
workflow_dispatch:

defaults:
run:
shell: bash

jobs:
build-docs:
runs-on: ubuntu-latest
steps:
- name: Trigger mintlify workflow
if: github.event_name == 'push'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.DOCS_CHILDREN_ACTIONS_TRIGGER_TOKEN }}
script: |
await github.rest.actions.createWorkflowDispatch({
owner: 'mintlify-onboarding',
repo: 'skip',
workflow_id: 'mintlify-action.yml',
ref: 'main',
});
88 changes: 88 additions & 0 deletions docs/incentivize-slashing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
title: 'Incentivization & Slashing'
---

## 🤝 Validators and Slinky[​](#-validators-and-slinky 'Direct link to heading')

✅ **Validators are the lifeblood of Slinky operation** - Slinky is a restaking product. This means it reuses all available network stake of a protocol to secure oracle operation. To do this, validators need to run the infrastructure required for Slinky to operate.

✅ **Validators do this by running the Slinky Sidecar** - Slinky comes with a highly optimized and reliable piece of software called the Sidecar, which validators run in tandem with chain binaries to fetch prices safely and reliably.

✅ **Validators benefit from running Slinky** - Validators can (should!) be rewarded for doing more for the chains they operate on. To accomplish this, Slinky can providet `fee-sharing` for validators who honestly operate the oracle. Fees can come from trading activity, inflation, or other mechanisms.

✅ **Validators can be punished for misuse** - As they are with the consensus process, validators can be punished if they don't report prices or report incorrect prices. As long as validators follow the correct operation guides and act honestly, this should never happen. To ensure its accuracy, Slinky has two prebuilt mechanisms to enable slashing.

## 💰 Reward Mechanism[​](#-reward-mechanism 'Direct link to heading')

- When Slinky is integrated, it can assign per-block rewards to validators who operate it correctly. Correct operation means:
- posting prices reliably
- posting correct prices

Rewards can come from various sources. The easiest to implement is an additional share of inflation yield. However, Slinky also can support sharing of trading-fees and any arbitrary source of revenue.

<Note>

We Share Everything

Skip is dedicated to rewarding validators. For any fees a chain agrees to pay Skip for Slinky operation, we share 20% of this with the validators who operate it.

</Note>

With fee sharing, a fixed amount of fees is shared **per-block** to validators that correctly operate Slinky.

- This means, if `$1000` was allocated for a certain block, and only 10 validators correctly operated Slinky that block, each validator would recieve an additional `$100` on top of their block rewards.

Note that the Slinky reward is **additional** to normal validator commission.

## 📉 Downtime slashing[​](#-downtime-slashing 'Direct link to heading')

Slinky comes prebuilt with the optional `x/sla` module, which enforces a minimum Service-Level Agreement (SLA) on validators and is verified on-chain.

See the code here: [https://github.com/skip-mev/slinky/tree/main/x/sla](https://github.com/skip-mev/slinky/tree/main/x/sla)

The SLA module is designed to issue a (small) slash whenever a validator doesn't meet the uptime SLA for a specific price feed over a moving window of blocks. For example, with an SLA set to `80%` for a currency pair (e.g. `ETH/USDC`) over a block-window of `100`, then:

- Every block, the `x/sla` module will find how many blocks in the past `100` each validator posted a price.
- If the percentage of blocks with prices is less than `80%`, then the validator is issued a small slash, proportional to their stake-weight.
- This process repeats until the validator is hitting the SLA.
- All these parameters, and the module itself, are initiated and set by governance. They are `OFF` by default.

For new currency pairs, there is a "grace period" that can be configured in case validators need to make updates. Correct operation should be simple and heavily assisted by Skip: our intention is for downtime slashing to never impact any validator.

Here is a rundown of the parameters for `x/sla`:

- `MaximumViableWindow` (e.g. `100` )
- This is the **window of blocks from head** that are evaluated to determine the uptime a validator had.
- For example, if set to `100` , the chain will look at every rolling window of `100` blocks to determine what percentage of the blocks the validator included a price update in their vote extension
- `ExpectedUptime` (e.g. `0.8` )
- This is the percentage of uptime expected from all validators for a specific currency pair. This is evaluated every `Frequency` number of blocks, and the check will be roughly `ExpectedUptime >= (NumBlocksWithUpdates / MaximumViableWindow)`
- `SlashConstant` (e.g. `6` )
- This is a constant amount of stake to slash every `Frequency` of blocks if the SLA is not being kept.
- In the case of SLA breach, the final amount to be slashed would be roughly `SlashConstant * StakeWeight(Validator)` . This would repeat every `Frequency` number of blocks that a specific validator breached the SLA
- `MinimumBlockUpdates` (e.g. `20` )
- This is a safety mechanism to avoid double-slashing validators experiencing overall downtime.
- This value represents the minimum number of blocks within the `MaximumViableWindow` that a validator needs to sign before the overall Oracle SLA kicks in.
- For example, if in `100` blocks a validator was only live & signing for `10` , if the `MinimumBlockUpdates` is set to `20` , then the validator will not be subject to Oracle SLA slashing penalties.
- This is useful for preventing slashing around chain upgrades, when multiple validators might be offline at once.
- `Frequency` (e.g. `10` )
- This is the number-of-block cadence when the SLA is checked for every validator for a specific price feed.
- This is mostly used to save computation resources - with a long `MaximumViableWindow` , we recommend increasing the `Frequency` to be upwards of `1` to save node resources.
- `MinStakeWeightToSlash` (e.g. `0.66` = 66% of stake weight)
- This is the minimum cumulative stake weight of validator price reports that is required before **any** slashing happens. This constitutes the "grace period" when a new currency pair is added and validators are getting set up.

## ❌ Incorrect-price slashing[​](#-incorrect-price-slashing 'Direct link to heading')

Downtime is serious, but not as serious as the network reporting incorrect prices. To prevent this, we have an exact replica of the **[ChainLink Town Crier](https://blog.chain.link/town-crier-and-chainlink/)** mechanism implemented as the `x/alerts` module.

The `x/alerts` module does not slash individual mistakes or one-off errors. It activates when a permissionless `alerter` raises an alarm that the **entire network** has reported an incorrect price. The `alerter` has to post a `bond`, which is money they put up and legitimizes their claim.

The `alert` raised is then forwarded to a `Concluder` network of trusted actors who can verify the validity of the `alert`.

- If the `alert` is deemed invalid (i.e. the network's prices **were** close enough to the best-effort prices that the `concluder` network can fetch), then the `alerter` bond is seized and distributed to validators.
- If the `alert` is deemed valid (i.e. the network's prices are **very different** from the best-effort prices that the `concluder` network can fetch), then all participating validators in the incorrect price are slashed, and the alerter receives the slashed amount.

This process is not designed to be even a remotely common occurrence. Slashing is a serious event, and the network should only slash in the event network prices are completely incorrect. As with the `x/sla` module, everything is defaulted to `OFF`, and all parameters are decided by governance.

For chains that wish to enable `x/alerts`, please contact us so we can help you implement it correctly. It is a highly sophisticated and nuanced system.

![](/images/slinky-town-crier.png)
82 changes: 82 additions & 0 deletions docs/overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: 'Overview'
---

<Frame>![](/images/slinky-banner.png)</Frame>

<Info>
Block SDK

Slinky is **business-licensed software** under BSL. It is source viewable, but [**reach out to us**](https://skip.money/contact) to us if you are interested in integrating! We are limiting the number of chains we work with to seven in 2024. We apologize if we run out of capacity.

Visit the GitHub repo [here](https://github.com/skip-mev/slinky).

For support, [**join our discord**](https://skip.money/discord)!

</Info>

<Frame>![](/images/slinky_customers.png)</Frame>

## 🦾 Slinky Features[​](#-slinky-features 'Direct link to heading')

✅ **Runs on the chain validator set** - Slinky leverages the chain’s security, giving the fastest updates possible, and removing the requirements for any 3rd party systems.

✅ **Highly performant** - Slinky can support over 2000 currency pairs and price feeds, allowing the launch of thousands of permissionless on-chain markets.

✅ **Full operational support** - comes with a 1-day SLAs for adding new feeds, and 24/7 on-call support and maintenance by the Skip team.

✅ **Better Application UX** - by leveraging new advancements in consensus like vote extensions & ABCI++, Slinky guarantees a millisecond-fresh oracle update every block, allowing applications to build without sacrificing UX for safety.

## 🏎️ The Slinky Sidecar[​](#️-the-slinky-sidecar 'Direct link to heading')

- The Slinky sidecar is an out-of-process service that efficiently fetches prices from various data sources and runs aggregation logic to combine them into a single price for each feed.
- Validators use GRPC requests to the sidecar to fetch the latest updates to update on-chain prices from over 20+ providers.

![Sidecar](/images/sidecar-18cc25dad8b4ca6d0ac7afc01b7511e0.svg)

## ⚡️ On-chain aggregation[​](#️-on-chain-aggregation 'Direct link to heading')

Slinky uses **[ABCI++](https://docs.cometbft.com/v0.37/spec/abci/)** to separate Oracle aggregation and into secure and efficient steps.

![Slinky Architecture](/images/slinky-arch-cbd6c2e4e5b05737441aed9995c278e0.png)

### Extend Vote / Verify Vote[​](#extend-vote--verify-vote 'Direct link to heading')

The `ExtendVote` and `VerifyVote` methods of ABCI++ are where a price is first queried.

- The validators fetch prices from the sidecar from a series of `providers` (e.g. Binance / Coinbase) for each currency pair.
- For each pair, the median is taken between all `providers`.
- Each validator then submits their final prices to the chain via the ABCI++ `ExtendVote` method.
- `VerifyVote` is used to ensure that the submitted data is valid--i.e. it can be unmarshalled by another validator.

### Prepare Proposal[​](#prepare-proposal 'Direct link to heading')

During `PrepareProposal`, the vote extensions from the previous block are aggregated by the block proposer into their block proposal, after various checks are run on them.

- Slinky ensures that the set of vote extensions comprise the required minimum stake required for a price update (default of 2/3).

- It also ensures that the vote extensions are valid and can be understood by the application.

- Finally, it encodes the vote extensions and injects them into the top of the block proposal as a pseudo-transaction ignored by the chain.

![Prepare Proposal](/images/prepare-ab3b2b6898825f3eb78a2c901a9436e8.svg)

For more information on vote extensions in general, refer to **[the Cosmos SDK docs](https://docs.cosmos.network/main/build/abci/vote-extensions)**.

### Process Proposal[​](#process-proposal 'Direct link to heading')

`ProcessProposal` is identical to PrepareProposal, except it is run on every validator to validate the block proposal.

- If the validator comes to the conclusion that the injected votes are valid and comprise the required minimum stake, it will accept the proposal.
- If not, the validator will reject the proposal.

### Finalize Block[​](#finalize-block 'Direct link to heading')

The end of a price's journey is in the `Preblock` step.

- Here, the the injected transaction data is unmarshalled back into vote extensions, and the application takes a stake-weighted median of the prices reported by every validator.
- The resulting canonical price for each pair is stored in the `x/oracle` module and can be queried by any application or RPC.

### Full Flow[​](#full-flow 'Direct link to heading')

- This full set of steps repeats on every block resulting in a continuous stream of guaranteed prices. The oracle is enshrined in the application by the validator set, and so is fundamentally equivalent to chain liveness (i.e. the oracle can't go down without the chain going down)
41 changes: 41 additions & 0 deletions docs/security-properties.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
title: "Security Properties"
---

![](/images/slinky_math.png)

## ⛓️ Overall Assumptions[​](#️-overall-assumptions "Direct link to heading")

✅ **Slinky is as secure as the chain it is deployed on** - This is the meaning of a "restaked" oracle - Slinky leverages all available security that the chain can provide by using the existing validator set and tying updates to consensus via vote extensions.

✅ **Prices require 2/3 participation from validators to be posted on chain** - We require a minimum of 2/3 of stake weight to contribute to a price aggregation for that price to actually update chain state. This is the same stake weight required to commit blocks.

✅ **Slinky avoids any external dependencies** - Slinky injects price data directly into the chain it's deployed on. This means there's no additional chain, token, relayer, or other outside actor dependency. The same operators that run the chain run the oracle.

✅ **Slinky price updates are atomic with liveness** - Since Slinky data is signed atomically with `PreCommit` votes via Vote Extensions, chains can configure their application (or parts of their application) to depend on per-block price updates. This makes almost all forms of oracle attacks impossible, and allows applications to avoid having to build their own UX roadblocks to ensure safety.

## 🔀 Impact of Vote Extensions[​](#-impact-of-vote-extensions "Direct link to heading")

Slinky updates by having over 2/3 of the validator set (by stake weight) suggest a series of prices, and then aggregates across them using a stake-weighted median. This price data is committed to the chain by validators through [vote extensions](https://docs.cosmos.network/main/build/abci/vote-extensions).

Vote extensions are arbitrary metadata that is signed atomically with a validator's `PreCommit` vote. In Slinky's case, that metadata is locally observed prices for a series of `CurrencyPairs` (e.g. `ETH/USDC`).

Given blocks cannot progress without 2/3 of stake weight submitting votes, blocks also cannot progress without 2/3 of vote extensions. Additionally, the `x/oracle` module (where prices are stored on chain) requires at least 2/3 of voting power to have contributed to individual price updates. This means that every price update has the same participation as block validity itself.

## 👺 Manipulation Thresholds[​](#-manipulation-thresholds "Direct link to heading")

In the standard configuration of Slinky, it requires `1/3` of stake to be manipulated to post an incorrect oracle price. This is because:

* `2/3` of stake is required to post any update (as described above)
* half of that stake must be manipulated to post incorrect prices in the _same direction_ to move the stake-weighted median final price posted on-chain
* That is, (`2/3 / 2 = 1/3`) of stake must be manipulated to post a malicious price.

However, Slinky can support additional constraints to increase this level to `2/3` of stake. To do this, the final on-chain prices are re-checked by all validators on the network in the `ProcessProposal` step to enforce some minimum deviation from their local prices are not exceeded. `2/3` of stake weight is required to vote "yes" on this check, raising the overall security back to that of the chain itself.

There are tradeoffs to increasing the security to this level. Validators may reject proposals more often if there is high volatility in price updates between them, which could result in longer periods of oracle downtime in periods of crypto market instability.

## 🎖️ Importance of Operational Excellence[​](#️-importance-of-operational-excellence "Direct link to heading")

Security assumptions, no matter how good, are no substitute for the oracle operators (the chain's validator set) keeping high uptime, reliable, and accurate price updates. Slinky makes this easy for validators, providing an ample amount of operational support and tooling for alerting, upgrading, and maintaining the Slinky sidecar. We work with operators from respected oracles like [ChainLink](https://chain.link/) to ensure validators replicate best practices.

Operational excellence is heavily tied to incentivization and disincentivization mechanisms imposed on operators. Please read our section on [Incentivization & Slashing](https://docs.skip.money/slinky/slashing) for more info.
Loading
Loading