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  }