From 6422a72a132a824aa5319c9048dacbf00b2be052 Mon Sep 17 00:00:00 2001 From: ismellike Date: Thu, 12 Dec 2024 16:39:39 -0600 Subject: [PATCH 1/9] Basics of release_stake doc --- docs/architecture/RELEASE_STAKE.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/architecture/RELEASE_STAKE.md diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md new file mode 100644 index 00000000..ec3aa9ff --- /dev/null +++ b/docs/architecture/RELEASE_STAKE.md @@ -0,0 +1,25 @@ +# Release Stake + +## Overview + +`release_stake` is a message in the restaking system that allows a consumer contract to request immediate release of tokens from its provider contract. + +The basic message structure: +```rust +ReleaseStake { + staker: String, + amount: Uint128, + denom: String, +} +``` + +## Known Requirements + +1. Authorization: + - Only a registered consumer contract can call release_stake on its provider + +2. Message Flow: + - Consumer initiates release_stake to provider + - Provider must validate the request + - Provider updates stake accounting + - Provider may need to clear any unbonding claims From 47a910384e965601eb084f5628fe598954db53a1 Mon Sep 17 00:00:00 2001 From: ismellike Date: Thu, 12 Dec 2024 16:42:16 -0600 Subject: [PATCH 2/9] Add section for contract types State-mutating and pass-through --- docs/architecture/RELEASE_STAKE.md | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index ec3aa9ff..da239097 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -23,3 +23,47 @@ ReleaseStake { - Provider must validate the request - Provider updates stake accounting - Provider may need to clear any unbonding claims + +## Contract Types + +### Pure Pass-Through Contracts +These contracts only authenticate and forward release_stake messages: + +**Token Staking** +- Simply validates consumer +- Forwards message to provider +- No state mutations needed +- No stake transformations + +**Fan In** +- Maps between input/output denominations +- Forwards to correct provider +- No stake amount transformations +- Only maintains denom mapping state + +### State-Mutating Contracts +These contracts must maintain their own stake accounting and potentially transform amounts: + +**Token Weighting** +- Must track weighted stakes +- Need to recalculate ratios +- Maintains complex stake state + +**Delegations** +- Must track delegate proportions +- May need to split release across delegates +- Maintains delegation relationships + +**Fan Out** +- Must handle multiple outputs +- Needs to maintain proportions + +**Splitter** +- Must handle multiple consumers +- Maintains stake proportions +- State for each split + +**Operators** +- Maps between operators and stakers +- Must maintain operator relationships +- Affects operator/staker mappings \ No newline at end of file From 905e6f119c74116fe8455cd700f1f2012330a860 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:54:00 +0200 Subject: [PATCH 3/9] fmt --- docs/architecture/RELEASE_STAKE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index da239097..289182e2 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -16,10 +16,10 @@ ReleaseStake { ## Known Requirements 1. Authorization: - - Only a registered consumer contract can call release_stake on its provider + - Only a registered consumer contract can call `release_stake` on its provider 2. Message Flow: - - Consumer initiates release_stake to provider + - Consumer initiates `release_stake` to provider - Provider must validate the request - Provider updates stake accounting - Provider may need to clear any unbonding claims @@ -27,7 +27,7 @@ ReleaseStake { ## Contract Types ### Pure Pass-Through Contracts -These contracts only authenticate and forward release_stake messages: +These contracts only authenticate and forward `release_stake` messages: **Token Staking** - Simply validates consumer From 200c2fb4ea5865b1ccdc61ca8478d597646b60c7 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:42:03 +0200 Subject: [PATCH 4/9] [no ci] questions about the stake --- docs/architecture/RELEASE_STAKE.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index 289182e2..66d20950 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -66,4 +66,13 @@ These contracts must maintain their own stake accounting and potentially transfo **Operators** - Maps between operators and stakers - Must maintain operator relationships -- Affects operator/staker mappings \ No newline at end of file +- Affects operator/staker mappings + + +## Questions + - when it comes to validating the request by the `provider`, should the `provider` always trust the `consumer's` request (`consumer` is always whitelisted) or the `provider` should do additional validation - eg, check that the request doesn't exceed what's already staked? + - do we allow for partial `release_stake` - eg, a consumer would like to free 1/3 of the staked tokens + - for `token_weighting` contract: what happens when the token-weighting contract receieve a msg to release stake when it's currently calculating new weight? Basically both requests in the same block + - for `fan-out` contract: what if we change the denom and request `release_stake` on the old name? It will fail ofc, but I guess we have to call the old denom name. + - for `operators` contract: that's for the future, but shouldn't we check if an operator is being slashed, before releasing the stake, there might be better options? Another one is to proceed with the removal of operators and their stake + From cd52357522097e9f22426baed27273537fb93e0d Mon Sep 17 00:00:00 2001 From: ismellike Date: Tue, 17 Dec 2024 13:19:55 -0600 Subject: [PATCH 5/9] Improve release_stake readme --- docs/architecture/RELEASE_STAKE.md | 105 +++++++++++++++-------------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index 66d20950..b0b86d7b 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -2,9 +2,9 @@ ## Overview -`release_stake` is a message in the restaking system that allows a consumer contract to request immediate release of tokens from its provider contract. +`release_stake` is a message in the restaking system that allows a **consumer contract** to request the release of tokens from its provider contract. -The basic message structure: +### Message Structure ```rust ReleaseStake { staker: String, @@ -13,61 +13,68 @@ ReleaseStake { } ``` -## Known Requirements +## Core Process +1. **Initiation:** A consumer contract sends the `release_stake` message to the provider. +2. **Validation:** The provider validates the request by checking the amount and ensuring proper authorization. +3. **State Update:** Stake accounting is updated in the provider contract, reflecting the released tokens. +4. **Finalization:** The provider processes any unbonding claims and optionally forwards the `release_stake` message up the chain. -1. Authorization: - - Only a registered consumer contract can call `release_stake` on its provider +> **Exception:** If the contract is the ultimate provider (e.g., Token Staking), the process terminates by sending a bank transfer to the original staker. -2. Message Flow: - - Consumer initiates `release_stake` to provider - - Provider must validate the request - - Provider updates stake accounting - - Provider may need to clear any unbonding claims - -## Contract Types +## Contract Behaviors +The behavior of `release_stake` varies depending on the contract type. Contracts are categorized into **Pure Pass-Through Contracts** and **State-Mutating Contracts**. ### Pure Pass-Through Contracts -These contracts only authenticate and forward `release_stake` messages: +These contracts do not alter the stake state and simply forward the message upstream to the provider: -**Token Staking** -- Simply validates consumer -- Forwards message to provider -- No state mutations needed -- No stake transformations +#### 1. Token Staking +- Receives `release_stake` from a consumer. +- Creates a **Bank Send** transaction to the staker. +- Terminates the flow; does not forward to a provider as it is a leaf node. -**Fan In** -- Maps between input/output denominations -- Forwards to correct provider -- No stake amount transformations -- Only maintains denom mapping state +#### 2. Fan In +- Maps output denominations to input denominations and forwards the request to the correct provider. +- Ensures the input denom is correctly remapped. ### State-Mutating Contracts -These contracts must maintain their own stake accounting and potentially transform amounts: - -**Token Weighting** -- Must track weighted stakes -- Need to recalculate ratios -- Maintains complex stake state - -**Delegations** -- Must track delegate proportions -- May need to split release across delegates -- Maintains delegation relationships - -**Fan Out** -- Must handle multiple outputs -- Needs to maintain proportions - -**Splitter** -- Must handle multiple consumers -- Maintains stake proportions -- State for each split - -**Operators** -- Maps between operators and stakers -- Must maintain operator relationships -- Affects operator/staker mappings - +These contracts manage stake accounting and modify state: + +#### 1. Token Weighting +- Receives `release_stake` after unbonding. +- Adjusts **token weight ratios** and stake state. +- Forwards the message to the provider. + +#### 2. Delegations +- Tracks delegate proportions. +- Waits for delegators to **claim their portions** before forwarding `release_stake` to the provider. +- Introduces a delay until claims are complete, ensuring accurate accounting. + +#### 3. Fan Out +- Handles multiple output flows. +- Updates **outflow accounting** to reflect the proportionate release. +- Maintains unbonding claims instead of directly triggering `release_stake`. +- The staker must call `ReleaseUnbonded` to propagate `release_stake` upstream. + +#### 4. Splitter +- Maintains split proportions for multiple consumers. +- Updates split accounting based on the `release_stake` message. + +#### 5. Operators +- Maps the **operator address** to the original staker address. +- Updates stake accounting and ensures the message flows through correctly. +- Maintains unbonding claims until the staker calls `ReleaseUnbonded`. + +## Known Trigger Points +`release_stake` can be triggered in several scenarios: + +1. **User-Initiated Claims** (ReleaseUnbonded): + - A user calls `ReleaseUnbonded` on a contract after the unbonding period expires. + - This triggers `release_stake` messages to propagate up to the provider. + +2. **Administrative Actions:** + - **DefineFlow (Fan Out):** Changing outflows creates unbonding claims for old outflows. + - **SetOperator (Operators):** Changing operators results in unbonding claims for the old operator. + - **DefineDelegates (Delegations):** Modifying delegation configuration creates unbonding claims that are finalized via `ReleaseUnbonded`. ## Questions - when it comes to validating the request by the `provider`, should the `provider` always trust the `consumer's` request (`consumer` is always whitelisted) or the `provider` should do additional validation - eg, check that the request doesn't exceed what's already staked? From 8a442134a28ab4508cbffce5225fdf6a6e9ed1a4 Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:42:12 +0200 Subject: [PATCH 6/9] [no ci] adds more questions --- docs/architecture/RELEASE_STAKE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index b0b86d7b..e6672cf6 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -17,10 +17,13 @@ ReleaseStake { 1. **Initiation:** A consumer contract sends the `release_stake` message to the provider. 2. **Validation:** The provider validates the request by checking the amount and ensuring proper authorization. 3. **State Update:** Stake accounting is updated in the provider contract, reflecting the released tokens. +3.1. *Question:* shouldn't this force the clearing of any unbonding claims and/or finalizing pending reward distributions. 4. **Finalization:** The provider processes any unbonding claims and optionally forwards the `release_stake` message up the chain. > **Exception:** If the contract is the ultimate provider (e.g., Token Staking), the process terminates by sending a bank transfer to the original staker. +*Question:* my understanding is that during the unbonding period, the tokens remain locked. During this period they still may be slashed or changed (delegation scenarios). So then when this period has ended, and any pending rewards are accounted for/distributed, can `release_stake` happen. + ## Contract Behaviors The behavior of `release_stake` varies depending on the contract type. Contracts are categorized into **Pure Pass-Through Contracts** and **State-Mutating Contracts**. @@ -41,6 +44,7 @@ These contracts manage stake accounting and modify state: #### 1. Token Weighting - Receives `release_stake` after unbonding. +- Makes sure it’s not recalculating weights before propagating `release_stake`. - Adjusts **token weight ratios** and stake state. - Forwards the message to the provider. From 6e0441f2a40ab510212b7a3ae7bb4d77153fc3cf Mon Sep 17 00:00:00 2001 From: gangov <6922910+gangov@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:19:49 +0200 Subject: [PATCH 7/9] [no ci] adds a table trackin the current state of contracts --- docs/architecture/RELEASE_STAKE.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index e6672cf6..b799af7b 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -68,6 +68,19 @@ These contracts manage stake accounting and modify state: - Updates stake accounting and ensures the message flows through correctly. - Maintains unbonding claims until the staker calls `ReleaseUnbonded`. +## State of Contracts Implementing The Release Stake + + +| Contract | `release_stake` Implementation | Current Status | Needed Changes | +|-------------------|---------------------------------------------------------------|----------------------------------------|------------------------------------------------------------------| +| Token Staking | `release_stake` implemented | Fully Implemented | Tokens are available for immediate withdrawal via `withdraw_unbonded`. | +| Fan In | `release_stake` updates `TOTAL_STAKE` and forwards upstream | Partially Implemented | Add reward accounting (not mandatory), we need partial/full release policy, add validation before forwarding | +| Fan Out | `release_stake` implemented: updates state and liens, but user must call `ReleaseUnbonded` to propagate upstream | Partially Implemented | Needs integration of reward logic (right now is `todo!()` in `withdraw_rewards`/`distribute_rewards`), ensure that all claims and outflows are settled before user triggers `ReleaseUnbonded` to finally push `release_stake` upstream | +| Delegations | still `todo!()` | Not Implemented | ensure delegators’ claims settled, distribute rewards, maybe also handle partial/full release before forwarding | +| Token Weighting | no explicit `release_stake` present | Not Implemented | implement `release_stake`: ensure no weight recalculations in progress, fix token weight ratios, then forward upstream | +| Operators | `release_stake` implemented | Partially Implemented | make sure that operator removal and slashing are in consideration. Ensure unbonding claims handling until `ReleaseUnbonded` called by staker, then forward upstream | +| Splitter | `release_stake` is still `todo!()` | Not Implemented | Implement logic for multiple splits, handle rewards/unbonding claims, then forward | + ## Known Trigger Points `release_stake` can be triggered in several scenarios: From b5c174021aa87ccba66856b4a7430f20ec9f16e1 Mon Sep 17 00:00:00 2001 From: ismellike Date: Mon, 6 Jan 2025 14:33:33 -0600 Subject: [PATCH 8/9] Add pseudocode for delegations release_stake --- docs/architecture/RELEASE_STAKE.md | 74 ++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index b799af7b..e4273ee1 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -49,9 +49,74 @@ These contracts manage stake accounting and modify state: - Forwards the message to the provider. #### 2. Delegations -- Tracks delegate proportions. -- Waits for delegators to **claim their portions** before forwarding `release_stake` to the provider. -- Introduces a delay until claims are complete, ensuring accurate accounting. + +The delegations contract manages stake allocation across multiple delegates. When processing `release_stake`, it must handle proportional distribution of released amounts across delegators. + +**Key Challenges:** +- Must handle potentially large numbers of delegators (1000+) +- Needs to maintain proper proportional distributions +- Cannot iterate through all delegators due to gas limits +- Must handle multiple release_stake requests during unbonding period +- Must update delegation ratios after release + +**State Management:** +```rust +#[cw_serde] +pub struct UnbondingClaim { + pub total_unbonding: Uint128, // Amount being unbonded in this claim + pub released_amount: Uint128, // Amount processed/released so far + pub start_time: u64, // When unbonding started +} + +// Maps (denom, delegate) -> vector of unbonding claims +pub const DELEGATE_UNBONDING: Map<(&str, &Addr), Vec>; +``` + +**Process Flow:** + +1. When consumer calls `release_stake`: +```rust +pub fn release_stake( + deps: DepsMut, + env: Env, + info: MessageInfo, + staker: String, // delegate address + amount: Uint128, + denom: String, +) -> Result { + // Validate sender is consumer contract + // Verify delegate has sufficient stake + // Verify no pending rewards need distribution + // Record historical stake amount for proper reward calculation + // Create new UnbondingClaim + // Update total staked amount + // Emit events +} +``` + +2. When delegator calls `release_unbonded`: +```rust +pub fn release_unbonded( + deps: DepsMut, + env: Env, + info: MessageInfo, +) -> Result { + // For each delegate where delegator has stake: + // For each unprocessed claim: + // If unbonding period complete: + // Update delegator's stake and liens + // Recalculate delegation ratios: + // - Get all current delegations + // - Subtract the released amount + // - Normalize remaining delegations to sum to 100% + // - Update STAKER_DELEGATIONS + // Forward portion upstream via release_stake message + // Mark as processed + // Update released_amount in claim + + // Send accumulated messages +} +``` #### 3. Fan Out - Handles multiple output flows. @@ -98,5 +163,4 @@ These contracts manage stake accounting and modify state: - do we allow for partial `release_stake` - eg, a consumer would like to free 1/3 of the staked tokens - for `token_weighting` contract: what happens when the token-weighting contract receieve a msg to release stake when it's currently calculating new weight? Basically both requests in the same block - for `fan-out` contract: what if we change the denom and request `release_stake` on the old name? It will fail ofc, but I guess we have to call the old denom name. - - for `operators` contract: that's for the future, but shouldn't we check if an operator is being slashed, before releasing the stake, there might be better options? Another one is to proceed with the removal of operators and their stake - + - for `operators` contract: that's for the future, but shouldn't we check if an operator is being slashed, before releasing the stake, there might be better options? Another one is to proceed with the removal of operators and their stake \ No newline at end of file From fa802a0660ac237a3d3a2bf9c447da2ee5c272f2 Mon Sep 17 00:00:00 2001 From: ismellike Date: Wed, 8 Jan 2025 09:35:00 -0600 Subject: [PATCH 9/9] Switch release_stake delegations start_time -> end_time --- docs/architecture/RELEASE_STAKE.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/architecture/RELEASE_STAKE.md b/docs/architecture/RELEASE_STAKE.md index e4273ee1..0a298f05 100644 --- a/docs/architecture/RELEASE_STAKE.md +++ b/docs/architecture/RELEASE_STAKE.md @@ -65,7 +65,7 @@ The delegations contract manages stake allocation across multiple delegates. Whe pub struct UnbondingClaim { pub total_unbonding: Uint128, // Amount being unbonded in this claim pub released_amount: Uint128, // Amount processed/released so far - pub start_time: u64, // When unbonding started + pub end_time: u64, // When unbonding will end } // Maps (denom, delegate) -> vector of unbonding claims @@ -136,15 +136,15 @@ pub fn release_unbonded( ## State of Contracts Implementing The Release Stake -| Contract | `release_stake` Implementation | Current Status | Needed Changes | -|-------------------|---------------------------------------------------------------|----------------------------------------|------------------------------------------------------------------| -| Token Staking | `release_stake` implemented | Fully Implemented | Tokens are available for immediate withdrawal via `withdraw_unbonded`. | -| Fan In | `release_stake` updates `TOTAL_STAKE` and forwards upstream | Partially Implemented | Add reward accounting (not mandatory), we need partial/full release policy, add validation before forwarding | -| Fan Out | `release_stake` implemented: updates state and liens, but user must call `ReleaseUnbonded` to propagate upstream | Partially Implemented | Needs integration of reward logic (right now is `todo!()` in `withdraw_rewards`/`distribute_rewards`), ensure that all claims and outflows are settled before user triggers `ReleaseUnbonded` to finally push `release_stake` upstream | -| Delegations | still `todo!()` | Not Implemented | ensure delegators’ claims settled, distribute rewards, maybe also handle partial/full release before forwarding | -| Token Weighting | no explicit `release_stake` present | Not Implemented | implement `release_stake`: ensure no weight recalculations in progress, fix token weight ratios, then forward upstream | -| Operators | `release_stake` implemented | Partially Implemented | make sure that operator removal and slashing are in consideration. Ensure unbonding claims handling until `ReleaseUnbonded` called by staker, then forward upstream | -| Splitter | `release_stake` is still `todo!()` | Not Implemented | Implement logic for multiple splits, handle rewards/unbonding claims, then forward | +| Contract | `release_stake` Implementation | Current Status | Needed Changes | +| --------------- | ---------------------------------------------------------------------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Token Staking | `release_stake` implemented | Fully Implemented | Tokens are available for immediate withdrawal via `withdraw_unbonded`. | +| Fan In | `release_stake` updates `TOTAL_STAKE` and forwards upstream | Partially Implemented | Add reward accounting (not mandatory), we need partial/full release policy, add validation before forwarding | +| Fan Out | `release_stake` implemented: updates state and liens, but user must call `ReleaseUnbonded` to propagate upstream | Partially Implemented | Needs integration of reward logic (right now is `todo!()` in `withdraw_rewards`/`distribute_rewards`), ensure that all claims and outflows are settled before user triggers `ReleaseUnbonded` to finally push `release_stake` upstream | +| Delegations | still `todo!()` | Not Implemented | ensure delegators’ claims settled, distribute rewards, maybe also handle partial/full release before forwarding | +| Token Weighting | no explicit `release_stake` present | Not Implemented | implement `release_stake`: ensure no weight recalculations in progress, fix token weight ratios, then forward upstream | +| Operators | `release_stake` implemented | Partially Implemented | make sure that operator removal and slashing are in consideration. Ensure unbonding claims handling until `ReleaseUnbonded` called by staker, then forward upstream | +| Splitter | `release_stake` is still `todo!()` | Not Implemented | Implement logic for multiple splits, handle rewards/unbonding claims, then forward | ## Known Trigger Points `release_stake` can be triggered in several scenarios: