Skip to content

Commit

Permalink
Merge branch 'release/v3.0.x' into aleem/basket-sims
Browse files Browse the repository at this point in the history
  • Loading branch information
aleem1314 authored Feb 23, 2022
2 parents a5c9594 + 982679c commit df30c09
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 37 deletions.
10 changes: 5 additions & 5 deletions proto/regen/ecocredit/basket/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ service Msg {
rpc Take(MsgTake) returns (MsgTakeResponse);
}

// MsgCreateBasket is the Msg/CreateBasket request type.
// MsgCreate is the Msg/Create request type.
message MsgCreate {
// curator is the address of the basket curator who is able to change certain
// basket settings.
Expand Down Expand Up @@ -52,7 +52,7 @@ message MsgCreate {
// following values 0, 1, 2, 3, 6, 9, 12, 15, 18, 21, or 24 which correspond
// to the exponents which have an official SI prefix.
//
// The exponent will be used to form the prefix part of the the bank denom
// The exponent will be used to form the prefix part of the bank denom
// and will be mapped as follows:
// 0 - no prefix
// 1 - d (deci)
Expand Down Expand Up @@ -96,7 +96,7 @@ message MsgCreate {
];
}

// MsgCreateBasketResponse is the Msg/CreateBasket response type.
// MsgCreateResponse is the Msg/Create response type.
message MsgCreateResponse {

// basket_denom is the unique denomination ID of the newly created basket.
Expand Down Expand Up @@ -126,7 +126,7 @@ message MsgPutResponse {
string amount_received = 1;
}

// MsgTakeFromBasket is the Msg/TakeFromBasket request type.
// MsgTake is the Msg/Take request type.
message MsgTake {

// owner is the owner of the basket tokens.
Expand All @@ -148,7 +148,7 @@ message MsgTake {
bool retire_on_take = 5;
}

// MsgTakeFromBasketResponse is the Msg/TakeFromBasket response type.
// MsgTakeResponse is the Msg/Take response type.
message MsgTakeResponse {

// credits are the credits taken out of the basket.
Expand Down
2 changes: 1 addition & 1 deletion x/ecocredit/basket/msg_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var (

const nameMinLen = 3
const nameMaxLen = 8
const descrMaxLen = 255
const descrMaxLen = 256
const creditTypeAbbrMaxLen = 3

var errBadReq = sdkerrors.ErrInvalidRequest
Expand Down
7 changes: 3 additions & 4 deletions x/ecocredit/basket/msg_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ func TestMsgCreateValidateBasic(t *testing.T) {
"name must start with an alphabetic character"},
{"exponent-1",
MsgCreate{Curator: a, Name: name, Exponent: 4},
"exponent must be one of"},
{"exponent-1",
"exponent must be one of [0 1 2 3 6 9 12 15 18 21 24]"},
{"exponent-2",
MsgCreate{Curator: a, Name: name, Exponent: 17},
"exponent must be one of"},
"exponent must be one of [0 1 2 3 6 9 12 15 18 21 24]"},
{"credity_type-1",
MsgCreate{Curator: a, Name: name, Exponent: 3},
"credit type abbreviation must be 1-3"},
Expand All @@ -82,7 +82,6 @@ func TestMsgCreateValidateBasic(t *testing.T) {
"invalid denom"},
{"fee-2", MsgCreate{Curator: a, Name: name, Exponent: 3, CreditTypeAbbrev: creditAbbr, DateCriteria: start, AllowedClasses: classes, Fee: sdk.Coins{sdk.Coin{"aa", sdk.NewInt(-1)}}},
"invalid denom"},

{"good-1-fees-not-required",
MsgCreate{Curator: a, Name: name, Exponent: 0, CreditTypeAbbrev: creditAbbr, DateCriteria: start, AllowedClasses: classes, Description: descr}, ""},
{"good-date-criteria-not-required",
Expand Down
9 changes: 6 additions & 3 deletions x/ecocredit/basket/msg_take.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/regen-network/regen-ledger/types/math"
"github.com/regen-network/regen-ledger/x/ecocredit"
)

Expand All @@ -31,8 +30,12 @@ func (m MsgTake) ValidateBasic() error {
if err := sdk.ValidateDenom(m.BasketDenom); err != nil {
return sdkerrors.ErrInvalidRequest.Wrapf("%s is not a valid basket denom", m.BasketDenom)
}
if _, err := math.NewPositiveDecFromString(m.Amount); err != nil {
return sdkerrors.ErrInvalidRequest.Wrap(err.Error())
i, ok := sdk.NewIntFromString(m.Amount)
if !ok {
return sdkerrors.ErrInvalidRequest.Wrapf("%s can't be converted to an integer", m.Amount)
}
if !i.IsPositive() {
return sdkerrors.ErrInvalidRequest.Wrapf("%s must be positive", m.Amount)
}
if m.RetireOnTake {
if err := ecocredit.ValidateLocation(m.RetirementLocation); err != nil {
Expand Down
40 changes: 31 additions & 9 deletions x/ecocredit/basket/msg_take_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
Expand All @@ -36,7 +36,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "",
RetireOnTake: false,
},
Expand All @@ -46,7 +46,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: "",
BasketDenom: "BCT",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
Expand All @@ -57,7 +57,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: "foo",
BasketDenom: "BCT",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
Expand All @@ -68,7 +68,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
Expand All @@ -79,7 +79,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "foo!bar",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
Expand All @@ -96,6 +96,28 @@ func TestMsgTakeValidateBasic(t *testing.T) {
},
wantErr: true,
},
{
name: "invalid amount - empty",
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
wantErr: true,
},
{
name: "invalid amount - not integer",
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "12.34",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
wantErr: true,
},
{
name: "invalid amount - format",
fields: fields{
Expand Down Expand Up @@ -123,7 +145,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "-12.34",
Amount: "-1234",
RetirementLocation: "US-WA",
RetireOnTake: true,
},
Expand All @@ -134,7 +156,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "",
RetireOnTake: true,
},
Expand All @@ -145,7 +167,7 @@ func TestMsgTakeValidateBasic(t *testing.T) {
fields: fields{
Owner: addr.String(),
BasketDenom: "BCT",
Amount: "12.34",
Amount: "1234",
RetirementLocation: "foo-bar",
RetireOnTake: true,
},
Expand Down
6 changes: 3 additions & 3 deletions x/ecocredit/client/basket/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ Example:
return cmd
}

// QueryBasketBalancesCmd returns a query command that retrieves the the balance of each credit batch for the given basket denom.
// QueryBasketBalancesCmd returns a query command that retrieves the balance of each credit batch for the given basket denom.
func QueryBasketBalancesCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "basket-balances [basket-denom]",
Short: "Retrieves the the balance of each credit batch for the given basket denom",
Long: strings.TrimSpace(`Retrieves the the balance of each credit batch for the given basket denom
Short: "Retrieves the balance of each credit batch for the given basket denom",
Long: strings.TrimSpace(`Retrieves the balance of each credit batch for the given basket denom
Examples:
$regen q ecocredit basket-balances BASKET1
Expand Down
25 changes: 16 additions & 9 deletions x/ecocredit/client/basket/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,16 @@ Flags:
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 the
paid a big fee and didn't know beforehand.
description: the description to be used in the basket coin's bank denom metadata.
`),
description: the description to be used in the basket coin's bank denom metadata.`),
Example: `
$regen tx ecocredit create-basket HEAED
--from regen...
--exponent=3
--credit-type-abbreviation=FOO
--allowed_classes="class1,class2"
--basket-fee=100regen
--description="any description"
`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
Expand All @@ -88,11 +96,10 @@ Flags:
return err
}

allowedClassesString, err := cmd.Flags().GetString(FlagAllowedClasses)
allowedClasses, err := cmd.Flags().GetStringSlice(FlagAllowedClasses)
if err != nil {
return err
}
allowedClasses := strings.Split(allowedClassesString, ",")
for i := range allowedClasses {
allowedClasses[i] = strings.TrimSpace(allowedClasses[i])
}
Expand All @@ -115,7 +122,7 @@ Flags:
return fmt.Errorf("both %s and %s cannot be set", FlagStartDateWindow, FlagMinimumStartDate)
}

dateCriteria := basket.DateCriteria{}
var dateCriteria *basket.DateCriteria

if minStartDateString != "" {
minStartDateTime, err := time.Parse("2006-01-02", minStartDateString)
Expand All @@ -126,13 +133,13 @@ Flags:
if err != nil {
return fmt.Errorf("failed to parse min_start_date: %w", err)
}
dateCriteria.MinStartDate = minStartDate
dateCriteria = &basket.DateCriteria{MinStartDate: minStartDate}
}

if startDateWindow != 0 {
startDateWindowDuration := time.Duration(startDateWindow)
startDateWindow := types.DurationProto(startDateWindowDuration)
dateCriteria.StartDateWindow = startDateWindow
dateCriteria = &basket.DateCriteria{StartDateWindow: startDateWindow}
}

fee := sdk.Coins{}
Expand All @@ -155,7 +162,7 @@ Flags:
DisableAutoRetire: disableAutoRetire,
CreditTypeAbbrev: creditTypeName,
AllowedClasses: allowedClasses,
DateCriteria: &dateCriteria,
DateCriteria: dateCriteria,
Fee: fee,
}

Expand All @@ -173,7 +180,7 @@ Flags:
cmd.Flags().String(FlagExponent, "", "the exponent used for converting credits to basket tokens")
cmd.Flags().Bool(FlagDisableAutoRetire, false, "dictates whether credits will be auto-retired upon taking")
cmd.Flags().String(FlagCreditTypeAbbreviation, "", "filters against credits from this credit type name (e.g. \"carbon\")")
cmd.Flags().String(FlagAllowedClasses, "", "comma separated (no spaces) list of credit classes allowed to be put in the basket (e.g. \"C01,C02\")")
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(FlagBasketFee, "", "the fee that the curator will pay to create the basket (e.g. \"20regen\")")
Expand Down
4 changes: 2 additions & 2 deletions x/ecocredit/denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ var exponentPrefixMap = map[uint32]string{
var validExponents string

func init() {
var exponents = make([]uint32, len(exponentPrefixMap))
var exponents = make([]uint32, 0, len(exponentPrefixMap))
for e := range exponentPrefixMap {
exponents = append(exponents, e)
}
sort.Slice(exponents, func(i, j int) bool { return exponents[i] < exponents[j] })
validExponents = fmt.Sprint(validExponents)
validExponents = fmt.Sprint(exponents)
}

// ExponentToPrefix returns a denom prefix for a given exponent.
Expand Down
2 changes: 1 addition & 1 deletion x/ecocredit/server/basket/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func NewKeeper(
}
}

// EcocreditKeeper abstracts over methods that the main eco-credit keeper
// EcocreditKeeper abstracts over methods that the main ecocredit keeper
// needs to expose to the basket keeper.
//
// NOTE: run `make mocks` whenever you add methods here
Expand Down
58 changes: 58 additions & 0 deletions x/ecocredit/server/basket/take_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"
"time"

"github.com/cosmos/cosmos-sdk/orm/types/ormerrors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/golang/mock/gomock"
"google.golang.org/protobuf/types/known/timestamppb"
Expand Down Expand Up @@ -172,6 +173,63 @@ func TestTakeTradable(t *testing.T) {
s.expectRetiredSupply("C4", "0")
}

func TestTakeTooMuchTradable(t *testing.T) {
t.Parallel()
s := setupTake(t)

// Try to take more than what's in the basket, should error.
amount := sdk.NewInt(99999999999)
barCoins := sdk.NewCoins(sdk.NewCoin("bar", amount))
s.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), s.addr, baskettypes.BasketSubModuleName, barCoins)
s.bankKeeper.EXPECT().BurnCoins(gomock.Any(), baskettypes.BasketSubModuleName, barCoins)

_, err := s.k.Take(s.ctx, &baskettypes.MsgTake{
Owner: s.addr.String(),
BasketDenom: "bar",
Amount: amount.String(),
RetireOnTake: false,
})
// IRL, the error below should throw earlier, on SendCoinsFromAccountToModule
// We're just testing here that some error is thrown.
assert.Error(t, err, "unexpected failure - balance invariant broken")
}

func TestTakeAllTradable(t *testing.T) {
t.Parallel()
s := setupTake(t)

barCoins := sdk.NewCoins(sdk.NewCoin("bar", sdk.NewInt(11000000))) // == 7C4 + 4C4
s.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), s.addr, baskettypes.BasketSubModuleName, barCoins)
s.bankKeeper.EXPECT().BurnCoins(gomock.Any(), baskettypes.BasketSubModuleName, barCoins)

res, err := s.k.Take(s.ctx, &baskettypes.MsgTake{
Owner: s.addr.String(),
BasketDenom: "bar",
Amount: "11000000",
RetireOnTake: false,
})
assert.NilError(t, err)
assert.Equal(t, 2, len(res.Credits))
assert.Equal(t, "C3", res.Credits[0].BatchDenom)
assertDecStringEqual(t, "7.0", res.Credits[0].Amount)
assert.Equal(t, "C4", res.Credits[1].BatchDenom)
assertDecStringEqual(t, "4.0", res.Credits[1].Amount)
found, err := s.stateStore.BasketBalanceStore().Has(s.ctx, s.barBasketId, "C3")
assert.NilError(t, err)
assert.Assert(t, !found)
_, err = s.stateStore.BasketBalanceStore().Get(s.ctx, s.barBasketId, "C4")
assert.ErrorIs(t, err, ormerrors.NotFound)

s.expectTradableBalance("C3", "7")
s.expectTradableBalance("C4", "4")
s.expectRetiredBalance("C3", "0")
s.expectRetiredBalance("C4", "0")
s.expectTradableSupply("C3", "7")
s.expectTradableSupply("C4", "4")
s.expectRetiredSupply("C3", "0")
s.expectRetiredSupply("C4", "0")
}

func assertDecStringEqual(t *testing.T, expected, actual string) {
dx, err := math.NewDecFromString(expected)
assert.NilError(t, err)
Expand Down

0 comments on commit df30c09

Please sign in to comment.