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

Update docs #91

Merged
merged 43 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
2eb1a64
Update top-level documentation
ethanfrey Jun 28, 2023
6d5887b
Start updating provider docs
ethanfrey Jun 28, 2023
1a4a40d
Fix syntax / links
maurolacy Jun 30, 2023
754bc93
Add ExternalStaking stub
maurolacy Jun 30, 2023
8ff32db
Fix Vault doc syntax
maurolacy Jun 30, 2023
663dcb3
Improve Vault docs
maurolacy Jul 4, 2023
37eba0f
Update / complete Vault doc Transitions
maurolacy Jul 4, 2023
b703c8d
Update Local Staking Transitions
maurolacy Jul 5, 2023
e25bf9f
Update External Staking transitions / API
maurolacy Jul 5, 2023
5008f5c
Improve Consumer syntax
maurolacy Jul 5, 2023
4b778e5
Improve Converter syntax
maurolacy Jul 5, 2023
0dbefc7
Update Converter Setup section
maurolacy Jul 5, 2023
c95c174
Update Converted doc
maurolacy Jul 6, 2023
472357d
Add Provider Setup section
maurolacy Jul 6, 2023
0f77b41
Move Consumer Setup section to Consumer.md
maurolacy Jul 6, 2023
f2b5a39
Update README (remove TODO)
maurolacy Jul 6, 2023
ff3e1c4
Update Rewards Flow section
maurolacy Jul 6, 2023
2bc1bac
Add Rebalancing Flow section
maurolacy Jul 6, 2023
d48a4d2
Update IBC Control Channel doc
maurolacy Jul 7, 2023
500cce3
Update converter IBC comments
maurolacy Jul 7, 2023
eb9ed32
Update IBC Overview doc
maurolacy Jul 7, 2023
5efd348
Improve Serializability doc syntax
maurolacy Jul 7, 2023
47357f5
Improve Slashing doc syntax
maurolacy Jul 7, 2023
2322a02
Update docs/UseCases.md
maurolacy Jul 7, 2023
290da7a
Update docs/consumer/Consumer.md
maurolacy Jul 7, 2023
c1b1b67
Update docs/ibc/ControlChannel.md
maurolacy Jul 7, 2023
cb3a9a4
Update docs/consumer/Converter.md
maurolacy Jul 7, 2023
09b0ce9
Add note about required wasmd version
maurolacy Jul 10, 2023
15a1c51
Rewrite Consumer contracts requirements section
maurolacy Jul 10, 2023
b469a8e
Clarify gov auth to mint / burn
maurolacy Jul 10, 2023
1cefda6
Clarify IBC conn / channel setup
maurolacy Jul 10, 2023
957b070
Clarify connection vs channel establishment
maurolacy Jul 10, 2023
9224e32
Clarify Consumer / Provider flows
maurolacy Jul 10, 2023
912c465
Remove refs to 'vouchers' for clarity
maurolacy Jul 10, 2023
0dafad8
Add empty version variant
maurolacy Jul 10, 2023
01cdd46
Clarify admin roles / perms
maurolacy Jul 10, 2023
0ce7fac
General syntax corrections
maurolacy Jul 10, 2023
7b10d83
Flesh out the Rewards doc
maurolacy Jul 10, 2023
1f5f190
Point to ControlChannel doc for channel establishment section
maurolacy Jul 10, 2023
52a572a
Fix / Use local links
maurolacy Jul 10, 2023
590de3e
Fix: s/Receiver/Provider/
maurolacy Jul 10, 2023
618f70f
Fix typos
maurolacy Jul 10, 2023
9aef3bb
Fix links / details
maurolacy Jul 10, 2023
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
6 changes: 3 additions & 3 deletions contracts/consumer/converter/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ const DEFAULT_VALIDATOR_TIMEOUT: u64 = 24 * 60 * 60;
const DEFAULT_REWARD_TIMEOUT: u64 = 60 * 60;

pub fn packet_timeout_validator(env: &Env) -> IbcTimeout {
// No idea about their blocktime, but 24 hours ahead of our view of the clock
// No idea about their block time, but 24 hours ahead of our view of the clock
// should be decently in the future.
let timeout = env.block.time.plus_seconds(DEFAULT_VALIDATOR_TIMEOUT);
IbcTimeout::with_timestamp(timeout)
}

pub fn packet_timeout_rewards(env: &Env) -> IbcTimeout {
// No idea about their blocktime, but 1 hour ahead of our view of the clock
// No idea about their block time, but 1 hour ahead of our view of the clock
// should be decently in the future.
let timeout = env.block.time.plus_seconds(DEFAULT_REWARD_TIMEOUT);
IbcTimeout::with_timestamp(timeout)
Expand Down Expand Up @@ -196,7 +196,7 @@ pub fn ibc_packet_receive(
}

#[cfg_attr(not(feature = "library"), entry_point)]
/// We get acks on sync state without much to do.
/// We get ACKs on sync state without much to do.
/// If it succeeded, take no action. If it errored, we can't do anything else and let it go.
/// We just log the error cases so they can be detected.
pub fn ibc_packet_ack(
Expand Down
2 changes: 1 addition & 1 deletion contracts/provider/external-staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ impl ExternalStakingContract<'_> {
}
}

/// Withdraws all released tokens to the sender.
/// Withdraws all of their released tokens to the calling user.
///
/// Tokens to be claimed have to be unbond before by calling the `unbond` message, and
/// their unbonding period must have passed.
Expand Down
4 changes: 2 additions & 2 deletions contracts/provider/external-staking/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ pub struct StakeInfo {
pub stake: Uint128,
}

/// Aggregated mutiple stakes response
/// Aggregated multiple stakes response
#[cw_serde]
pub struct StakesResponse {
pub stakes: Vec<StakeInfo>,
}

/// Message to be send as `msg` field on `receive_virtual_staking`
/// Message to be sent as `msg` field on `receive_virtual_staking`
#[cw_serde]
pub struct ReceiveVirtualStake {
pub validator: String,
Expand Down
4 changes: 2 additions & 2 deletions contracts/provider/vault/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub struct VaultContract<'a> {
pub local_staking: Item<'a, LocalStaking>,
/// All liens in the protocol
///
/// Liens are indexed with (user, creditor), as this pair has to be unique
/// Liens are indexed with (user, lien_holder), as this pair has to be unique
pub liens: Map<'a, (&'a Addr, &'a Addr), Lockable<Lien>>,
/// Per-user information
pub users: Map<'a, &'a Addr, Lockable<UserInfo>>,
Expand Down Expand Up @@ -685,7 +685,7 @@ impl VaultContract<'_> {
/// Updates the local stake for unstaking from any contract
///
/// The unstake (both local and remote) is always called by the staking contract
/// (aka lienholder), so the `sender` address is used for that.
/// (aka lien_holder), so the `sender` address is used for that.
fn unstake(&self, ctx: &mut ExecCtx, owner: String, amount: Coin) -> Result<(), ContractError> {
let denom = self.config.load(ctx.deps.storage)?.denom;
ensure!(amount.denom == denom, ContractError::UnexpectedDenom(denom));
Expand Down
76 changes: 41 additions & 35 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ simplifications used for MVP (testnet) or v1 (production-ready, feature-limited)
as footnotes in the documents.

```mermaid
%%{init: {'theme': 'forest'}}%%
flowchart TD
%%{init: {'theme': 'forest'}}%%

subgraph Osmosis
A{{$OSMO}} -- User Deposit --> B(Vault);
B -- $OSMO --> C(Local Staker);
Expand All @@ -25,25 +24,28 @@ flowchart TD
end

subgraph Juno
I(Price Oracle) -- price feed --> M;
J(Price Oracle) -- price feed --> N;

M(Osmosis Converter) -- virtual stake --> O(Virtual Staking 1);
N(Akash Converter) -- virtual stake --> P(Virtual Staking 2);
O & P -- $JUNO --> Q[Native Staking];
end

G -. IBC .-> R;
G -. IBC .-> T;

subgraph Stargaze
R{{Osmosis Receiver}} -- virtual stake --> S(Virtual Staking);
S -- $STARS --> T[Native Staking];
S(Price Oracle) -- price feed --> T;
T{{Osmosis Converter}} -- virtual stake --> U(Virtual Staking);
U -- $STARS --> V[Native Staking];
end

```

You can get a good overview of the whole system flow in the above diagram.
The design should allow one chain to provide security to multiple chains, while
at the same time receiving security from multiple chains.

A key to understanding the design, is that the whole system is _delegator-centeric_
A key to understanding the design, is that the whole system is _delegator-centric_
not _validator-centric_. This means that we don't try to match the same validators on
multiple chains, or even subsets, but rather focus on leveraging the security
provided by staking tokens to secure validators on multiple chains. This provides a way to
Expand All @@ -63,9 +65,9 @@ Addressing some common points people raise up, which are hidden in the docs.

There are many questions if this isn't "fractional reserve banking" or such.
This does use the same collateral to back multiple claims (staking), but
the [final invariant in the vault](https://github.com/osmosis-labs/mesh-security/blob/main/contracts/vault/README.md#invariants)
the [final invariant in the vault](./provider/Vault.md#invariants)
ensures there is sufficient collateral to cover the maximum loss
(eg. if all local and cross-staked validators double-sign).
(e.g. if all local and cross-staked validators double-sign).
If the double slash penalty is 5%, you can safely cross stake 20x.
If it were to be raised to say 40%, you could only safely cross stake 2.5x
This is more like insurance companies holding reserves for the worse cases expected losses,
Expand All @@ -74,18 +76,18 @@ not the total value of all property insured.
### Power Limits on Remote Chains

Another common concern is whether there are effective limits in the power a remote
chain can exert over one chain. Would it be possible for a higher cap chain (eg $ATOM)
chain can exert over one chain. Would it be possible for a higher cap chain (e.g. $ATOM)
to take over more than one-third, or even two-thirds or the power of a smaller cap chain
(eg $STARS) it is cross-staking on.
(e.g. $STARS) it is cross-staking on.

Clearly the consumer chain wants to put some limits. The first limit is the
[discount applied during the conversion](https://github.com/osmosis-labs/mesh-security/blob/main/docs/consumer/Converter.md#price-normalization).
[discount applied during the conversion](./consumer/Converter.md#price-normalization).
This doesn't just provide margin for price fluctuations but also means that on average
a remote token has less voting power (and rewards) per USD-value than a local token, favoring
local stakers.

In addition, the Virtual Staking module enforces a
[max cap per provider](https://github.com/osmosis-labs/mesh-security/blob/main/docs/consumer/VirtualStaking.md#module).
[max cap per provider](./consumer/VirtualStaking.md#interface).
This limits how many virtual tokens a given provider can stake.
For computational reasons, it is defined as a number of tokens, not a percentage of stake,
but looking at an average number of local tokens staked, the chain governance on
Expand All @@ -94,6 +96,9 @@ This max cap can be updated by governance as needed, so if a lot more (or less)
tokens are staked, the max cap of the providers can be updated with a gov vote to
keep them in reasonable limits.

Please [look at the use cases](./UseCases.md) to see the use of max cap in some example scenarios
to gain a better intuition of how it works.

### Failure Modes

There are three main failure modes to consider:
Expand All @@ -105,17 +110,17 @@ There are three main failure modes to consider:
#### Huge Price Swing

This is the most likely scenario. If the provider price rises too much, it may suddenly have
disproportionate power over the affairs of the consumer. If the provier price falls too much,
disproportionate power over the affairs of the consumer. If the provider price falls too much,
in the period until the price oracle is updated, there may be less remote collateral
than the virtual stake.

For price increases, we have the max cap described under "Power Limits" which places a cap
on the provider chain's influence in all circumstances, so this isn't a large problem.

For a rapid price decrease, we must consider the time frame.
It is a [requirement of an oracle](https://github.com/osmosis-labs/mesh-security/blob/main/docs/consumer/Converter.md#price-feeds)
It is a [requirement of an oracle](./consumer/Converter.md#price-feeds)
to provide timely feeds, say once a day or week, so we should focus on the relative price movement
in such a period. [The discount](https://github.com/osmosis-labs/mesh-security/blob/main/docs/consumer/Converter.md#price-normalization)
in such a period. [The discount](./consumer/Converter.md#price-normalization)
provides such a buffer. If there is a discount of 40% and the provider tokens drop 30% relative to
the consumer tokens in one oracle epoch, then it is still over-collateralized relative to voting power.
If, however, it falls 60%, then it would only have 2/3 of the collateral locked on the provider
Expand All @@ -130,7 +135,7 @@ max cap limit preventing total takeover, so it just provides overly high rewards
#### Byzantine Provider Chain

The worst case is the provider claims to deposit millions of tokens on one malicious validator,
while not actually locking any collateral on it's own chain. This is similar to the case of
while not actually locking any collateral on its own chain. This is similar to the case of
a hostile community on the provider chain selecting validators against the interest of the
community on the consumer chain.

Expand All @@ -149,18 +154,18 @@ perceived stability.
If a Consumer Chain goes Byzantine (or starts some mob-rule governance proposals), it can
try to damage stake on the Provider chain. There are several ways it can try to do so:

- Withholding all rewards to said Provider
- Removing all voting power from said Provider
- Refusing to unlock the virtual stake of the Provider
- Unfairly slashing virtual stake from the Provider
- Withholding all rewards to said Provider.
- Removing all voting power from said Provider.
- Refusing to unlock the virtual stake of the Provider.
- Unfairly slashing virtual stake from the Provider.

The first two are temporary and can be seen in the case when the consumer no longer trusts the
provider and sets "max cap" to zero. This is a temporary effect but must be acknowledged as
a possible risk, which is loss of benefits, but not loss of collateral.

The third point is impossible, as the unlock period is implemented between the external staking
contracts and the vault on the provider side. Nothing on the Consumer can lock up stake longer.
And if a Provider feels they have unfairly withhold benefits (first two points), they could
And if a Provider feels they have unfairly withheld benefits (first two points), they could
make a governance vote to allow immediate unbonding of all cross-stake to that consumer.

The last point is a bit trickier. We will not fully define slashing until v1, but the design is
Expand All @@ -174,7 +179,9 @@ such a condition without the Validators fault. It would require hacks deep into
(not the custom ABCI app) and a governance upgrade to direct the validators to use it, and we
generally consider this unlikely (it has never been observed in 4+ years of the Cosmos).

## Definitions
## Glossary

Some common terms are defined here, which may be used throughout the documentation.

- **Pairing** - a trust relationship between two chains, such that one promises to lock up slashable
stake, while the other leverages this promise to issue validation power in the dPoS system.
Expand All @@ -194,7 +201,7 @@ generally consider this unlikely (it has never been observed in 4+ years of the
based on misbehavior of that validator.
- **Unbonding period** - The time delay between initiating unbonding and having free access to the
underlying collateral. Once this time has passed after unstaking, all claims on the underlying
collateral are released and
collateral are released.
- **Rewards** - Block rewards are issued to validators in the native token of the consumer chain.
A portion of these rewards goes to the stakers and is collected cross-chain.
- **Slashing** - If a validator misbehaves, the tokens delegated to it, which provided the
Expand All @@ -205,7 +212,7 @@ generally consider this unlikely (it has never been observed in 4+ years of the
prevented from returning. Tokens staked to it would be partially slashed and should be unstaked
as soon as possible, as they will receive no more rewards. Stake to a jailed validator still must
wait the unbonding period to be liquid.
- **Latency** - Time delay from an action being initiated and the effects being reflected in
- **Latency** - Time delay from an action being initiated and its effects being reflected in
another contract or chain. This doesn't refer to the unbonding period, but rather the delay between
initiating bonding or unbonding on the provider and the equivalent action occurring on the consumer.

Expand All @@ -215,19 +222,18 @@ Below are links to detailed documents on various sub-systems:

[Provider](./provider/Provider.md):

- [Vault](./provider/Vault.md)
- [Local Staking](./provider/LocalStaking.md)
- [External Staking](./provider/ExternalStaking.md)
- TODO - Rust interfaces
- [Vault](./provider/Vault.md).
- [Local Staking](./provider/LocalStaking.md).
- [External Staking](./provider/ExternalStaking.md).

[Consumer](./consumer/Consumer.md):

- [Converter](./consumer/Converter.md)
- [Virtual Staking](./consumer/VirtualStaking.md)
- SDK Changes
- [Converter](./consumer/Converter.md).
- [Virtual Staking](./consumer/VirtualStaking.md).
- SDK Changes.

[IBC Protocol](./ibc/Overview.md):

- [Cross-Chain Staking](./ibc/Staking.md)
- [Reward Flow](./ibc/Rewards.md)
- [Handling Slashing Evidence](./ibc/Slashing.md)
- [Cross-Chain Staking](./ibc/Staking.md).
- [Reward Flow](./ibc/Rewards.md).
- [Handling Slashing Evidence](./ibc/Slashing.md).
67 changes: 48 additions & 19 deletions docs/UseCases.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Use Cases

We assume each chain has a native staking token denom, with some quantity (could be 1 or 1,000,000,000).
This is the initial token to start the chain with. Each provider chain that connects may mint up to a maximum of X virtual tokens,
defined by consumer governance when authorizing the new provider. The ratio between the amount of native tokens
and the max cap of virtual tokens on each provider is a key element in defining the various security models.

To make these diagrams easier to read, I will normalize each chain has 100 native tokens, and label the
connections on how many virtual tokens they are authorized to mint. Thus, a connection with 100 could
exert the same amount of voting power as all native stakers. A connection with 10 could exert 10% of the
power of native stakers, and a connection of 1000 could exert 10 times the power of native stakers.

(Note that these are not clear percentages. 40 / (100 + 40) = 28.5% of the total power in the hands of that provider).

## Sibling Chains

Two chains of similar size want to support each other.
Expand All @@ -9,8 +21,8 @@ larger -> smaller has more weight than smaller -> larger.
```mermaid
flowchart LR
%%{init: {'theme': 'forest'}}%%
A(Juno) -- 40% --> B(Star);
B -- 20% --> A;
A(Juno) -- 40 --> B(Star);
B -- 20 --> A;
```

## Full Mesh
Expand All @@ -27,32 +39,40 @@ so the weights are proportional to their relative market caps.
```mermaid
flowchart LR
%%{init: {'theme': 'forest'}}%%
A(OSMO) == 50% ==> B(Juno);
A == 50% ==> C(Akash);
B -- 20% --> C;
C -- 20% --> B;
B -- 10% --> A;
C -- 10% --> A;
A(OSMO) == 60 ==> B(Juno);
A == 60 ==> C(Akash);
B -- 20 --> C;
C -- 20 --> B;
B -- 10 --> A;
C -- 10 --> A;
```

## DAOs migrating to own chain
You could analyze Juno in this example:
100 native, 60 from Osmosis, 20 from Akash = 180 total.
Osmosis hits the 1/3 threshold exactly, while native tokens still hold the majority in the governance votes.
Does that make sense, should this be adjusted?

## DAOs migrating to their own chain

A number of Juno DAOs launching their own chains. They want to inherit most of their security from Juno,
but keep governance to their own token.

```mermaid
flowchart TD
%%{init: {'theme': 'forest'}}%%
Juno -- 75%, no gov --> DAO1;
Juno -- 75%, no gov --> DAO2;
Juno -- 75%, no gov --> DAO3;
Juno -- 300, no gov --> DAO1;
Juno -- 300, no gov --> DAO2;
Juno -- 300, no gov --> DAO3;
```

Note that less than 1/3 power is in the native token, so all PoS security relies on Juno (while all governance security relies
on the DAO token).

## Almost Replicated Security

Mesh Security is not ICSv1 "Replicated Security". We do not map validators from provider to consumer, but rather delegators.
And the power is the subset of staked tokens that opt-in, so will always be lower than full stake. By design we always require
a native staking token in the consumer chain, but we can approximate "replciated security" for the "fully owned subsidiary"
And the power is the subset of staked tokens that opt-in, so will always be lower than full stake. By design, we always require
a native staking token in the consumer chain, but we can approximate "replicated security" for the "fully owned subsidiary"
use case.

You can launch a chain with a governance token with minimal distribution to bootstrap the chain. Then accept another chain as a
Expand All @@ -62,9 +82,14 @@ of the chain, including gov votes. The end effect is the new chain is almost 100
```mermaid
flowchart TD
%%{init: {'theme': 'forest'}}%%
Juno -- 99%, gov --> Eve;
Juno -- 10000, gov --> Eve;
```

The native token is just used in bootstrapping, to make setup and deployment simple.
However, at around 1% of the power, it quickly becomes irrelevant, and makes this a close approximation of "replicated security".
You could just reduce the native supply to 1 solo token and then this gets like 99.9999% replicated security, but with a much
clearer setup phase.

## Credibly Neutral Common Good

There are some items that should be neutral or independent of multiple chains,
Expand All @@ -74,8 +99,12 @@ control the staking and governance, even without any native staking power.
```mermaid
flowchart TD
%%{init: {'theme': 'forest'}}%%
A(OSMO) --> |25%| N[Name Service];
B(Juno) -- 25% --> N;
C(Stargaze) -- 25% --> N;
D(Cosmos Hub) -- 25% --> N;
A(OSMO) --> |10000| N[Name Service];
B(Juno) -- 10000 --> N;
C(Stargaze) -- 10000 --> N;
D(Cosmos Hub) -- 10000 --> N;
```

All participating chains have the same power. The native token is almost irrelevant (100 / 40100 = 0.25% of the power)
and can be ignored. It is essential, however, for bootstrapping and getting up the chain until all the provider chains have
connected and sufficient amount of cross-stakers have joined from those chains.
Loading
Loading