1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
use std::fmt::{self, Display, Formatter};
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Binary, CosmosMsg, Uint128};
use crate::{
asset::{Asset, AssetInfo},
vault::{FeeInfo, NativeAssetPrecisionInfo, PoolType},
};
#[cw_serde]
pub struct PoolCreationRequest {
pub vault_addr: String,
pub pool_type: PoolType,
pub fee_info: Option<FeeInfo>,
pub native_asset_precisions: Vec<NativeAssetPrecisionInfo>,
pub asset_info: Vec<AssetInfo>,
pub init_params: Option<Binary>,
// this address will be the owner of the bootsrapping liquidity
pub bootstrapping_liquidity_owner: String,
// Optional fields depending on the fact if user wants to bootstrap liquidty to the pool
pub bootstrapping_amount: Option<Vec<Asset>>,
// Optional field to specify if the user wants to create reward schedule(s) for this pool
pub reward_schedules: Option<Vec<RewardScheduleCreationRequest>>,
}
#[cw_serde]
#[derive(Copy)]
pub enum PoolCreationRequestStatus {
PendingProposalCreation,
ProposalCreated {
proposal_id: u64,
},
PoolCreated {
proposal_id: u64,
pool_id: Uint128,
},
RequestFailedAndRefunded {
proposal_id: u64,
refund_block_height: u64,
},
RequestSuccessfulAndDepositRefunded {
proposal_id: u64,
refund_block_height: u64,
},
}
impl PoolCreationRequestStatus {
pub fn proposal_id(&self) -> Option<u64> {
match self {
PoolCreationRequestStatus::ProposalCreated { proposal_id } => Some(*proposal_id),
PoolCreationRequestStatus::PoolCreated { proposal_id, .. } => Some(*proposal_id),
PoolCreationRequestStatus::RequestFailedAndRefunded { proposal_id, .. } => {
Some(*proposal_id)
}
PoolCreationRequestStatus::RequestSuccessfulAndDepositRefunded {
proposal_id, ..
} => Some(*proposal_id),
_ => None,
}
}
}
#[cw_serde]
pub struct PoolCreateRequestContextData {
pub status: PoolCreationRequestStatus,
pub request_sender: Addr,
pub total_funds_acquired_from_user: Vec<Asset>,
pub user_deposits_detailed: Vec<UserDeposit>,
pub pool_creation_request: PoolCreationRequest,
}
#[cw_serde]
pub struct RewardScheduleCreationRequest {
/// This is null when it is being used within a new pool creation request
/// This is not null when it is being used as a reward schedule creation request
pub lp_token_addr: Option<Addr>,
pub title: String,
pub asset: AssetInfo,
pub amount: Uint128,
pub start_block_time: u64,
pub end_block_time: u64,
}
#[cw_serde]
#[derive(Copy)]
pub enum RewardSchedulesCreationRequestStatus {
PendingProposalCreation,
NonProposalRewardSchedule,
ProposalCreated {
proposal_id: u64,
},
RewardSchedulesCreated {
proposal_id: Option<u64>,
},
RequestFailedAndRefunded {
proposal_id: u64,
refund_block_height: u64,
},
RequestSuccessfulAndDepositRefunded {
proposal_id: u64,
refund_block_height: u64,
},
}
impl RewardSchedulesCreationRequestStatus {
pub fn proposal_id(&self) -> Option<u64> {
match self {
RewardSchedulesCreationRequestStatus::ProposalCreated { proposal_id } => {
Some(*proposal_id)
}
RewardSchedulesCreationRequestStatus::RewardSchedulesCreated { proposal_id } => {
*proposal_id
}
RewardSchedulesCreationRequestStatus::RequestFailedAndRefunded {
proposal_id, ..
} => Some(*proposal_id),
RewardSchedulesCreationRequestStatus::RequestSuccessfulAndDepositRefunded {
proposal_id,
..
} => Some(*proposal_id),
_ => None,
}
}
}
#[cw_serde]
pub struct RewardScheduleCreationRequestsState {
pub multistaking_contract_addr: Addr,
pub status: RewardSchedulesCreationRequestStatus,
pub request_sender: Addr,
/// this field is only set if the request is linked to a governance proposal
pub total_funds_acquired_from_user: Vec<Asset>,
pub user_deposits_detailed: Vec<UserDeposit>,
pub reward_schedule_creation_requests: Vec<RewardScheduleCreationRequest>,
}
#[cw_serde]
pub struct GovernanceProposalDescription {
pub title: String,
pub metadata: String,
pub summary: String,
}
#[cw_serde]
pub enum GovAdminProposalRequestType {
PoolCreationRequest { request_id: u64 },
RewardSchedulesCreationRequest { request_id: u64 },
}
#[cw_serde]
pub enum FundsCategory {
PoolCreationFee,
ProposalDeposit,
PoolBootstrappingAmount,
RewardScheduleAmount,
}
#[cw_serde]
pub struct UserDeposit {
pub category: FundsCategory,
pub assets: Vec<Asset>,
}
#[cw_serde]
pub enum RefundReason {
ProposalPassedDepositRefund,
ProposalRejectedFullRefund,
ProposalVetoedRefundExceptDeposit,
ProposalFailedFullRefund,
}
impl Display for RefundReason {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
RefundReason::ProposalPassedDepositRefund => {
write!(f, "ProposalPassedDepositRefund")
}
RefundReason::ProposalRejectedFullRefund => {
write!(f, "ProposalRejectedFullRefund")
}
RefundReason::ProposalVetoedRefundExceptDeposit => {
write!(f, "ProposalVetoedRefundExceptDeposit")
}
RefundReason::ProposalFailedFullRefund => {
write!(f, "ProposalFailedFullRefund")
}
}
}
}
#[cw_serde]
pub struct RefundResponse {
pub refund_reason: RefundReason,
pub refund_receiver: Addr,
pub refund_amount: Vec<Asset>,
pub detailed_refund_amount: Vec<UserDeposit>,
}
#[cw_serde]
pub struct UserTotalDeposit {
pub total_deposit: Vec<Asset>,
pub deposit_breakdown: Vec<UserDeposit>,
}
#[cw_serde]
pub struct InstantiateMsg {}
#[cw_serde]
pub enum ExecuteMsg {
// User executable
/// Creates a proposal to create a pool
/// The proposal is created by the governance admin contract on behalf of the user to enable easy accounting of funds for pool creation
/// Pool creation follows the following steps:
/// 1. User calls this contract with a pool creation request and required funds and(or) approval to spend funds in case of CW20 tokens
/// 2. This contract verifies the funds, and transfers the funds to this contract in case of CW20 tokens. The custody of the funds is transferred to the governance admin contract.
/// 3. This contract stores the pool creation request in its state.
/// 3. Then, this contract creates a proposal to resume the pool creation process, which returns a callback to itself with the pool creation request id.
/// 4. If the proposal is passed, governance module of the chain will call the callback with the pool creation request id.
/// 5. This contract will then resume the pool creation process and create the pool in the vault contract.
/// 6. If specified, it will also bootstrap the pool with the bootstrapping amount.
/// 7. If specified, it will also create the reward schedules for the pool in the multi-staking contract.
/// 8. If the pool creation fails or if the proposal is rejected, the user can request all the funds back by executing the `ClaimRefund` message.
/// 9. If the pool creation is successful, the user can request Proposal Deposit amount by the same `ClaimRefund` message.
CreatePoolCreationProposal {
proposal_description: GovernanceProposalDescription,
pool_creation_request: PoolCreationRequest,
},
/// Creates a proposal to add one or more new reward schedule(s) to an existing pool
/// The proposal is created by the governance admin contract on behalf of the user to enable easy accounting of funds for reward schedule creation
/// Reward schedule creation follows the following steps:
/// 1. User calls this contract with a reward schedule creation request and required funds and(or) approval to spend funds in case of CW20 tokens
/// 2. This contract verifies the funds, and transfers the funds to this contract in case of CW20 tokens. The custody of the funds is transferred to the governance admin contract.
/// 3. This contract stores the reward schedule creation request in its state.
/// 3. Then, this contract creates a proposal to resume the reward schedule creation process, which returns a callback to itself with the reward schedule creation request id.
/// 4. If the proposal is passed, governance module of the chain will call the callback with the reward schedule creation request id.
/// 5. This contract will then resume the reward schedule creation process and create the reward schedule(s) in the multi-staking contract.
/// 8. If the pool creation fails or if the proposal is rejected, the user can request all the funds back by executing the `ClaimRefund` message.
/// 9. If the pool creation is successful, the user can request Proposal Deposit amount by the same `ClaimRefund` message.
CreateRewardSchedulesProposal {
proposal_description: GovernanceProposalDescription,
multistaking_contract_addr: String,
reward_schedule_creation_requests: Vec<RewardScheduleCreationRequest>,
},
/// Claims the refundable funds from the governance admin contract.
/// Will return an error if the valid funds are already refunded to the user.
ClaimRefund {
request_type: GovAdminProposalRequestType,
},
// Gov executable
/// Execute any messages on behalf of the governance admin contract. This is useful for configuration updates using the Governance Admin contract.
/// As governance admin contract is designed to become owner of Vault and Multi-staking contracts, any configuration change on them can be done using this message
/// This message can be executed only by the Governace module of the chain i.e. it is fully chain governed.
ExecuteMsgs { msgs: Vec<CosmosMsg> },
/// Resumes the pool creation process after the proposal is passed.
/// This message is called by the governance module of the chain as an action of the proposal created by the `CreatePoolCreationProposal` message.
/// This message can only be called by the governance module of the chain.
ResumeCreatePool { pool_creation_request_id: u64 },
/// Resumes the reward schedule creation process.
/// This message is called by the governance module of the chain as an action of the proposal created by the `CreateRewardSchedulesProposal` message.
/// This message can also be called by the contract itself after a new pool with reward schedules is created using the `ResumeCreatePool` message.
ResumeCreateRewardSchedules {
reward_schedules_creation_request_id: u64,
},
// Self executable
/// Callback message to store the proposal id after the proposal is created.
/// This message is ordered by the `CreatePoolCreationProposal` message after the `SubmitProposal` message, so it is executed right after the proposal is created in the same transaction.
/// This message is executed by the governance admin contract itself and no-one else can execute this message.
PostGovernanceProposalCreationCallback {
gov_proposal_type: GovAdminProposalRequestType,
},
/// Callback message after the pool is created in the vault.
/// This message is ordered by the `ResumeCreatePool` message after the `CreatePool` message, so it is executed right after the pool is created in the same transaction.
/// This message is executed by the governance admin contract itself and no-one else can execute this message.
/// We trigger the pool join functionality and store pool specific data in the Gov admin contract state in this message.
ResumeJoinPool { pool_creation_request_id: u64 },
}
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
/// Returns the state of the pool creation request
#[returns(PoolCreateRequestContextData)]
PoolCreationRequest { pool_creation_request_id: u64 },
/// Returns the state of the reward schedule creation request
#[returns(RewardScheduleCreationRequestsState)]
RewardScheduleRequest { reward_schedule_request_id: u64 },
#[returns(UserTotalDeposit)]
FundsForPoolCreation { request: PoolCreationRequest },
#[returns(UserTotalDeposit)]
FundsForRewardScheduleCreation {
requests: Vec<RewardScheduleCreationRequest>,
},
/// Returns the refundable funds for the user.
/// It provides total refund and also a breakdown of the refundable funds so that the user can understand the reason for the refund
/// and the calculation involved in the refund.
#[returns(RefundResponse)]
RefundableFunds {
request_type: GovAdminProposalRequestType,
},
}