use cosmwasm_std::{Deps, Order, StdResult};
use cw20::{AllAccountsResponse, AllAllowancesResponse, AllowanceInfo};
use crate::state::{ALLOWANCES, BALANCES};
use cw_storage_plus::Bound;
const MAX_LIMIT: u32 = 30;
const DEFAULT_LIMIT: u32 = 10;
pub fn query_all_allowances(
deps: Deps,
owner: String,
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<AllAllowancesResponse> {
let owner_addr = deps.api.addr_validate(&owner)?;
let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;
let start = start_after.map(Bound::exclusive);
let allowances: StdResult<Vec<AllowanceInfo>> = ALLOWANCES
.prefix(&owner_addr)
.range(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|item| {
let (k, v) = item?;
Ok(AllowanceInfo {
spender: String::from_utf8(k)?,
allowance: v.allowance,
expires: v.expires,
})
})
.collect();
Ok(AllAllowancesResponse {
allowances: allowances?,
})
}
pub fn query_all_accounts(
deps: Deps,
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<AllAccountsResponse> {
let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;
let start = start_after.map(Bound::exclusive);
let accounts: Result<Vec<_>, _> = BALANCES
.keys(deps.storage, start, None, Order::Ascending)
.map(String::from_utf8)
.take(limit)
.collect();
Ok(AllAccountsResponse {
accounts: accounts?,
})
}
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, DepsMut, Uint128};
use cw20::{Cw20Coin, Expiration, TokenInfoResponse};
use crate::contract::{execute, instantiate, query_token_info};
use crate::msg::{ExecuteMsg, InstantiateMsg};
fn do_instantiate(mut deps: DepsMut, addr: &str, amount: Uint128) -> TokenInfoResponse {
let instantiate_msg = InstantiateMsg {
name: "Auto Gen".to_string(),
symbol: "AUTO".to_string(),
decimals: 3,
initial_balances: vec![Cw20Coin {
address: addr.into(),
amount,
}],
mint: None,
};
let info = mock_info("creator", &[]);
let env = mock_env();
instantiate(deps.branch(), env, info, instantiate_msg).unwrap();
query_token_info(deps.as_ref()).unwrap()
}
#[test]
fn query_all_allowances_works() {
let mut deps = mock_dependencies(&coins(2, "token"));
let owner = String::from("owner");
let spender1 = String::from("earlier");
let spender2 = String::from("later");
let info = mock_info(owner.as_ref(), &[]);
let env = mock_env();
do_instantiate(deps.as_mut(), &owner, Uint128::new(12340000));
let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, None).unwrap();
assert_eq!(allowances.allowances, vec![]);
let allow1 = Uint128::new(7777);
let expires = Expiration::AtHeight(5432);
let msg = ExecuteMsg::IncreaseAllowance {
spender: spender1.clone(),
amount: allow1,
expires: Some(expires),
};
execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap();
let allow2 = Uint128::new(54321);
let msg = ExecuteMsg::IncreaseAllowance {
spender: spender2.clone(),
amount: allow2,
expires: None,
};
execute(deps.as_mut(), env, info, msg).unwrap();
let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, None).unwrap();
assert_eq!(allowances.allowances.len(), 2);
let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, Some(1)).unwrap();
assert_eq!(allowances.allowances.len(), 1);
let allow = &allowances.allowances[0];
assert_eq!(&allow.spender, &spender1);
assert_eq!(&allow.expires, &expires);
assert_eq!(&allow.allowance, &allow1);
let allowances = query_all_allowances(
deps.as_ref(),
owner,
Some(allow.spender.clone()),
Some(10000),
)
.unwrap();
assert_eq!(allowances.allowances.len(), 1);
let allow = &allowances.allowances[0];
assert_eq!(&allow.spender, &spender2);
assert_eq!(&allow.expires, &Expiration::Never {});
assert_eq!(&allow.allowance, &allow2);
}
#[test]
fn query_all_accounts_works() {
let mut deps = mock_dependencies(&coins(2, "token"));
let acct1 = String::from("acct01");
let acct2 = String::from("zebra");
let acct3 = String::from("nice");
let acct4 = String::from("aaaardvark");
let expected_order = [acct4.clone(), acct1.clone(), acct3.clone(), acct2.clone()];
do_instantiate(deps.as_mut(), &acct1, Uint128::new(12340000));
let info = mock_info(acct1.as_ref(), &[]);
let env = mock_env();
execute(
deps.as_mut(),
env.clone(),
info.clone(),
ExecuteMsg::Transfer {
recipient: acct2,
amount: Uint128::new(222222),
},
)
.unwrap();
execute(
deps.as_mut(),
env.clone(),
info.clone(),
ExecuteMsg::Transfer {
recipient: acct3,
amount: Uint128::new(333333),
},
)
.unwrap();
execute(
deps.as_mut(),
env,
info,
ExecuteMsg::Transfer {
recipient: acct4,
amount: Uint128::new(444444),
},
)
.unwrap();
let accounts = query_all_accounts(deps.as_ref(), None, None).unwrap();
assert_eq!(accounts.accounts, expected_order);
let accounts = query_all_accounts(deps.as_ref(), None, Some(2)).unwrap();
assert_eq!(accounts.accounts, expected_order[0..2].to_vec());
let accounts =
query_all_accounts(deps.as_ref(), Some(accounts.accounts[1].clone()), Some(1)).unwrap();
assert_eq!(accounts.accounts, expected_order[2..3].to_vec());
let accounts =
query_all_accounts(deps.as_ref(), Some(accounts.accounts[0].clone()), Some(777))
.unwrap();
assert_eq!(accounts.accounts, expected_order[3..].to_vec());
}
}