diff --git a/contracts/voting/dao-voting-onft-staked/src/contract.rs b/contracts/voting/dao-voting-onft-staked/src/contract.rs index 9c105ddd7..32ab9f8d6 100644 --- a/contracts/voting/dao-voting-onft-staked/src/contract.rs +++ b/contracts/voting/dao-voting-onft-staked/src/contract.rs @@ -146,10 +146,14 @@ pub fn execute_confirm_stake( deps: DepsMut, env: Env, info: MessageInfo, - token_ids: Vec, + mut token_ids: Vec, ) -> Result { let config = CONFIG.load(deps.storage)?; + // de-duplicate token IDs to prevent double-counting exploit + token_ids.sort(); + token_ids.dedup(); + // verify sender prepared and transferred all the tokens let sender_prepared_all = token_ids .iter() diff --git a/contracts/voting/dao-voting-onft-staked/src/testing/tests.rs b/contracts/voting/dao-voting-onft-staked/src/testing/tests.rs index cbd807060..4e5e5e0bb 100644 --- a/contracts/voting/dao-voting-onft-staked/src/testing/tests.rs +++ b/contracts/voting/dao-voting-onft-staked/src/testing/tests.rs @@ -62,6 +62,25 @@ fn test_stake_tokens() -> anyhow::Result<()> { assert_eq!(total, Uint128::new(1)); assert_eq!(personal, Uint128::new(1)); + // Registering duplicate token IDs does not provide more voting power. + mint_nft(&mut app, &nft, STAKER, "2")?; + prepare_stake_nft(&mut app, &module, STAKER, "2")?; + send_nft(&mut app, &nft, "2", STAKER, module.as_str())?; + app.execute_contract( + Addr::unchecked(STAKER), + module.clone(), + &ExecuteMsg::ConfirmStake { + token_ids: vec!["2".to_string(), "2".to_string(), "2".to_string()], + }, + &[], + )?; + + app.update_block(next_block); + + let (total, personal) = query_total_and_voting_power(&app, &module, STAKER, None)?; + assert_eq!(total, Uint128::new(2)); + assert_eq!(personal, Uint128::new(2)); + Ok(()) }