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

Allow tributes for proposals in past rounds #147

Merged
merged 9 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
2 changes: 1 addition & 1 deletion artifacts/checksums.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
b8ad3e6620dffc6b4d0357d983333d6db3f2ec4a485f0b87906bcff6c6e223e1 hydro.wasm
b522862cb198bbfa2cab046110b4d26a590dea315fe838af3cf1455cad41f9b7 tribute.wasm
923dbd99ceddf13394eaf9e861500b284f523cab01b991a13b6692acde167992 tribute.wasm
Binary file modified artifacts/tribute.wasm
Binary file not shown.
6 changes: 6 additions & 0 deletions contracts/tribute/schema/execute_msg.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"type": "object",
"required": [
"proposal_id",
"round_id",
"tranche_id"
],
"properties": {
Expand All @@ -20,6 +21,11 @@
"format": "uint64",
"minimum": 0.0
},
"round_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"tranche_id": {
"type": "integer",
"format": "uint64",
Expand Down
6 changes: 6 additions & 0 deletions contracts/tribute/schema/tribute_full_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"type": "object",
"required": [
"proposal_id",
"round_id",
"tranche_id"
],
"properties": {
Expand All @@ -41,6 +42,11 @@
"format": "uint64",
"minimum": 0.0
},
"round_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"tranche_id": {
"type": "integer",
"format": "uint64",
Expand Down
19 changes: 7 additions & 12 deletions contracts/tribute/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ pub fn execute(
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::AddTribute {
round_id,
tranche_id,
proposal_id,
} => add_tribute(deps, info, tranche_id, proposal_id),
} => add_tribute(deps, info, round_id, tranche_id, proposal_id),
ExecuteMsg::ClaimTribute {
round_id,
tranche_id,
Expand All @@ -82,20 +83,14 @@ pub fn execute(
fn add_tribute(
deps: DepsMut,
info: MessageInfo,
round_id: u64,
tranche_id: u64,
proposal_id: u64,
) -> Result<Response, ContractError> {
let hydro_contract = CONFIG.load(deps.storage)?.hydro_contract;
let current_round_id = query_current_round_id(&deps, &hydro_contract)?;

// Check that the proposal exists
query_proposal(
&deps,
&hydro_contract,
current_round_id,
tranche_id,
proposal_id,
)?;
query_proposal(&deps, &hydro_contract, round_id, tranche_id, proposal_id)?;

// Check that the sender has sent funds
if info.funds.is_empty() {
Expand All @@ -115,7 +110,7 @@ fn add_tribute(
let tribute_id = TRIBUTE_ID.load(deps.storage)?;
TRIBUTE_ID.save(deps.storage, &(tribute_id + 1))?;
let tribute = Tribute {
round_id: current_round_id,
round_id: round_id,
tranche_id,
proposal_id,
tribute_id,
Expand All @@ -125,15 +120,15 @@ fn add_tribute(
};
TRIBUTE_MAP.save(
deps.storage,
(current_round_id, proposal_id, tribute_id),
(round_id, proposal_id, tribute_id),
&tribute_id,
)?;
ID_TO_TRIBUTE_MAP.save(deps.storage, tribute_id, &tribute)?;

Ok(Response::new()
.add_attribute("action", "add_tribute")
.add_attribute("depositor", info.sender.clone())
.add_attribute("round_id", current_round_id.to_string())
.add_attribute("round_id", round_id.to_string())
.add_attribute("tranche_id", tranche_id.to_string())
.add_attribute("proposal_id", proposal_id.to_string())
.add_attribute("tribute_id", tribute_id.to_string())
Expand Down
6 changes: 5 additions & 1 deletion contracts/tribute/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ pub struct InstantiateMsg {
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
#[cw_orch(payable)]
AddTribute { tranche_id: u64, proposal_id: u64 },
AddTribute {
round_id: u64,
tranche_id: u64,
proposal_id: u64,
},
ClaimTribute {
round_id: u64,
tranche_id: u64,
Expand Down
29 changes: 17 additions & 12 deletions contracts/tribute/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl MockWasmQuerier {
Ok(res) => res,
Err(_) => {
return SystemResult::Err(SystemError::InvalidRequest {
error: "proposal couldn't be found".to_string(),
error: format!("proposal couldn't be found: round_id={}, tranche_id={}, proposal_id={}", round_id, tranche_id, proposal_id),
request: Binary::new(vec![]),
})
}
Expand Down Expand Up @@ -180,8 +180,6 @@ impl MockWasmQuerier {

struct AddTributeTestCase {
description: String,
// (tranche_id, proposal_id)
proposal_info: (u64, u64),
tributes_to_add: Vec<Vec<Coin>>,
// (current_round_id, proposal_to_tribute)
mock_data: (u64, Vec<Proposal>),
Expand Down Expand Up @@ -234,7 +232,6 @@ fn add_tribute_test() {
let test_cases: Vec<AddTributeTestCase> = vec![
AddTributeTestCase {
description: "happy path".to_string(),
proposal_info: (0, 5),
tributes_to_add: vec![
vec![Coin::new(1000u64, DEFAULT_DENOM)],
vec![Coin::new(5000u64, DEFAULT_DENOM)],
Expand All @@ -245,23 +242,20 @@ fn add_tribute_test() {
},
AddTributeTestCase {
description: "try adding tribute for non-existing proposal".to_string(),
proposal_info: (0, 5),
tributes_to_add: vec![vec![Coin::new(1000u64, DEFAULT_DENOM)]],
mock_data: (10, vec![]),
expected_success: false,
expected_error_msg: "proposal couldn't be found".to_string(),
},
AddTributeTestCase {
description: "try adding tribute without providing any funds".to_string(),
proposal_info: (0, 5),
tributes_to_add: vec![vec![]],
mock_data: (10, vec![mock_proposal.clone()]),
expected_success: false,
expected_error_msg: "Must send funds to add tribute".to_string(),
},
AddTributeTestCase {
description: "try adding tribute by providing more than one token".to_string(),
proposal_info: (0, 5),
tributes_to_add: vec![vec![
Coin::new(1000u64, DEFAULT_DENOM),
Coin::new(1000u64, "stake"),
Expand All @@ -270,6 +264,14 @@ fn add_tribute_test() {
expected_success: false,
expected_error_msg: "Must send exactly one coin".to_string(),
},
AddTributeTestCase {
description: "add tribute to previous round".to_string(),
tributes_to_add: vec![vec![Coin::new(1000u64, DEFAULT_DENOM)]],
// proposal is in round 10, but we are trying to add tribute during round 11
mock_data: (11, vec![mock_proposal.clone()]),
expected_success: true,
expected_error_msg: String::new(),
},
];

for test in test_cases {
Expand Down Expand Up @@ -298,13 +300,14 @@ fn add_tribute_test() {
for tribute in &test.tributes_to_add {
let info = get_message_info(&deps.api, tribute_payer, tribute);
let msg = ExecuteMsg::AddTribute {
tranche_id: test.proposal_info.0,
proposal_id: test.proposal_info.1,
tranche_id: mock_proposal.tranche_id,
round_id: mock_proposal.round_id,
proposal_id: mock_proposal.proposal_id,
};

let res = execute(deps.as_mut(), env.clone(), info.clone(), msg);
if test.expected_success {
assert!(res.is_ok());
assert!(res.is_ok(), "failed with: {}", res.unwrap_err());
} else {
assert!(res
.unwrap_err()
Expand All @@ -320,8 +323,8 @@ fn add_tribute_test() {

let res = query_proposal_tributes(
deps.as_ref(),
test.mock_data.0,
test.proposal_info.1,
mock_proposal.round_id,
mock_proposal.proposal_id,
0,
3000,
)
Expand Down Expand Up @@ -508,6 +511,7 @@ fn claim_tribute_test() {
let info = get_message_info(&deps.api, tribute_payer, &test.tribute_to_add);
let msg = ExecuteMsg::AddTribute {
tranche_id: test.tribute_info.1,
round_id: test.tribute_info.0,
proposal_id: test.tribute_info.2,
};

Expand Down Expand Up @@ -662,6 +666,7 @@ fn refund_tribute_test() {
let info = get_message_info(&deps.api, tribute_payer, &test.tribute_to_add);
let msg = ExecuteMsg::AddTribute {
tranche_id: test.tribute_info.1,
round_id: test.tribute_info.0,
proposal_id: test.tribute_info.2,
};

Expand Down
9 changes: 8 additions & 1 deletion docs/oversight_committee.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@ and verify the results.
This is how you can query the top N proposals using the command line (make sure to put the right contract address and query parameters):
```bash
neutrond q wasm contract-state smart neutron192s005pfsx7j397l4jarhgu8gs2lcgwyuntehp6wundrh8pgkywqgss0tm "{\"top_n_proposals\": {\"round_id\": 0, \"tranche_id\": 1, \"number_of_proposals\": 5}}"
```
```

## Revenue Sharing

Revenue sharing (i.e. distributing a portion of the profit made by a liquidity deployment to
its voters) is enabled in Hydro by utilizing the tribute contract.
While projects would add their tribute *during* a round, the revenue sharing is done *after* the round has ended, where the committee can simply add the appropriate revenue that should
be shared with voters as a tribute.
3 changes: 2 additions & 1 deletion test/interchain/hydro_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,10 +685,11 @@ func (s *HydroSuite) WithdrawICQFunds(contractAddr string, amount int64) error {
return nil
}

func (s *HydroSuite) SubmitTribute(validatorIndex, amount, trancheId, proposalId int, contractAddr string) (int, error) {
func (s *HydroSuite) SubmitTribute(validatorIndex, amount, round_id, trancheId, proposalId int, contractAddr string) (int, error) {
txData := map[string]interface{}{
"add_tribute": map[string]interface{}{
"tranche_id": trancheId,
"round_id": round_id,
"proposal_id": proposalId,
},
}
Expand Down
32 changes: 28 additions & 4 deletions test/interchain/hydro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,13 @@ func (s *HydroSuite) TestTributeContract() {
roundId := s.GetCurrentRound(hydroContractAddr) // all proposals are expected to be submitted in the same round

// validator 1 adds tribute for proposals
tribute1Id, err := s.SubmitTribute(0, 10000, proposal1.TrancheID, proposal1.ProposalID, tributeContractAddr)
tribute1Id, err := s.SubmitTribute(0, 10000, proposal1.RoundID, proposal1.TrancheID, proposal1.ProposalID, tributeContractAddr)
s.Require().NoError(err)
tribute2Id, err := s.SubmitTribute(0, 20000, proposal2.TrancheID, proposal2.ProposalID, tributeContractAddr)
tribute2Id, err := s.SubmitTribute(0, 20000, proposal2.RoundID, proposal2.TrancheID, proposal2.ProposalID, tributeContractAddr)
s.Require().NoError(err)
tribute3Id, err := s.SubmitTribute(0, 30000, proposal3.TrancheID, proposal3.ProposalID, tributeContractAddr)
tribute3Id, err := s.SubmitTribute(0, 30000, proposal3.RoundID, proposal3.TrancheID, proposal3.ProposalID, tributeContractAddr)
s.Require().NoError(err)
tribute4Id, err := s.SubmitTribute(3, 40000, proposal4.TrancheID, proposal4.ProposalID, tributeContractAddr)
tribute4Id, err := s.SubmitTribute(3, 40000, proposal4.RoundID, proposal4.TrancheID, proposal4.ProposalID, tributeContractAddr)
s.Require().NoError(err)

// val2 votes for proposal 1
Expand Down Expand Up @@ -508,4 +508,28 @@ func (s *HydroSuite) TestTributeContract() {
s.Require().True(newBalanceVal3.Sub(oldBalanceVal3).Equal(math.NewInt(20000))) // reward is tribute for proposal2 = 20000
s.Require().True(newBalanceVal1.GT(oldBalanceVal1)) // refunded proposal3
s.Require().True(newBalanceVal4.GT(oldBalanceVal4)) // refunded proposal4

// verify that we can add a tribute to proposals even after the round has ended
tribute5Id, err := s.SubmitTribute(0, 50000, proposal1.RoundID, proposal1.TrancheID, proposal1.ProposalID, tributeContractAddr)
s.Require().NoError(err)
tribute6Id, err := s.SubmitTribute(0, 50000, proposal3.RoundID, proposal3.TrancheID, proposal3.ProposalID, tributeContractAddr)
s.Require().NoError(err)

// users can claim immediately, since the voting period for the proposal is over
// expect no error when claiming the tribute for prop 1
err = s.ClaimTribute(0, tributeContractAddr, s.NeutronChain.ValidatorWallets[1].Address, proposal4.RoundID, proposal4.TrancheID, tribute5Id)
s.Require().NoError(err)
// expect an error when claiming the tribute for prop 4, since it is not in the top N proposals
err = s.ClaimTribute(0, tributeContractAddr, s.NeutronChain.ValidatorWallets[3].Address, proposal4.RoundID, proposal4.TrancheID, tribute6Id)
s.Require().Error(err)
s.Require().Contains(err.Error(), "outside of top N proposals")

// also, tributes can be refund immediately, since the voting period for the proposal is over
// expect an error refunding tribute 5 since it was for a top n proposal
err = s.RefundTribute(0, tributeContractAddr, proposal4.RoundID, proposal4.TrancheID, tribute5Id, proposal1.ProposalID)
s.Require().Error(err)

// expect no error when refunding tribute 6 since it was for a proposal that was not in the top N
err = s.RefundTribute(0, tributeContractAddr, proposal4.RoundID, proposal4.TrancheID, tribute6Id, proposal3.ProposalID)
s.Require().NoError(err)
}
5 changes: 5 additions & 0 deletions ts_types/TributeBase.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,11 @@ export interface TributeBaseInterface extends TributeBaseReadOnlyInterface {
sender: string;
addTribute: ({
proposalId,
roundId,
trancheId
}: {
proposalId: number;
roundId: number;
trancheId: number;
}, fee?: number | StdFee | "auto", memo?: string, _funds?: Coin[]) => Promise<ExecuteResult>;
claimTribute: ({
Expand Down Expand Up @@ -196,14 +198,17 @@ export class TributeBaseClient extends TributeBaseQueryClient implements Tribute
}
addTribute = async ({
proposalId,
roundId,
trancheId
}: {
proposalId: number;
roundId: number;
trancheId: number;
}, fee: number | StdFee | "auto" = "auto", memo?: string, _funds?: Coin[]): Promise<ExecuteResult> => {
return await this.client.execute(this.sender, this.contractAddress, {
add_tribute: {
proposal_id: proposalId,
round_id: roundId,
tranche_id: trancheId
}
}, fee, memo, _funds);
Expand Down
1 change: 1 addition & 0 deletions ts_types/TributeBase.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface Config {
export type ExecuteMsg = {
add_tribute: {
proposal_id: number;
round_id: number;
tranche_id: number;
};
} | {
Expand Down
Loading