github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/dev/wasm/cw20-base/src/enumerable.rs (about) 1 use cosmwasm_std::{Deps, Order, StdResult}; 2 use cw20::{AllAccountsResponse, AllAllowancesResponse, AllowanceInfo}; 3 4 use crate::state::{ALLOWANCES, BALANCES}; 5 use cw_storage_plus::Bound; 6 7 // settings for pagination 8 const MAX_LIMIT: u32 = 30; 9 const DEFAULT_LIMIT: u32 = 10; 10 11 pub fn query_all_allowances( 12 deps: Deps, 13 owner: String, 14 start_after: Option<String>, 15 limit: Option<u32>, 16 ) -> StdResult<AllAllowancesResponse> { 17 let owner_addr = deps.api.addr_validate(&owner)?; 18 let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; 19 let start = start_after.map(|s| Bound::ExclusiveRaw(s.into_bytes())); 20 21 let allowances = ALLOWANCES 22 .prefix(&owner_addr) 23 .range(deps.storage, start, None, Order::Ascending) 24 .take(limit) 25 .map(|item| { 26 item.map(|(addr, allow)| AllowanceInfo { 27 spender: addr.into(), 28 allowance: allow.allowance, 29 expires: allow.expires, 30 }) 31 }) 32 .collect::<StdResult<_>>()?; 33 Ok(AllAllowancesResponse { allowances }) 34 } 35 36 pub fn query_all_accounts( 37 deps: Deps, 38 start_after: Option<String>, 39 limit: Option<u32>, 40 ) -> StdResult<AllAccountsResponse> { 41 let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; 42 let start = start_after.map(|s| Bound::ExclusiveRaw(s.into())); 43 44 let accounts = BALANCES 45 .keys(deps.storage, start, None, Order::Ascending) 46 .take(limit) 47 .map(|item| item.map(Into::into)) 48 .collect::<StdResult<_>>()?; 49 50 Ok(AllAccountsResponse { accounts }) 51 } 52 53 #[cfg(test)] 54 mod tests { 55 use super::*; 56 57 use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env, mock_info}; 58 use cosmwasm_std::{coins, DepsMut, Uint128}; 59 use cw20::{Cw20Coin, Expiration, TokenInfoResponse}; 60 61 use crate::contract::{execute, instantiate, query_token_info}; 62 use crate::msg::{ExecuteMsg, InstantiateMsg}; 63 64 // this will set up the instantiation for other tests 65 fn do_instantiate(mut deps: DepsMut, addr: &str, amount: Uint128) -> TokenInfoResponse { 66 let instantiate_msg = InstantiateMsg { 67 name: "Auto Gen".to_string(), 68 symbol: "AUTO".to_string(), 69 decimals: 3, 70 initial_balances: vec![Cw20Coin { 71 address: addr.into(), 72 amount, 73 }], 74 mint: None, 75 marketing: None, 76 }; 77 let info = mock_info("creator", &[]); 78 let env = mock_env(); 79 instantiate(deps.branch(), env, info, instantiate_msg).unwrap(); 80 query_token_info(deps.as_ref()).unwrap() 81 } 82 83 #[test] 84 fn query_all_allowances_works() { 85 let mut deps = mock_dependencies_with_balance(&coins(2, "token")); 86 87 let owner = String::from("owner"); 88 // these are in alphabetical order same than insert order 89 let spender1 = String::from("earlier"); 90 let spender2 = String::from("later"); 91 92 let info = mock_info(owner.as_ref(), &[]); 93 let env = mock_env(); 94 do_instantiate(deps.as_mut(), &owner, Uint128::new(12340000)); 95 96 // no allowance to start 97 let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, None).unwrap(); 98 assert_eq!(allowances.allowances, vec![]); 99 100 // set allowance with height expiration 101 let allow1 = Uint128::new(7777); 102 let expires = Expiration::AtHeight(5432); 103 let msg = ExecuteMsg::IncreaseAllowance { 104 spender: spender1.clone(), 105 amount: allow1, 106 expires: Some(expires), 107 }; 108 execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); 109 110 // set allowance with no expiration 111 let allow2 = Uint128::new(54321); 112 let msg = ExecuteMsg::IncreaseAllowance { 113 spender: spender2.clone(), 114 amount: allow2, 115 expires: None, 116 }; 117 execute(deps.as_mut(), env, info, msg).unwrap(); 118 119 // query list gets 2 120 let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, None).unwrap(); 121 assert_eq!(allowances.allowances.len(), 2); 122 123 // first one is spender1 (order of CanonicalAddr uncorrelated with String) 124 let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, Some(1)).unwrap(); 125 assert_eq!(allowances.allowances.len(), 1); 126 let allow = &allowances.allowances[0]; 127 assert_eq!(&allow.spender, &spender1); 128 assert_eq!(&allow.expires, &expires); 129 assert_eq!(&allow.allowance, &allow1); 130 131 // next one is spender2 132 let allowances = query_all_allowances( 133 deps.as_ref(), 134 owner, 135 Some(allow.spender.clone()), 136 Some(10000), 137 ) 138 .unwrap(); 139 assert_eq!(allowances.allowances.len(), 1); 140 let allow = &allowances.allowances[0]; 141 assert_eq!(&allow.spender, &spender2); 142 assert_eq!(&allow.expires, &Expiration::Never {}); 143 assert_eq!(&allow.allowance, &allow2); 144 } 145 146 #[test] 147 fn query_all_accounts_works() { 148 let mut deps = mock_dependencies_with_balance(&coins(2, "token")); 149 150 // insert order and lexicographical order are different 151 let acct1 = String::from("acct01"); 152 let acct2 = String::from("zebra"); 153 let acct3 = String::from("nice"); 154 let acct4 = String::from("aaaardvark"); 155 let expected_order = [acct4.clone(), acct1.clone(), acct3.clone(), acct2.clone()]; 156 157 do_instantiate(deps.as_mut(), &acct1, Uint128::new(12340000)); 158 159 // put money everywhere (to create balanaces) 160 let info = mock_info(acct1.as_ref(), &[]); 161 let env = mock_env(); 162 execute( 163 deps.as_mut(), 164 env.clone(), 165 info.clone(), 166 ExecuteMsg::Transfer { 167 recipient: acct2, 168 amount: Uint128::new(222222), 169 }, 170 ) 171 .unwrap(); 172 execute( 173 deps.as_mut(), 174 env.clone(), 175 info.clone(), 176 ExecuteMsg::Transfer { 177 recipient: acct3, 178 amount: Uint128::new(333333), 179 }, 180 ) 181 .unwrap(); 182 execute( 183 deps.as_mut(), 184 env, 185 info, 186 ExecuteMsg::Transfer { 187 recipient: acct4, 188 amount: Uint128::new(444444), 189 }, 190 ) 191 .unwrap(); 192 193 // make sure we get the proper results 194 let accounts = query_all_accounts(deps.as_ref(), None, None).unwrap(); 195 assert_eq!(accounts.accounts, expected_order); 196 197 // let's do pagination 198 let accounts = query_all_accounts(deps.as_ref(), None, Some(2)).unwrap(); 199 assert_eq!(accounts.accounts, expected_order[0..2].to_vec()); 200 201 let accounts = 202 query_all_accounts(deps.as_ref(), Some(accounts.accounts[1].clone()), Some(1)).unwrap(); 203 assert_eq!(accounts.accounts, expected_order[2..3].to_vec()); 204 205 let accounts = 206 query_all_accounts(deps.as_ref(), Some(accounts.accounts[0].clone()), Some(777)) 207 .unwrap(); 208 assert_eq!(accounts.accounts, expected_order[3..].to_vec()); 209 } 210 }