diff --git a/CHANGELOG.md b/CHANGELOG.md index a835fe6b1..02ba4d208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,48 @@ # Changelog -# Changelog - ## [Unreleased](https://github.com/CosmWasm/cw-plus/tree/HEAD) -[Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.11.1...HEAD) +[Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.12.0-alpha1...HEAD) + +**Closed issues:** + +- Incorrect Cw4ExecuteMsg used during remove\_hook [\#637](https://github.com/CosmWasm/cw-plus/issues/637) +- Make `Bound`s type safe [\#462](https://github.com/CosmWasm/cw-plus/issues/462) + +**Merged pull requests:** + +- Fix benchmarks \(after 1.58.1 update\) [\#639](https://github.com/CosmWasm/cw-plus/pull/639) ([maurolacy](https://github.com/maurolacy)) +- Fix `remove_hook` helper [\#638](https://github.com/CosmWasm/cw-plus/pull/638) ([maurolacy](https://github.com/maurolacy)) +- Type safe bounds [\#627](https://github.com/CosmWasm/cw-plus/pull/627) ([maurolacy](https://github.com/maurolacy)) + +## [v0.12.0-alpha1](https://github.com/CosmWasm/cw-plus/tree/v0.12.0-alpha1) (2022-01-27) + +[Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.11.1...v0.12.0-alpha1) + +**Deprecated:** + +- Remove `IntKey` with surrounding implementation [\#570](https://github.com/CosmWasm/cw-plus/issues/570) + +**Closed issues:** + +- Move all cw20 examples to new repo [\#578](https://github.com/CosmWasm/cw-plus/issues/578) +- Add more debug output from multi-test [\#575](https://github.com/CosmWasm/cw-plus/issues/575) + +**Merged pull requests:** + +- Update Rust to v1.54.0 in CI [\#636](https://github.com/CosmWasm/cw-plus/pull/636) ([maurolacy](https://github.com/maurolacy)) +- Refactor cw2 spec readme [\#635](https://github.com/CosmWasm/cw-plus/pull/635) ([orkunkl](https://github.com/orkunkl)) +- Fix tag consolidation for matching CHANGELOG entries [\#634](https://github.com/CosmWasm/cw-plus/pull/634) ([maurolacy](https://github.com/maurolacy)) +- Ics20 contract rollback [\#633](https://github.com/CosmWasm/cw-plus/pull/633) ([ethanfrey](https://github.com/ethanfrey)) +- Fix typo in README.md [\#632](https://github.com/CosmWasm/cw-plus/pull/632) ([josefrichter](https://github.com/josefrichter)) +- Update ics20 contract [\#631](https://github.com/CosmWasm/cw-plus/pull/631) ([ethanfrey](https://github.com/ethanfrey)) +- Publish snapshot map changelog [\#622](https://github.com/CosmWasm/cw-plus/pull/622) ([maurolacy](https://github.com/maurolacy)) +- Remove `IntKey` and `TimestampKey` [\#620](https://github.com/CosmWasm/cw-plus/pull/620) ([ueco-jb](https://github.com/ueco-jb)) +- Signed int key benchmarks [\#619](https://github.com/CosmWasm/cw-plus/pull/619) ([maurolacy](https://github.com/maurolacy)) +- fix readme update coralnet to sandynet-1 [\#617](https://github.com/CosmWasm/cw-plus/pull/617) ([yubrew](https://github.com/yubrew)) +- Publish `PrefixBound` [\#616](https://github.com/CosmWasm/cw-plus/pull/616) ([maurolacy](https://github.com/maurolacy)) +- Move contracts to cw-tokens [\#613](https://github.com/CosmWasm/cw-plus/pull/613) ([ethanfrey](https://github.com/ethanfrey)) +- Add context to multitest execution errors [\#597](https://github.com/CosmWasm/cw-plus/pull/597) ([uint](https://github.com/uint)) ## [v0.11.1](https://github.com/CosmWasm/cw-plus/tree/v0.11.1) (2021-12-28) diff --git a/MIGRATING.md b/MIGRATING.md index ea5b67c8d..8fe761275 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -2,6 +2,58 @@ This guide lists API changes between *cw-plus* major releases. +## v0.11.0 -> v0.12.0 + +### Breaking Issues / PRs + +- Type safe `Bound`s [\#462](https://github.com/CosmWasm/cw-plus/issues/462) + +Bounds are now type-safe. That means the bound type must match the key / sub-key you are ranging over. + +Migration code example: + +```diff +fn list_allowed( + deps: Deps, + start_after: Option, + limit: Option, +) -> StdResult { + let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; +- let start = match start_after { +- Some(x) => Some(Bound::exclusive(deps.api.addr_validate(&x)?.into_string())), +- None => None, +- }; ++ let addr = maybe_addr(deps.api, start_after)?; ++ let start = addr.as_ref().map(Bound::exclusive); + + let allow = ALLOW_LIST + .range(deps.storage, start, None, Order::Ascending) +``` +Here the `ALLOW_LIST` key is of type `&Addr`. That's why we use `as_ref()` before the `map()` that builds the bound. +Notice also that this "forces" you to use `addr_validate()`, in order to build a bound over the proper type. + +You can still use untyped bounds, with the `ExclusiveRaw` and `InclusiveRaw` enum types. +Migration code example, in case you want to keep your raw bounds: + +```diff +pub fn query_all_allowances( + deps: Deps, + env: Env, + start_after: Option, + limit: Option, +) -> StdResult { + let limit = calc_limit(limit); + // we use raw addresses here.... +- let start = start_after.map(Bound::exclusive); ++ let start = start_after.map(|s| Bound::ExclusiveRaw(s.into())); + + let allowances = ALLOWANCES + .range(deps.storage, start, None, Order::Ascending) +``` +Notice that here we build a bound for an address, and using a raw bound allows us to skip address validation / build up. + +See storage-plus [README.md](./packages/storage-plus/README.md#Bound) for more information on `Bound`. + ## v0.10.3 -> v0.11.0 ### Breaking Issues / PRs diff --git a/contracts/cw20-base/src/enumerable.rs b/contracts/cw20-base/src/enumerable.rs index aa5998d86..7f7991c93 100644 --- a/contracts/cw20-base/src/enumerable.rs +++ b/contracts/cw20-base/src/enumerable.rs @@ -16,7 +16,7 @@ pub fn query_all_allowances( ) -> StdResult { 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(|s| Bound::ExclusiveRaw(s.as_bytes().into())); + let start = start_after.map(|s| Bound::ExclusiveRaw(s.into_bytes())); let allowances = ALLOWANCES .prefix(&owner_addr) diff --git a/packages/storage-plus/README.md b/packages/storage-plus/README.md index 214228bd5..edb17d8ed 100644 --- a/packages/storage-plus/README.md +++ b/packages/storage-plus/README.md @@ -314,7 +314,7 @@ fn demo() -> StdResult<()> { In addition to getting one particular item out of a map, we can iterate over the map (or a subset of the map). This let us answer questions like "show me all tokens", -and we provide some nice `Bound`s helpers to easily allow pagination or custom ranges. +and we provide some nice [`Bound`](#Bound) helpers to easily allow pagination or custom ranges. The general format is to get a `Prefix` by calling `map.prefix(k)`, where `k` is exactly one less item than the normal key (If `map.key()` took `(&[u8], &[u8])`, then `map.prefix()` takes `&[u8]`. @@ -322,21 +322,28 @@ If `map.key()` took `&[u8]`, `map.prefix()` takes `()`). Once we have a prefix s over all items with `range(store, min, max, order)`. It supports `Order::Ascending` or `Order::Descending`. `min` is the lower bound and `max` is the higher bound. +If the `min` and `max` bounds are `None`, `range` will return all items under the prefix. You can use `.take(n)` to +limit the results to `n` items and start doing pagination. You can also set the `min` bound to +eg. `Bound::exclusive(last_value)` to start iterating over all items *after* the last value. Combined with +`take`, we easily have pagination support. You can also use `Bound::inclusive(x)` when you want to include any +perfect matches. + +### Bound + +`Bound` is a helper to build type-safe bounds on the keys or sub-keys you want to iterate over. +It also supports a raw (`Vec`) bounds specification, for the cases you don't want or can't use typed bounds. + ```rust -#[derive(Copy, Clone, Debug)] -pub enum Bound { - Inclusive(Vec), - Exclusive(Vec), - None, +#[derive(Clone, Debug)] +pub enum Bound<'a, K: PrimaryKey<'a>> { + Inclusive((K, PhantomData<&'a bool>)), + Exclusive((K, PhantomData<&'a bool>)), + InclusiveRaw(Vec), + ExclusiveRaw(Vec), } ``` -If the `min` and `max` bounds, it will return all items under this prefix. You can use `.take(n)` to -limit the results to `n` items and start doing pagination. You can also set the `min` bound to -eg. `Bound::Exclusive(last_value)` to start iterating over all items *after* the last value. Combined with -`take`, we easily have pagination support. You can also use `Bound::Inclusive(x)` when you want to include any -perfect matches. To better understand the API, please read the following example: - +To better understand the API, please read the following example: ```rust #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct Data { @@ -358,7 +365,7 @@ fn demo() -> StdResult<()> { // iterate over them all let all: StdResult> = PEOPLE - .range(&store, Bound::None, Bound::None, Order::Ascending) + .range(&store, None, None, Order::Ascending) .collect(); assert_eq!( all?, @@ -369,8 +376,8 @@ fn demo() -> StdResult<()> { let all: StdResult> = PEOPLE .range( &store, - Bound::Exclusive("jim"), - Bound::None, + Some(Bound::exclusive("jim")), + None, Order::Ascending, ) .collect(); @@ -384,7 +391,7 @@ fn demo() -> StdResult<()> { // get all under one key let all: StdResult> = ALLOWANCE .prefix("owner") - .range(&store, Bound::None, Bound::None, Order::Ascending) + .range(&store, None, None, Order::Ascending) .collect(); assert_eq!( all?, @@ -396,8 +403,8 @@ fn demo() -> StdResult<()> { .prefix("owner") .range( &store, - Bound::Exclusive("spender1"), - Bound::Inclusive("spender2"), + Some(Bound::exclusive("spender1")), + Some(Bound::inclusive("spender2")), Order::Descending, ) .collect();