white_whale_std/pool_network/incentive.rs
1use std::collections::{BTreeMap, HashMap};
2use std::fmt;
3
4use cosmwasm_schema::{cw_serde, QueryResponses};
5use cosmwasm_std::{Addr, Decimal256, Uint128};
6
7use crate::pool_network::asset::{Asset, AssetInfo};
8
9#[cw_serde]
10pub struct InstantiateMsg {
11 /// The address of the LP token that the incentive should be tied to.
12 pub lp_asset: AssetInfo,
13 /// Fee distributor contract address.
14 pub fee_distributor_address: String,
15}
16
17#[cw_serde]
18pub enum ExecuteMsg {
19 /// Makes a snapshot of the current global weight, at the current epoch.
20 TakeGlobalWeightSnapshot {},
21 /// Opens a new liquidity flow
22 OpenFlow {
23 /// The epoch at which the flow will start. If unspecified, the flow will start at the
24 /// current epoch.
25 start_epoch: Option<u64>,
26 /// The epoch at which the flow should end. If unspecified, the flow will default to end at
27 /// 14 epochs from the current one.
28 end_epoch: Option<u64>,
29 /// The type of distribution curve. If unspecified, the distribution will be linear.
30 curve: Option<Curve>,
31 /// The asset to be distributed in this flow.
32 flow_asset: Asset,
33 /// If set, the label will be used to identify the flow, in addition to the flow_id.
34 flow_label: Option<String>,
35 },
36 /// Closes an existing liquidity flow.
37 ///
38 /// Sender of the message must either be the contract admin or the creator of the flow.
39 CloseFlow {
40 /// The identifier of the flow to close.
41 flow_identifier: FlowIdentifier,
42 },
43 /// Creates a new position to earn flow rewards.
44 OpenPosition {
45 /// The amount to add to the position.
46 amount: Uint128,
47 /// The amount of time (in seconds) before the LP tokens can be redeemed.
48 unbonding_duration: u64,
49 /// The receiver of the new position.
50 ///
51 /// This is mostly used for the frontend helper contract.
52 ///
53 /// If left empty, defaults to the message sender.
54 receiver: Option<String>,
55 },
56 /// Expands an existing position to earn more flow rewards.
57 ExpandPosition {
58 /// The amount to add to the existing position.
59 amount: Uint128,
60 /// The unbond completion timestamp to identify the position to add to.
61 unbonding_duration: u64,
62 /// The receiver of the expanded position.
63 ///
64 /// This is mostly used for the frontend helper contract.
65 ///
66 /// If left empty, defaults to the message sender.
67 receiver: Option<String>,
68 },
69 /// Closes an existing position to stop earning flow rewards.
70 ClosePosition {
71 /// The unbonding duration of the position to close.
72 unbonding_duration: u64,
73 },
74 /// Withdraws the LP tokens from a closed position once the unbonding duration has passed.
75 Withdraw {},
76 /// Claims the flow rewards.
77 Claim {},
78 /// Expands an existing flow.
79 ExpandFlow {
80 /// The identifier of the flow to expand, whether an id or a label.
81 flow_identifier: FlowIdentifier,
82 /// The epoch at which the flow should end. If not set, the flow will be expanded a default value of 14 epochs.
83 end_epoch: Option<u64>,
84 /// The asset to expand this flow with.
85 flow_asset: Asset,
86 },
87}
88
89#[cw_serde]
90pub struct MigrateMsg {}
91
92/// Represents a flow.
93#[cw_serde]
94pub struct Flow {
95 /// A unique identifier of the flow.
96 pub flow_id: u64,
97 /// An alternative flow label.
98 pub flow_label: Option<String>,
99 /// The account which opened the flow and can manage it.
100 pub flow_creator: Addr,
101 /// The asset the flow was created to distribute.
102 pub flow_asset: Asset,
103 /// The amount of the `flow_asset` that has been claimed so far.
104 pub claimed_amount: Uint128,
105 /// The type of curve the flow has.
106 pub curve: Curve,
107 //todo not doing anything for now
108 /// The epoch at which the flow starts.
109 pub start_epoch: u64,
110 /// The epoch at which the flow ends.
111 pub end_epoch: u64,
112 /// emitted tokens
113 pub emitted_tokens: HashMap<u64, Uint128>,
114 /// A map containing the amount of tokens it was expanded to at a given epoch. This is used
115 /// to calculate the right amount of tokens to distribute at a given epoch when a flow is expanded.
116 pub asset_history: BTreeMap<u64, (Uint128, u64)>,
117}
118
119/// Represents a position that accumulates flow rewards.
120///
121/// An address can have multiple incentive positions active at once.
122#[cw_serde]
123pub struct OpenPosition {
124 /// The amount of LP tokens that are put up to earn incentives.
125 pub amount: Uint128,
126 /// Represents the amount of time in seconds the user must wait after unbonding for the LP tokens to be released.
127 pub unbonding_duration: u64,
128}
129
130impl fmt::Display for OpenPosition {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(
133 f,
134 "OpenPosition(amount: {}, unbonding_duration: {})",
135 self.amount, self.unbonding_duration
136 )
137 }
138}
139
140/// Represents a position that has moved from the [`OpenPosition`] state.
141///
142/// This position is no longer accumulating rewards, and the underlying tokens are claimable after `unbonding_duration`.
143#[cw_serde]
144pub struct ClosedPosition {
145 /// The amount of LP tokens that the user is unbonding in this position.
146 pub amount: Uint128,
147 /// The block timestamp when the user can withdraw the position to retrieve the underlying `amount` of LP tokens.
148 pub unbonding_timestamp: u64,
149}
150
151#[cw_serde]
152#[derive(QueryResponses)]
153pub enum QueryMsg {
154 /// Retrieves the current contract configuration.
155 #[returns(ConfigResponse)]
156 Config {},
157 /// Retrieves a specific flow. If start_epoch and end_epoch are set, the asset_history and
158 /// emitted_tokens will be filtered to only include epochs within the range. The maximum gap between
159 /// the start_epoch and end_epoch is 100 epochs.
160 #[returns(FlowResponse)]
161 Flow {
162 /// The id of the flow to find.
163 flow_identifier: FlowIdentifier,
164 /// If set, filters the asset_history and emitted_tokens to only include epochs from start_epoch.
165 start_epoch: Option<u64>,
166 /// If set, filters the asset_history and emitted_tokens to only include epochs until end_epoch.
167 end_epoch: Option<u64>,
168 },
169 /// Retrieves the current flows. If start_epoch and end_epoch are set, the asset_history and
170 /// emitted_tokens will be filtered to only include epochs within the range. The maximum gap between
171 /// the start_epoch and end_epoch is 100 epochs.
172 #[returns(FlowsResponse)]
173 Flows {
174 /// If set, filters the asset_history and emitted_tokens to only include epochs from start_epoch.
175 start_epoch: Option<u64>,
176 /// If set, filters the asset_history and emitted_tokens to only include epochs until end_epoch.
177 end_epoch: Option<u64>,
178 },
179 /// Retrieves the positions for an address.
180 #[returns(PositionsResponse)]
181 Positions {
182 /// The address to get positions for.
183 address: String,
184 },
185 /// Retrieves the rewards for an address.
186 #[returns(RewardsResponse)]
187 Rewards {
188 /// The address to get all the incentive rewards for.
189 address: String,
190 },
191 /// Retrieves the rewards for an address.
192 #[returns(GlobalWeightResponse)]
193 GlobalWeight {
194 /// The epoch to get the global weight for.
195 epoch_id: u64,
196 },
197 /// Retrieves the rewards/weight share of an address for the current epoch.
198 #[returns(RewardsShareResponse)]
199 CurrentEpochRewardsShare {
200 /// The address to query the rewards share for.
201 address: String,
202 },
203}
204
205/// Stores the reply data set in the response when instantiating an incentive contract.
206#[cw_serde]
207pub struct InstantiateReplyCallback {
208 /// The address of the LP token that is tied to the incentive contract.
209 pub lp_asset: AssetInfo,
210}
211
212/// Represents the configuration of the incentive contract.
213#[cw_serde]
214pub struct Config {
215 /// The address of the incentive factory.
216 pub factory_address: Addr,
217
218 /// Fee distributor contract.
219 pub fee_distributor_address: Addr,
220
221 /// The LP token asset tied to the incentive contract.
222 pub lp_asset: AssetInfo,
223}
224
225/// The type of distribution curve to exist.
226#[cw_serde]
227pub enum Curve {
228 /// A linear curve that releases assets as we approach the end of the flow period.
229 Linear,
230}
231
232impl std::fmt::Display for Curve {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 match self {
235 Curve::Linear => write!(f, "Linear"),
236 }
237 }
238}
239
240pub type ConfigResponse = Config;
241
242#[cw_serde]
243pub struct FlowResponse {
244 //TODO why is this returning a Option<Flow>? why not a flow directly?
245 /// The flow that was searched for.
246 pub flow: Option<Flow>,
247}
248
249#[cw_serde]
250pub struct FlowsResponse {
251 /// The current flows.
252 pub flows: Vec<Flow>,
253}
254
255#[cw_serde]
256pub enum QueryPosition {
257 /// Represents a position that a user has deposited, but not yet begun to unbond.
258 OpenPosition {
259 /// The amount of LP tokens the user deposited into the position.
260 amount: Uint128,
261 /// The amount of time (in seconds) the user must wait after they begin the unbonding process.
262 unbonding_duration: u64,
263 /// The amount of weight the position has.
264 weight: Uint128,
265 },
266 /// Represents a position that a user has initiated the unbonding process on. The position may or may not be withdrawable.
267 ClosedPosition {
268 /// The amount of LP tokens the user deposited into the position, and will receive after they withdraw.
269 amount: Uint128,
270 /// The timestamp (in seconds) the user unbonded at.
271 unbonding_timestamp: u64,
272 /// The amount of weight the position has.
273 weight: Uint128,
274 },
275}
276
277#[cw_serde]
278pub struct PositionsResponse {
279 /// The current time of the blockchain.
280 pub timestamp: u64,
281 /// All the positions a user has.
282 pub positions: Vec<QueryPosition>,
283}
284
285#[cw_serde]
286pub struct RewardsResponse {
287 /// The rewards that is available to a user if they executed the `claim` function at this point.
288 pub rewards: Vec<Asset>,
289}
290
291#[cw_serde]
292pub struct GlobalWeightResponse {
293 /// the global weight of the incentive contract for the given epoch
294 pub global_weight: Uint128,
295 /// Epoch id for which the global weight is calculated
296 pub epoch_id: u64,
297}
298
299#[cw_serde]
300pub struct RewardsShareResponse {
301 pub address: Addr,
302 pub global_weight: Uint128,
303 pub address_weight: Uint128,
304 pub share: Decimal256,
305 pub epoch_id: u64,
306}
307
308#[cw_serde]
309pub enum FlowIdentifier {
310 Id(u64),
311 Label(String),
312}
313
314impl fmt::Display for FlowIdentifier {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 match self {
317 FlowIdentifier::Id(flow_id) => write!(f, "flow_id: {}", flow_id),
318 FlowIdentifier::Label(flow_label) => write!(f, "flow_label: {}", flow_label),
319 }
320 }
321}