Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: backport basket proto updates #772

Merged
merged 17 commits into from
Feb 15, 2022
Merged
52 changes: 52 additions & 0 deletions proto/regen/ecocredit/basket/v1/events.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
syntax = "proto3";

package regen.ecocredit.basket.v1;

import "regen/ecocredit/basket/v1/types.proto";

option go_package = "github.com/regen-network/regen-ledger/x/ecocredit/basket";

// EventCreate is an event emitted when a basket is created.
message EventCreate {

// basket_denom is the basket bank denom.
string basket_denom = 1;

// curator is the address of the basket curator who is able to change certain
// basket settings.
string curator = 2;
}

// EventPut is an event emitted when credits are put into a basket in return
// for basket tokens.
message EventPut {

// owner is the owner of the credits put into the basket.
string owner = 1;

// basket_denom is the basket bank denom that the credits were added to.
string basket_denom = 2;

// credits are the credits that were added to the basket.
repeated BasketCredit credits = 3;

// amount is the integer number of basket tokens converted from credits.
string amount = 4;
}

// EventTake is an event emitted when credits are taken from a basket starting
// from the oldest credits first.
message EventTake {

// owner is the owner of the credits taken from the basket.
string owner = 1;

// basket_denom is the basket bank denom that credits were taken from.
string basket_denom = 2;

// credits are the credits that were taken from the basket.
repeated BasketCredit credits = 3;

// amount is the integer number of basket tokens converted to credits.
string amount = 4;
}
97 changes: 97 additions & 0 deletions proto/regen/ecocredit/basket/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
syntax = "proto3";

package regen.ecocredit.basket.v1;

import "google/api/annotations.proto";
import "regen/ecocredit/basket/v1/state.proto";
import "cosmos/base/query/v1beta1/pagination.proto";

option go_package = "github.com/regen-network/regen-ledger/x/ecocredit/basket";

// Msg is the regen.ecocredit.basket.v1beta1 Query service.
service Query {

// Basket queries one basket by denom.
rpc Basket(QueryBasketRequest) returns (QueryBasketResponse) {
option (google.api.http).get =
"/regen/ecocredit/basket/v1/baskets/{basket_denom}";
}

// Baskets lists all baskets in the ecocredit module.
rpc Baskets(QueryBasketsRequest) returns (QueryBasketsResponse) {
option (google.api.http).get =
"/regen/ecocredit/basket/v1/baskets";
}

// BasketBalances lists the balance of each credit batch in the basket.
rpc BasketBalances(QueryBasketBalancesRequest) returns (QueryBasketBalancesResponse) {
option (google.api.http).get =
"/regen/ecocredit/basket/v1/baskets/{basket_denom}/balances";
}

// BasketBalance queries the balance of a specific credit batch in the basket.
rpc BasketBalance(QueryBasketBalanceRequest) returns (QueryBasketBalanceResponse) {
option (google.api.http).get =
"/regen/ecocredit/basket/v1/baskets/{basket_denom}/balances/{batch_denom}";
}
}

// QueryBasketRequest is the Query/Basket request type.
message QueryBasketRequest {
// basket_denom represents the denom of the basket to query.
string basket_denom = 1;
}

// QueryBasketResponse is the Query/Basket response type.
message QueryBasketResponse {
// basket is the queried basket.
Basket basket = 1;
}

// QueryBasketsRequest is the Query/Baskets request type.
message QueryBasketsRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryBasketsResponse is the Query/Baskets response type.
message QueryBasketsResponse {
// baskets are the fetched baskets.
repeated Basket baskets = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryBasketBalancesRequest is the Query/BasketBalances request type.
message QueryBasketBalancesRequest {
// basket_denom is the denom of the basket.
string basket_denom = 1;

// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

// QueryBasketBalancesResponse is the Query/BasketBalances response type.
message QueryBasketBalancesResponse {
// balances is a list of credit balances in the basket.
repeated BasketBalance balances = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryBasketBalanceRequest is the Query/BasketBalance request type.
message QueryBasketBalanceRequest {
// basket_denom is the denom of the basket.
string basket_denom = 1;

// batch_denom is the denom of the credit batch.
string batch_denom = 2;
}

// QueryBasketBalanceResponse is the Query/BasketBalance response type.
message QueryBasketBalanceResponse {
// balance is the amount of the queried credit batch in the basket.
string balance = 1;
}
42 changes: 28 additions & 14 deletions proto/regen/ecocredit/basket/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,45 +28,59 @@ message MsgCreate {
// basket settings.
string curator = 1;

// name will be used to create a bank denom for this basket token.
// name will be used to together with prefix to create a bank denom for this
// basket token. It can be between 3-8 alphanumeric characters, with the
// first character being alphabetic. The bank denom will be
// `eco/<prefix><name>` and its display name will be `eco/<name>`.
string name = 2;

// display_name will be used to create a bank Metadata display name for this
// basket token.
string display_name = 3;
// prefix is a single alphabetic character that denotes
// the denom prefix and indicates in some way what relationship is between
// the denom and display denom. Standard conventions are that m indicates
// milli (10^3), u indicates micro (10^6), n indicates nano (10^9).
// Typical usage of prefix should correspond with the `exponent` field,
// which is used to convert decimal ecocredit amounts to integral
// basket tokens.
string prefix = 3;

// description is a human-readable description of the basket denom that should
// be at most 256 characters.
string description = 4;


// exponent is the exponent that will be used for converting credits to basket
// tokens and for bank denom metadata. It also limits the precision of
// credit amounts when putting credits into a basket. An exponent of 6 will
// mean that 10^6 units of a basket token will be issued for 1.0 credits and
// that this should be displayed as one unit in user interfaces. It also means
// mean that 10^6 units of a basket token will be issued for 1.0 credits and that
// this should be displayed as one unit in user interfaces. It also means
// that the maximum precision of credit amounts is 6 decimal places so that
// the need to round is eliminated. The exponent must be >= the precision of
// the credit type at the time the basket is created.
uint32 exponent = 4;
uint32 exponent = 5;

// disable_auto_retire allows auto-retirement to be disabled.
// The credits will be auto-retired if disable_auto_retire is
// false unless the credits were previously put into the basket by the
// address picking them from the basket, in which case they will remain
// tradable.
bool disable_auto_retire = 5;
bool disable_auto_retire = 6;

// credit_type_name filters against credits from this credit type name.
string credit_type_name = 6;
// credit_type_abbrev is the abbreviation of the credit type this basket is
// able to hold.
string credit_type_abbrev = 7;

// allowed_classes are the credit classes allowed to be put in the basket
repeated string allowed_classes = 7;
repeated string allowed_classes = 8;

// date_criteria is the date criteria for batches admitted to the basket.
DateCriteria date_criteria = 8;
DateCriteria date_criteria = 9;

// fee is 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 the paid a big fee and didn't know
// beforehand.
repeated cosmos.base.v1beta1.Coin fee = 9 [
repeated cosmos.base.v1beta1.Coin fee = 10 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
Expand Down Expand Up @@ -108,7 +122,7 @@ message MsgTake {
// owner is the owner of the basket tokens.
string owner = 1;

// basket_denom is the basket denom to take credits from.
// basket_denom is the basket bank denom to take credits from.
string basket_denom = 2;

// amount is the integer number of basket tokens to convert into credits.
Expand Down
5 changes: 2 additions & 3 deletions proto/regen/ecocredit/basket/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ message DateCriteria {
// start_date_window is a duration of time measured into the past which sets
// a cutoff for batch start dates when adding new credits to the basket.
// Based on the current block timestamp, credits whose start date is before
// `block_timestamp - batch_date_window` will not be allowed into the
// basket.
// `block_timestamp - batch_date_window` will not be allowed into the basket.
google.protobuf.Duration start_date_window = 2;
}
}
}
30 changes: 14 additions & 16 deletions x/ecocredit/basket/msg_create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package basket

import (
"fmt"
"regexp"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
Expand All @@ -12,35 +15,30 @@ var (
_ legacytx.LegacyMsg = &MsgCreate{}
)

const nameMaxLen = 32
const displayNameMinLen = 3
const displayNameMaxLen = 32
const nameMinLen = 3
const nameMaxLen = 8
const exponentMax = 32
const creditNameMaxLen = 32
const creditAbbrMaxLen = 32
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

var errBadReq = sdkerrors.ErrInvalidRequest
var reName = regexp.MustCompile(fmt.Sprintf("^[[:alnum:]]{%d,%d}$", nameMinLen, nameMaxLen))
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

// ValidateBasic does a stateless sanity check on the provided data.
func (m MsgCreate) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Curator); err != nil {
return sdkerrors.ErrInvalidAddress.Wrap("malformed curator address " + err.Error())
}
// TODO: add proper validation once we will have proper requirements.
// https://github.com/regen-network/regen-ledger/issues/732
if m.Name == "" || len(m.Name) > nameMaxLen {
return errBadReq.Wrapf("name must not be empty and must not be longer than %d characters long", nameMaxLen)
}
if len(m.DisplayName) < displayNameMinLen || len(m.DisplayName) > displayNameMaxLen {
return errBadReq.Wrapf("display_name must be between %d and %d characters long", displayNameMinLen, displayNameMaxLen)
if !reName.MatchString(m.Name) {
return errBadReq.Wrapf("name must be between %d and %d alpha-numeric characters long", nameMinLen, nameMaxLen)
}
if m.Exponent > exponentMax {
return errBadReq.Wrapf("exponent must not be bigger than %d", exponentMax)
}
if m.CreditTypeName == "" {
if m.CreditTypeAbbrev == "" {
return errBadReq.Wrap("credit_type_name must be defined")
}
if len(m.CreditTypeName) > creditNameMaxLen {
return errBadReq.Wrapf("credit_type_name must not be longer than %d", creditNameMaxLen)
if len(m.CreditTypeAbbrev) > creditAbbrMaxLen {
return errBadReq.Wrapf("credit_type_name must not be longer than %d", creditAbbrMaxLen)
}
if err := validateDateCriteria(m.DateCriteria); err != nil {
return err
Expand All @@ -56,9 +54,9 @@ func (m MsgCreate) ValidateBasic() error {
return m.Fee.Validate()
}

// ValidateCreateFee additional validation with access to the state data.
// ValidateMsgCreate additional validation with access to the state data.
// minFee must be sorted.
func ValidateCreateFee(m *MsgCreate, minFee sdk.Coins) error {
func ValidateMsgCreate(m *MsgCreate, minFee sdk.Coins) error {
if !m.Fee.IsAllGTE(minFee) {
return sdkerrors.ErrInsufficientFee.Wrapf("minimum fee %s, got %s", minFee, m.Fee)
}
Expand Down
44 changes: 22 additions & 22 deletions x/ecocredit/basket/msg_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ func errorMatches(t *testing.T, err error, expect string) {
func TestMsgCreateValidateBasic(t *testing.T) {
_, _, addr1 := testdata.KeyTestPubAddr()
a := addr1.String()
name := randstr.String(nameMaxLen)
dName := randstr.String((displayNameMaxLen + displayNameMinLen) / 2)
creditName := randstr.String(10)
name := randstr.String((nameMaxLen + nameMinLen) / 2)
creditAbbr := randstr.String(10)
start := &DateCriteria{&DateCriteria_MinStartDate{gogotypes.TimestampNow()}}

classes := []string{"eco_class1"}
Expand All @@ -39,44 +38,45 @@ func TestMsgCreateValidateBasic(t *testing.T) {
MsgCreate{Curator: "wrong"},
"malformed curator address"},
{"name-1",
MsgCreate{Curator: a, Name: ""}, "name must not be empty"},
{"name-2",
MsgCreate{Curator: a, Name: ""},
"name must be between"},
{"name-long",
MsgCreate{Curator: a, Name: randstr.String(nameMaxLen + 1)},
"name must not be empty and must not be longer than"},
{"name-3",
MsgCreate{Curator: a, Name: name, DisplayName: ""},
"display_name must be between"},
{"name-4",
MsgCreate{Curator: a, Name: name, DisplayName: randstr.String(displayNameMaxLen + 1)},
"display_name must be between"},
"name must be between"},
{"name-short",
MsgCreate{Curator: a, Name: randstr.String(nameMinLen - 1)},
"name must be between"},
{"name-no-alpahnum",
MsgCreate{Curator: a, Name: randstr.String(nameMinLen) + "*"},
"name must be between"},
{"exponent-1",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax + 1},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax + 1},
"exponent must not be bigger than"},
{"credity_type-1",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax},
"credit_type_name must be defined"},
{"credity_type-2",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax, CreditTypeName: randstr.String(creditNameMaxLen + 1)},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax, CreditTypeAbbrev: randstr.String(creditAbbrMaxLen + 1)},
"credit_type_name must not be longer"},
{"date_criteria-1",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax, CreditTypeName: creditName, DateCriteria: &DateCriteria{}},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax, CreditTypeAbbrev: creditAbbr, DateCriteria: &DateCriteria{}},
"unsupported date_criteria value"},
{"allowed_classes-1",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax, CreditTypeName: creditName, DateCriteria: start},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax, CreditTypeAbbrev: creditAbbr, DateCriteria: start},
"allowed_classes is required"},
{"allowed_classes-2",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax, CreditTypeName: creditName, DateCriteria: start, AllowedClasses: []string{"class1", ""}},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax, CreditTypeAbbrev: creditAbbr, DateCriteria: start, AllowedClasses: []string{"class1", ""}},
"allowed_classes[1] must be defined"},
{"fee-1",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax, CreditTypeName: creditName, DateCriteria: start, AllowedClasses: classes, Fee: sdk.Coins{sdk.Coin{Denom: "1a"}}},
MsgCreate{Curator: a, Name: name, Exponent: exponentMax, CreditTypeAbbrev: creditAbbr, DateCriteria: start, AllowedClasses: classes, Fee: sdk.Coins{sdk.Coin{Denom: "1a"}}},
"invalid denom"},
{"fee-2", MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: exponentMax, CreditTypeName: creditName, DateCriteria: start, AllowedClasses: classes, Fee: sdk.Coins{sdk.Coin{"aa", sdk.NewInt(-1)}}},
{"fee-2", MsgCreate{Curator: a, Name: name, Exponent: exponentMax, 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, DisplayName: dName, Exponent: 0, CreditTypeName: creditName, DateCriteria: start, AllowedClasses: classes}, ""},
MsgCreate{Curator: a, Name: name, Exponent: 0, CreditTypeAbbrev: creditAbbr, DateCriteria: start, AllowedClasses: classes}, ""},
{"good-date-criteria-not-required",
MsgCreate{Curator: a, Name: name, DisplayName: dName, Exponent: 6, CreditTypeName: creditName, DateCriteria: nil, AllowedClasses: classes, Fee: sdk.Coins{sdk.NewInt64Coin("regen", 1)}}, ""},
MsgCreate{Curator: a, Name: name, Exponent: 6, CreditTypeAbbrev: creditAbbr, DateCriteria: nil, AllowedClasses: classes, Fee: sdk.Coins{sdk.NewInt64Coin("regen", 1)}}, ""},
}

for _, tc := range tcs {
Expand Down
Loading