Skip to content

Commit ca84f67

Browse files
authored
Fix tribute migration and UserVotes query (#252)
* Remove the tribute upgrade, and update the query_user_votes to check previous round votes * Cleaner query_user_votes, tests now pass * Update comment on VOTE_MAP_V1 that we cannot remove it until all tributes are claimed for round 0 * Adjusting after @dusan-maksimovic comments
1 parent cc7321c commit ca84f67

File tree

24 files changed

+219
-599
lines changed

24 files changed

+219
-599
lines changed

artifacts/checksums.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
872843538f64fddbdb63f238270df8bdeb7b433193973dba80303821f3ce1d52 dao_voting_adapter.wasm
22
a1b2f7f0b77ca19d092bb70e2777f022f9e38326dfe8e70a03ac4571b407faf9 gatekeeper.wasm
3-
1072947a96908c2d13b2a1dadfc7d781e1690960ba3582934af78eb8fc5697e4 hydro.wasm
3+
8568b551541a60ad749d083447b43ccc87db8e1229be6fa8f697147ed4dfc471 hydro.wasm
44
76c72dcddf59a7d9dcd7d56da7367ff926554eac34b465fd580317fd9dbfd628 st_token_info_provider.wasm
5-
f92f2dc9fd5a684a7fa44f7f79629e5f10cbc1ab1bab4c82775ba538e8bad097 tribute.wasm
5+
733ba174383bb3e1116c8e92fa842cc42f368bb5c8d6555a84a0f3af0effaa63 tribute.wasm

artifacts/hydro.wasm

-7.56 KB
Binary file not shown.

artifacts/tribute.wasm

-31.3 KB
Binary file not shown.

contracts/hydro/schema/hydro.json

Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,39 +1394,6 @@
13941394
},
13951395
"additionalProperties": false
13961396
},
1397-
{
1398-
"type": "object",
1399-
"required": [
1400-
"user_voted_locks"
1401-
],
1402-
"properties": {
1403-
"user_voted_locks": {
1404-
"type": "object",
1405-
"required": [
1406-
"address",
1407-
"round_id",
1408-
"tranche_id"
1409-
],
1410-
"properties": {
1411-
"address": {
1412-
"type": "string"
1413-
},
1414-
"round_id": {
1415-
"type": "integer",
1416-
"format": "uint64",
1417-
"minimum": 0.0
1418-
},
1419-
"tranche_id": {
1420-
"type": "integer",
1421-
"format": "uint64",
1422-
"minimum": 0.0
1423-
}
1424-
},
1425-
"additionalProperties": false
1426-
}
1427-
},
1428-
"additionalProperties": false
1429-
},
14301397
{
14311398
"type": "object",
14321399
"required": [
@@ -3558,62 +3525,6 @@
35583525
}
35593526
}
35603527
},
3561-
"user_voted_locks": {
3562-
"$schema": "http://json-schema.org/draft-07/schema#",
3563-
"title": "UserVotedLocksResponse",
3564-
"type": "object",
3565-
"required": [
3566-
"voted_locks"
3567-
],
3568-
"properties": {
3569-
"voted_locks": {
3570-
"type": "array",
3571-
"items": {
3572-
"type": "array",
3573-
"items": [
3574-
{
3575-
"type": "integer",
3576-
"format": "uint64",
3577-
"minimum": 0.0
3578-
},
3579-
{
3580-
"type": "array",
3581-
"items": {
3582-
"$ref": "#/definitions/VotedLockInfo"
3583-
}
3584-
}
3585-
],
3586-
"maxItems": 2,
3587-
"minItems": 2
3588-
}
3589-
}
3590-
},
3591-
"additionalProperties": false,
3592-
"definitions": {
3593-
"Decimal": {
3594-
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
3595-
"type": "string"
3596-
},
3597-
"VotedLockInfo": {
3598-
"type": "object",
3599-
"required": [
3600-
"lock_id",
3601-
"power"
3602-
],
3603-
"properties": {
3604-
"lock_id": {
3605-
"type": "integer",
3606-
"format": "uint64",
3607-
"minimum": 0.0
3608-
},
3609-
"power": {
3610-
"$ref": "#/definitions/Decimal"
3611-
}
3612-
},
3613-
"additionalProperties": false
3614-
}
3615-
}
3616-
},
36173528
"user_votes": {
36183529
"$schema": "http://json-schema.org/draft-07/schema#",
36193530
"title": "UserVotesResponse",

contracts/hydro/schema/raw/query.json

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -267,39 +267,6 @@
267267
},
268268
"additionalProperties": false
269269
},
270-
{
271-
"type": "object",
272-
"required": [
273-
"user_voted_locks"
274-
],
275-
"properties": {
276-
"user_voted_locks": {
277-
"type": "object",
278-
"required": [
279-
"address",
280-
"round_id",
281-
"tranche_id"
282-
],
283-
"properties": {
284-
"address": {
285-
"type": "string"
286-
},
287-
"round_id": {
288-
"type": "integer",
289-
"format": "uint64",
290-
"minimum": 0.0
291-
},
292-
"tranche_id": {
293-
"type": "integer",
294-
"format": "uint64",
295-
"minimum": 0.0
296-
}
297-
},
298-
"additionalProperties": false
299-
}
300-
},
301-
"additionalProperties": false
302-
},
303270
{
304271
"type": "object",
305272
"required": [

contracts/hydro/src/contract.rs

Lines changed: 35 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ use crate::query::{
3333
RoundTotalVotingPowerResponse, RoundTrancheLiquidityDeploymentsResponse,
3434
SpecificUserLockupsResponse, SpecificUserLockupsWithTrancheInfosResponse,
3535
TokenInfoProvidersResponse, TopNProposalsResponse, TotalLockedTokensResponse, TranchesResponse,
36-
UserVotedLocksResponse, UserVotesResponse, UserVotingPowerResponse, VoteEntry, VotedLockInfo,
37-
WhitelistAdminsResponse, WhitelistResponse,
36+
UserVotesResponse, UserVotingPowerResponse, VoteEntry, WhitelistAdminsResponse,
37+
WhitelistResponse,
3838
};
3939
use crate::score_keeper::{
4040
add_token_group_shares_to_proposal, add_token_group_shares_to_round_total,
@@ -47,8 +47,8 @@ use crate::state::{
4747
VoteWithPower, CONSTANTS, GATEKEEPER, ICQ_MANAGERS, LIQUIDITY_DEPLOYMENTS_MAP, LOCKED_TOKENS,
4848
LOCKS_MAP_V2, LOCK_ID, PROPOSAL_MAP, PROPS_BY_SCORE, PROP_ID, SNAPSHOTS_ACTIVATION_HEIGHT,
4949
TOKEN_INFO_PROVIDERS, TRANCHE_ID, TRANCHE_MAP, USER_LOCKS, VALIDATORS_INFO,
50-
VALIDATORS_PER_ROUND, VALIDATORS_STORE_INITIALIZED, VALIDATOR_TO_QUERY_ID, VOTE_MAP_V2,
51-
VOTING_ALLOWED_ROUND, WHITELIST, WHITELIST_ADMINS,
50+
VALIDATORS_PER_ROUND, VALIDATORS_STORE_INITIALIZED, VALIDATOR_TO_QUERY_ID, VOTE_MAP_V1,
51+
VOTE_MAP_V2, VOTING_ALLOWED_ROUND, WHITELIST, WHITELIST_ADMINS,
5252
};
5353
use crate::token_manager::{
5454
add_token_info_providers, handle_token_info_provider_add_remove,
@@ -59,7 +59,7 @@ use crate::utils::{
5959
get_highest_known_height_for_round_id, get_lock_time_weighted_shares, get_owned_lock_entry,
6060
load_constants_active_at_timestamp, load_current_constants, run_on_each_transaction,
6161
scale_lockup_power, to_lockup_with_power, update_locked_tokens_info,
62-
validate_locked_tokens_caps,
62+
validate_locked_tokens_caps, verify_historical_data_availability,
6363
};
6464
use crate::validators_icqs::{
6565
build_create_interchain_query_submsg, handle_delivered_interchain_query_result,
@@ -1820,13 +1820,6 @@ pub fn query(deps: Deps<NeutronQuery>, env: Env, msg: QueryMsg) -> StdResult<Bin
18201820
tranche_id,
18211821
address,
18221822
} => to_json_binary(&query_user_votes(deps, round_id, tranche_id, address)?),
1823-
QueryMsg::UserVotedLocks {
1824-
round_id,
1825-
tranche_id,
1826-
address,
1827-
} => to_json_binary(&query_user_voted_locks(
1828-
deps, round_id, tranche_id, address,
1829-
)?),
18301823
QueryMsg::AllVotes { start_from, limit } => {
18311824
to_json_binary(&query_all_votes(deps, start_from, limit)?)
18321825
}
@@ -2235,17 +2228,38 @@ pub fn query_user_votes(
22352228
let user_address = deps.api.addr_validate(&user_address)?;
22362229
let mut voted_proposals_power_sum: HashMap<u64, Decimal> = HashMap::new();
22372230

2238-
// Get the user's locks from USER_LOCKS
2239-
let user_locks = USER_LOCKS
2240-
.may_load(deps.storage, user_address.clone())?
2241-
.unwrap_or_default();
2231+
// The USER_LOCKS only has history starting from round_id: 3
2232+
// Before that round, we cannot query USER_LOCKS, which is necessary to check votes from VOTE_MAP_V2
2233+
// So, we need to query VOTE_MAP_V1 for those rounds
2234+
let round_highest_height = get_highest_known_height_for_round_id(deps.storage, round_id)?;
2235+
let is_historical_data_available =
2236+
verify_historical_data_availability(deps.storage, round_highest_height);
22422237

2243-
// Collect all votes for user's locks
22442238
let mut votes = Vec::new();
2245-
for lock_id in user_locks {
2246-
let vote = VOTE_MAP_V2.may_load(deps.storage, ((round_id, tranche_id), lock_id))?;
2247-
if let Some(vote) = vote {
2248-
votes.push(vote);
2239+
2240+
if is_historical_data_available.is_err() {
2241+
// We still use the old VOTE_MAP_V1 store for where there's no historical data available
2242+
votes = VOTE_MAP_V1
2243+
.prefix(((round_id, tranche_id), user_address.clone()))
2244+
.range(deps.storage, None, None, Order::Ascending)
2245+
.filter_map(|vote| match vote {
2246+
Err(_) => None,
2247+
Ok(vote) => Some(vote.1),
2248+
})
2249+
.collect::<Vec<Vote>>();
2250+
} else {
2251+
// Get the user's locks from USER_LOCKS.
2252+
// If the lock was created at round_highest_height, it should still be counted (hence the load_at_height + 1)
2253+
let user_locks = USER_LOCKS
2254+
.may_load_at_height(deps.storage, user_address.clone(), round_highest_height + 1)?
2255+
.unwrap_or_default();
2256+
2257+
// Collect all votes for user's locks
2258+
for lock_id in user_locks {
2259+
let vote = VOTE_MAP_V2.may_load(deps.storage, ((round_id, tranche_id), lock_id))?;
2260+
if let Some(vote) = vote {
2261+
votes.push(vote);
2262+
}
22492263
}
22502264
}
22512265

@@ -2287,64 +2301,6 @@ pub fn query_user_votes(
22872301
Ok(UserVotesResponse { votes })
22882302
}
22892303

2290-
// This function queries user voted locks for the given round and tranche.
2291-
// Unlike query_user_votes which aggregates voting power by proposal,
2292-
// this function returns the individual locks that voted for each proposal
2293-
// along with their voting power, to support transferable locks in the tribute contract.
2294-
pub fn query_user_voted_locks(
2295-
deps: Deps<NeutronQuery>,
2296-
round_id: u64,
2297-
tranche_id: u64,
2298-
user_address: String,
2299-
) -> StdResult<UserVotedLocksResponse> {
2300-
let user_address = deps.api.addr_validate(&user_address)?;
2301-
let mut voted_proposals_locks: HashMap<u64, Vec<VotedLockInfo>> = HashMap::new();
2302-
// Get the users locks from USER_LOCKS for the given height
2303-
let round_highest_height = get_highest_known_height_for_round_id(deps.storage, round_id)?;
2304-
let user_locks = USER_LOCKS
2305-
.may_load_at_height(deps.storage, user_address.clone(), round_highest_height)?
2306-
.unwrap_or_default();
2307-
2308-
let mut token_manager = TokenManager::new(&deps);
2309-
2310-
// For each user lock, check if it voted in this round/tranche
2311-
for lock_id in user_locks {
2312-
if let Some(vote) = VOTE_MAP_V2.may_load(deps.storage, ((round_id, tranche_id), lock_id))? {
2313-
let vote_token_group_id = vote.time_weighted_shares.0.clone();
2314-
let token_ratio =
2315-
token_manager.get_token_group_ratio(&deps, round_id, vote_token_group_id)?;
2316-
2317-
// Calculate the vote power
2318-
let vote_power = vote.time_weighted_shares.1.checked_mul(token_ratio)?;
2319-
2320-
// Skip votes with zero power (happens if token ratio became zero)
2321-
if vote_power == Decimal::zero() {
2322-
continue;
2323-
}
2324-
2325-
// Add this lock to the map for its proposal
2326-
voted_proposals_locks
2327-
.entry(vote.prop_id)
2328-
.or_default()
2329-
.push(VotedLockInfo {
2330-
lock_id,
2331-
power: vote_power,
2332-
});
2333-
}
2334-
}
2335-
2336-
if voted_proposals_locks.is_empty() {
2337-
return Err(StdError::generic_err(
2338-
"User didn't vote in the given round and tranche",
2339-
));
2340-
}
2341-
2342-
// Convert the HashMap to a Vec of tuples
2343-
let voted_locks: Vec<(u64, Vec<VotedLockInfo>)> = voted_proposals_locks.into_iter().collect();
2344-
2345-
Ok(UserVotedLocksResponse { voted_locks })
2346-
}
2347-
23482304
pub fn query_all_votes(
23492305
deps: Deps<NeutronQuery>,
23502306
start_from: u32,

contracts/hydro/src/query.rs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
token_manager::TokenInfoProvider,
55
};
66
use cosmwasm_schema::{cw_serde, QueryResponses};
7-
use cosmwasm_std::{Addr, Decimal, Timestamp, Uint128};
7+
use cosmwasm_std::{Addr, Timestamp, Uint128};
88

99
#[cw_serde]
1010
#[derive(QueryResponses, cw_orch::QueryFns)]
@@ -60,13 +60,6 @@ pub enum QueryMsg {
6060
address: String,
6161
},
6262

63-
#[returns(UserVotedLocksResponse)]
64-
UserVotedLocks {
65-
round_id: u64,
66-
tranche_id: u64,
67-
address: String,
68-
},
69-
7063
#[returns(AllVotesResponse)]
7164
AllVotes { start_from: u32, limit: u32 },
7265

@@ -244,19 +237,6 @@ pub struct UserVotesResponse {
244237
pub votes: Vec<VoteWithPower>,
245238
}
246239

247-
#[cw_serde]
248-
pub struct VotedLockInfo {
249-
pub lock_id: u64,
250-
pub power: Decimal,
251-
}
252-
253-
#[cw_serde]
254-
pub struct UserVotedLocksResponse {
255-
// Maps proposal_id to a list of locks that voted for it with their voting power
256-
// The first item in each tuple is the proposal_id
257-
pub voted_locks: Vec<(u64, Vec<VotedLockInfo>)>,
258-
}
259-
260240
#[cw_serde]
261241
pub struct VoteEntry {
262242
pub round_id: u64,

contracts/hydro/src/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ pub struct Proposal {
187187
pub minimum_atom_liquidity_request: Uint128,
188188
}
189189

190-
// VOTE_MAP_V1: Previous structure, now preserved for migration
190+
// VOTE_MAP_V1: Previous structure, we need to keep it until all the tributes are claimed for round 0
191191
// VOTE_MAP: key((round_id, tranche_id), sender_addr, lock_id) -> Vote
192192
pub const VOTE_MAP_V1: Map<((u64, u64), Addr, u64), Vote> = Map::new("vote_map");
193193

contracts/hydro/src/testing_queries.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::contract::{
99
use crate::msg::ProposalToLockups;
1010
use crate::query::VoteEntry;
1111
use crate::state::{
12-
RoundLockPowerSchedule, ValidatorInfo, Vote, LOCKS_MAP_V2, TOKEN_INFO_PROVIDERS, USER_LOCKS,
13-
VALIDATORS_INFO, VOTE_MAP_V2,
12+
HeightRange, RoundLockPowerSchedule, ValidatorInfo, Vote, LOCKS_MAP_V2, ROUND_TO_HEIGHT_RANGE,
13+
SNAPSHOTS_ACTIVATION_HEIGHT, TOKEN_INFO_PROVIDERS, USER_LOCKS, VALIDATORS_INFO, VOTE_MAP_V2,
1414
};
1515
use crate::testing::{
1616
get_default_instantiate_msg, get_default_lsm_token_info_provider, get_message_info,
@@ -821,6 +821,20 @@ fn query_user_votes_test() {
821821
println!("running test case: {}", test_case.description);
822822
let (mut deps, _env) = (mock_dependencies(no_op_grpc_query_mock()), mock_env());
823823

824+
let height_range = HeightRange {
825+
lowest_known_height: 0,
826+
highest_known_height: env.block.height,
827+
};
828+
829+
// We need to fill these stores or query_user_votes won't work
830+
ROUND_TO_HEIGHT_RANGE
831+
.save(&mut deps.storage, round_id, &height_range)
832+
.unwrap();
833+
834+
SNAPSHOTS_ACTIVATION_HEIGHT
835+
.save(&mut deps.storage, &0)
836+
.unwrap();
837+
824838
for vote_to_create in &test_case.votes_to_create {
825839
let mut lock_ids = USER_LOCKS
826840
.load(&deps.storage, test_case.voter.clone())

0 commit comments

Comments
 (0)