Skip to content

Commit

Permalink
feat: eliminate dust
Browse files Browse the repository at this point in the history
  • Loading branch information
ratik committed Dec 13, 2022
1 parent 6d877f1 commit efeba00
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 7 deletions.
33 changes: 27 additions & 6 deletions contracts/distribution/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cosmwasm_std::{
use cw_storage_plus::KeyDeserialize;

use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{Config, CONFIG, PENDING_DISTRIBUTION, SHARES};
use crate::state::{Config, CONFIG, FUND_COUNTER, PENDING_DISTRIBUTION, SHARES};

//--------------------------------------------------------------------------------------------------
// Instantiation
Expand Down Expand Up @@ -89,6 +89,7 @@ fn get_denom_amount(coins: Vec<Coin>, denom: String) -> Option<Uint128> {
pub fn execute_fund(deps: DepsMut, info: MessageInfo) -> StdResult<Response> {
let config: Config = CONFIG.load(deps.storage)?;
let denom = config.denom;
let fund_counter = FUND_COUNTER.may_load(deps.storage)?.unwrap_or(0);
let funds = get_denom_amount(info.funds, denom).unwrap_or(Uint128::zero());
if funds.is_zero() {
return Err(StdError::generic_err("no funds sent"));
Expand All @@ -101,14 +102,34 @@ pub fn execute_fund(deps: DepsMut, info: MessageInfo) -> StdResult<Response> {
return Err(StdError::generic_err("no shares set"));
}
let total_shares = shares.iter().fold(Uint128::zero(), |acc, (_, s)| acc + s);
for (addr, share) in shares {
let amount = funds.checked_mul(share)?.checked_div(total_shares)?;
let mut spent = Uint128::zero();
let mut resp = Response::new().add_attribute("action", "neutron/distribution/fund");

for (addr, share) in shares.iter() {
let amount = funds.checked_mul(*share)?.checked_div(total_shares)?;
let pending = PENDING_DISTRIBUTION
.may_load(deps.storage, addr)?
.unwrap_or(Uint128::zero());
PENDING_DISTRIBUTION.save(deps.storage, addr, &(pending.checked_add(amount)?))?;
spent = spent.checked_add(amount)?;
resp = resp
.add_attribute("address", Addr::from_slice(addr)?)
.add_attribute("amount", amount);
}
let remaining = funds.checked_sub(spent)?;
if !remaining.is_zero() {
let index = fund_counter % shares.len() as u64;
let key = &shares.get(index as usize).unwrap().0;
let pending = PENDING_DISTRIBUTION
.may_load(deps.storage, &addr)?
.may_load(deps.storage, key)?
.unwrap_or(Uint128::zero());
PENDING_DISTRIBUTION.save(deps.storage, &addr, &(pending.checked_add(amount)?))?;
PENDING_DISTRIBUTION.save(deps.storage, key, &(pending.checked_add(remaining)?))?;
resp = resp
.add_attribute("remainder_address", Addr::from_slice(key)?)
.add_attribute("remainder_amount", remaining);
}
Ok(Response::new().add_attribute("action", "neutron/distribution/fund"))
FUND_COUNTER.save(deps.storage, &(fund_counter + 1))?;
Ok(resp)
}

pub fn execute_set_shares(
Expand Down
2 changes: 2 additions & 0 deletions contracts/distribution/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ pub const PENDING_DISTRIBUTION: Map<&[u8], Uint128> = Map::new("pending_distribu
pub const SHARES: Map<&[u8], Uint128> = Map::new("shares");

pub const CONFIG: Item<Config> = Item::new("config");

pub const FUND_COUNTER: Item<u64> = Item::new("fund_counter");
47 changes: 46 additions & 1 deletion contracts/distribution/src/testing/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cosmwasm_std::{
use crate::{
contract::{execute, instantiate},
msg::{ExecuteMsg, InstantiateMsg},
state::{CONFIG, PENDING_DISTRIBUTION, SHARES},
state::{CONFIG, FUND_COUNTER, PENDING_DISTRIBUTION, SHARES},
testing::mock_querier::mock_dependencies,
};

Expand Down Expand Up @@ -96,6 +96,51 @@ fn test_fund_success() {
.unwrap(),
Uint128::from(7500u128)
);
let fund_counter = FUND_COUNTER.load(deps.as_ref().storage).unwrap();
assert_eq!(fund_counter, 1u64);
}

#[test]
fn test_fund_success_with_dust() {
let mut deps = mock_dependencies(&[]);
init_base_contract(deps.as_mut());
SHARES
.save(
deps.as_mut().storage,
"addr1".as_bytes(),
&Uint128::from(1u128),
)
.unwrap();
SHARES
.save(
deps.as_mut().storage,
"addr2".as_bytes(),
&Uint128::from(3u128),
)
.unwrap();
let msg = ExecuteMsg::Fund {};
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("someone", &[coin(10001u128, DENOM)]),
msg,
);
assert!(res.is_ok());
println!("{:?}", res.unwrap().attributes);
assert_eq!(
PENDING_DISTRIBUTION
.load(deps.as_ref().storage, "addr1".as_bytes())
.unwrap(),
Uint128::from(2501u128)
);
assert_eq!(
PENDING_DISTRIBUTION
.load(deps.as_ref().storage, "addr2".as_bytes())
.unwrap(),
Uint128::from(7500u128)
);
let fund_counter = FUND_COUNTER.load(deps.as_ref().storage).unwrap();
assert_eq!(fund_counter, 1u64);
}

#[test]
Expand Down
3 changes: 3 additions & 0 deletions contracts/treasury/schema/instantiate_msg.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@
"type": "string"
},
"distribution_contract": {
"description": "Address of distribution contract",
"type": "string"
},
"distribution_rate": {
"description": "Distribution rate in percent (0-100) which goes to distribution contract",
"type": "integer",
"format": "uint8",
"minimum": 0.0
},
"min_period": {
"description": "Minimum period between distribution calls",
"type": "integer",
"format": "uint64",
"minimum": 0.0
Expand Down

0 comments on commit efeba00

Please sign in to comment.