Skip to content

Commit

Permalink
fix(x/ecocredit): basket date criteria and create basket cmd (#1841)
Browse files Browse the repository at this point in the history
Co-authored-by: Cory <cjlevinson@gmail.com>
  • Loading branch information
ryanchristo and clevinson committed Mar 22, 2023
1 parent a76941f commit fce5ae8
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 9 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- [#1785](https://github.com/regen-network/regen-ledger/pull/1785) Add `amount` and `origin_tx` to `EventBridgeReceive`
- [#1837](https://github.com/regen-network/regen-ledger/pull/1837) Add `batch_denom` to `EventBridge`
- [#1841](https://github.com/regen-network/regen-ledger/pull/1841) Add `--years-in-the-past` to `create-basket` command

#### Fixed

- [#1841](https://github.com/regen-network/regen-ledger/pull/1841) Fix `years_in_the_past` not being set when creating a basket
- [#1841](https://github.com/regen-network/regen-ledger/pull/1841) Fix `--start-date-window` with `create-basket` command

## [v5.0.0](https://github.com/regen-network/regen-ledger/releases/tag/v5.0.0) - 2023-01-05

Expand Down
41 changes: 32 additions & 9 deletions x/ecocredit/basket/client/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
FlagAllowedClasses = "allowed-classes"
FlagMinimumStartDate = "minimum-start-date"
FlagStartDateWindow = "start-date-window"
FlagYearsInThePast = "years-in-the-past"
FlagBasketFee = "basket-fee"
FlagDenomDescription = "description"
FlagRetirementJurisdiction = "retirement-jurisdiction"
Expand All @@ -49,9 +50,12 @@ Flags:
- credit-type-abbrev: filters against credits from this credit type abbreviation (e.g. "BIO").
- allowed-classes: comma separated (no spaces) list of credit classes allowed to be put in
the basket (e.g. "C01,C02").
- min-start-date: the earliest start date for batches of credits allowed into the basket.
- start-date-window: the duration of time (in seconds) measured into the past which sets a
cutoff for batch start dates when adding new credits to the basket.
- min-start-date: the earliest start date for batches of credits allowed into the basket
(e.g. \"2012-01-01\").
- start-date-window: the amount of time (formatted as a duration string) measured into the past which sets a
cutoff for batch start dates when adding new credits to the basket (e.g. "43800h").
- years-in-the-past: the number of years in the past which sets a cutoff for batch start
dates when adding new credits to the basket (e.g. 10).
- basket-fee: the fee that the curator will pay to create the basket. It must be >= the
required Params.basket_creation_fee. We include the fee explicitly here so that the
curator explicitly acknowledges paying this fee and is not surprised to learn that they
Expand Down Expand Up @@ -87,7 +91,13 @@ Flags:
if err != nil {
return err
}
startDateWindow, err := cmd.Flags().GetUint64(FlagStartDateWindow)

startDateWindow, err := cmd.Flags().GetString(FlagStartDateWindow)
if err != nil {
return err
}

yearsInThePast, err := cmd.Flags().GetUint32(FlagYearsInThePast)
if err != nil {
return err
}
Expand All @@ -97,8 +107,13 @@ Flags:
return err
}

if minStartDateString != "" && startDateWindow != 0 {
return fmt.Errorf("both %s and %s cannot be set", FlagStartDateWindow, FlagMinimumStartDate)
if (minStartDateString != "" && startDateWindow != "") ||
(startDateWindow != "" && yearsInThePast != 0) ||
(minStartDateString != "" && yearsInThePast != 0) {
return fmt.Errorf(
"only one date criteria option can be set: %s, %s, or %s",
FlagStartDateWindow, FlagMinimumStartDate, FlagYearsInThePast,
)
}

var dateCriteria *types.DateCriteria
Expand All @@ -115,12 +130,19 @@ Flags:
dateCriteria = &types.DateCriteria{MinStartDate: minStartDate}
}

if startDateWindow != 0 {
startDateWindowDuration := time.Duration(startDateWindow)
if startDateWindow != "" {
startDateWindowDuration, err := time.ParseDuration(startDateWindow)
if err != nil {
return fmt.Errorf("failed to parse start_date_window: %w", err)
}
startDateWindow := prototypes.DurationProto(startDateWindowDuration)
dateCriteria = &types.DateCriteria{StartDateWindow: startDateWindow}
}

if yearsInThePast != 0 {
dateCriteria = &types.DateCriteria{YearsInThePast: yearsInThePast}
}

fee := sdk.Coins{}
feeString, err := cmd.Flags().GetString(FlagBasketFee)
if err != nil {
Expand Down Expand Up @@ -157,7 +179,8 @@ Flags:
cmd.Flags().String(FlagCreditTypeAbbrev, "", "filters against credits from this credit type abbreviation (e.g. \"C\")")
cmd.Flags().StringSlice(FlagAllowedClasses, []string{}, "comma separated (no spaces) list of credit classes allowed to be put in the basket (e.g. \"C01,C02\")")
cmd.Flags().String(FlagMinimumStartDate, "", "the earliest start date for batches of credits allowed into the basket (e.g. \"2012-01-01\")")
cmd.Flags().Uint64(FlagStartDateWindow, 0, "sets a cutoff for batch start dates when adding new credits to the basket (e.g. 1325404800)")
cmd.Flags().String(FlagStartDateWindow, "", "sets a cutoff for batch start dates when adding new credits to the basket (e.g. \"43800h\")")
cmd.Flags().Uint32(FlagYearsInThePast, 0, "the earliest start date for batches of credits allowed into the basket based on number of years in the past (e.g. 10)")
cmd.Flags().String(FlagBasketFee, "", "the fee that the curator will pay to create the basket (e.g. \"20regen\")")
cmd.Flags().String(FlagDenomDescription, "", "the description to be used in the bank denom metadata.")

Expand Down
18 changes: 18 additions & 0 deletions x/ecocredit/basket/keeper/features/msg_create.feature
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Feature: Msg/Create
- when the basket includes a credit type that exists
- when the basket criteria includes credit classes that exist
- when the basket criteria includes credit classes that match the credit type
- when the basket criteria includes optional date criteria
- the user token balance is updated and only the minimum fee is taken
- the basket denom is formatted with a prefix based on credit type precision
- the response includes the basket denom
Expand Down Expand Up @@ -148,6 +149,23 @@ Feature: Msg/Create
When alice attempts to create a basket with credit type "C" and allowed class "BIO01"
Then expect the error "basket specified credit type C, but class BIO01 is of type BIO: invalid request"

Rule: The basket criteria may include optional start date criteria

Background:
Given a credit type

Scenario: basket criteria minimum start date
When alice attempts to create a basket with minimum start date "2020-01-01"
Then expect minimum start date "2020-01-01"

Scenario: basket criteria start date window
When alice attempts to create a basket with start date window "43800h"
Then expect start date window "43800h"

Scenario: basket criteria years in the past
When alice attempts to create a basket with years in the past "10"
Then expect years in the past "10"

Rule: The user token balance is updated and only the minimum fee is taken

Background:
Expand Down
95 changes: 95 additions & 0 deletions x/ecocredit/basket/keeper/msg_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"encoding/json"
"strconv"
"testing"
"time"

"github.com/gogo/protobuf/jsonpb"
gogotypes "github.com/gogo/protobuf/types"
"github.com/regen-network/gocuke"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -210,6 +212,59 @@ func (s *createSuite) AliceAttemptsToCreateABasketWithNameAndCreditType(a string
})
}

func (s *createSuite) AliceAttemptsToCreateABasketWithMinimumStartDate(a string) {
s.createExpectCalls()

ts, err := regentypes.ParseDate(a, a)
require.NoError(s.t, err)

minStartDate, err := gogotypes.TimestampProto(ts)
require.NoError(s.t, err)

s.res, s.err = s.k.Create(s.ctx, &types.MsgCreate{
Curator: s.alice.String(),
Name: s.basketName,
CreditTypeAbbrev: s.creditTypeAbbrev,
DateCriteria: &types.DateCriteria{
MinStartDate: minStartDate,
},
})
}

func (s *createSuite) AliceAttemptsToCreateABasketWithStartDateWindow(a string) {
s.createExpectCalls()

dur, err := time.ParseDuration(a)
require.NoError(s.t, err)

startDateWindow := gogotypes.DurationProto(dur)

s.res, s.err = s.k.Create(s.ctx, &types.MsgCreate{
Curator: s.alice.String(),
Name: s.basketName,
CreditTypeAbbrev: s.creditTypeAbbrev,
DateCriteria: &types.DateCriteria{
StartDateWindow: startDateWindow,
},
})
}

func (s *createSuite) AliceAttemptsToCreateABasketWithYearsInThePast(a string) {
s.createExpectCalls()

yearsInThePast, err := strconv.ParseUint(a, 10, 32)
require.NoError(s.t, err)

s.res, s.err = s.k.Create(s.ctx, &types.MsgCreate{
Curator: s.alice.String(),
Name: s.basketName,
CreditTypeAbbrev: s.creditTypeAbbrev,
DateCriteria: &types.DateCriteria{
YearsInThePast: uint32(yearsInThePast),
},
})
}

func (s *createSuite) ExpectNoError() {
require.NoError(s.t, s.err)
}
Expand All @@ -233,6 +288,46 @@ func (s *createSuite) ExpectTheResponse(a gocuke.DocString) {
require.Equal(s.t, res, s.res)
}

func (s *createSuite) ExpectMinimumStartDate(a string) {
ts, err := regentypes.ParseDate(a, a)
require.NoError(s.t, err)

minStartDate, err := gogotypes.TimestampProto(ts)
require.NoError(s.t, err)

dc, err := s.k.Basket(s.ctx, &types.QueryBasketRequest{
BasketDenom: s.res.BasketDenom,
})
require.NoError(s.t, err)

require.Equal(s.t, minStartDate, dc.BasketInfo.DateCriteria.MinStartDate)
}

func (s *createSuite) ExpectStartDateWindow(a string) {
dur, err := time.ParseDuration(a)
require.NoError(s.t, err)

startDateWindow := gogotypes.DurationProto(dur)

dc, err := s.k.Basket(s.ctx, &types.QueryBasketRequest{
BasketDenom: s.res.BasketDenom,
})
require.NoError(s.t, err)
require.Equal(s.t, startDateWindow, dc.BasketInfo.DateCriteria.StartDateWindow)
}

func (s *createSuite) ExpectYearsInThePast(a string) {
yearsInThePast, err := strconv.ParseUint(a, 10, 32)
require.NoError(s.t, err)

dc, err := s.k.Basket(s.ctx, &types.QueryBasketRequest{
BasketDenom: s.res.BasketDenom,
})
require.NoError(s.t, err)

require.Equal(s.t, uint32(yearsInThePast), dc.BasketInfo.DateCriteria.YearsInThePast)
}

func (s *createSuite) ExpectEventWithProperties(a gocuke.DocString) {
var event types.EventCreate
err := json.Unmarshal([]byte(a.Content), &event)
Expand Down
2 changes: 2 additions & 0 deletions x/ecocredit/basket/types/v1/types_date_criteria.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ func (d *DateCriteria) ToAPI() *api.DateCriteria {
return &api.DateCriteria{MinStartDate: types.GogoToProtobufTimestamp(x)}
} else if x := d.GetStartDateWindow(); x != nil {
return &api.DateCriteria{StartDateWindow: types.GogoToProtobufDuration(x)}
} else if x := d.GetYearsInThePast(); x != 0 {
return &api.DateCriteria{YearsInThePast: x}
}
return nil
}
Expand Down
5 changes: 5 additions & 0 deletions x/ecocredit/basket/types/v1/types_date_criteria_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ func TestDateCriteriaToAPI(t *testing.T) {
dw := dc.ToAPI().GetStartDateWindow()
require.NotNil(dw)
require.Equal(durStd, dw.AsDuration(), "handles window date")

dc = &DateCriteria{YearsInThePast: 10}
yip := dc.ToAPI().GetYearsInThePast()
require.NotNil(yip)
require.Equal(uint32(10), yip, "handles years in the past")
}

func TestValidateDateCriteria(t *testing.T) {
Expand Down

0 comments on commit fce5ae8

Please sign in to comment.