Skip to content

Commit

Permalink
feat: backport basket proto updates (#772)
Browse files Browse the repository at this point in the history
* backporting proto

* gen proto update

* wip

* update msg_create

* add basket.name checks

* add description check

* chore: update msgs,tests

* fix: cli and test

* fix: put tests/impl

* use ValidateCreditTypeAbbreviation

* add ExponentToPrefix

* compute prefix from exponent

* update denom format

* update prefix

* update tests

* extract denom creation to separate function

* Update x/ecocredit/basket/msg_create.go

Co-authored-by: Aaron Craelius <aaron@regen.network>

Co-authored-by: technicallyty <48813565+tytech3@users.noreply.github.com>
Co-authored-by: Aaron Craelius <aaron@regen.network>
  • Loading branch information
3 people authored Feb 15, 2022
1 parent df802ea commit 1cb3728
Show file tree
Hide file tree
Showing 20 changed files with 600 additions and 294 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ require (
github.com/prometheus/procfs v0.6.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/regen-network/cosmos-proto v0.3.1 // indirect
github.com/regen-network/regen-ledger/api v0.3.0 // indirect
github.com/regen-network/regen-ledger/api v0.4.0 // indirect
github.com/regen-network/regen-ledger/orm v1.0.0-beta1 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -916,8 +916,8 @@ github.com/regen-network/cosmos-sdk v0.44.2-regen-1/go.mod h1:fwQJdw+aECatpTvQTo
github.com/regen-network/protobuf v1.3.2-alpha.regen.4 h1:c9jEnU+xm6vqyrQe3M94UFWqiXxRIKKnqBOh2EACmBE=
github.com/regen-network/protobuf v1.3.2-alpha.regen.4/go.mod h1:/J8/bR1T/NXyIdQDLUaq15LjNE83nRzkyrLAMcPewig=
github.com/regen-network/regen-ledger/api v0.2.0/go.mod h1:kWly2pK0u3fDfyoYYilpEoTEg61pCjV/f5XSY0KzJQY=
github.com/regen-network/regen-ledger/api v0.3.0 h1:gam9DzeklPi9OySQoS2RIwzQhUBwd5UDK8joe0YqHA4=
github.com/regen-network/regen-ledger/api v0.3.0/go.mod h1:kWly2pK0u3fDfyoYYilpEoTEg61pCjV/f5XSY0KzJQY=
github.com/regen-network/regen-ledger/api v0.4.0 h1:klcMljLCHU3MpkRyjrEXL6KKsDGeqFBt2aFUwFdpEH8=
github.com/regen-network/regen-ledger/api v0.4.0/go.mod h1:kWly2pK0u3fDfyoYYilpEoTEg61pCjV/f5XSY0KzJQY=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
Expand Down
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;
}
}
}
60 changes: 39 additions & 21 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,39 +15,37 @@ var (
_ legacytx.LegacyMsg = &MsgCreate{}
)

const nameMaxLen = 32
const displayNameMinLen = 3
const displayNameMaxLen = 32
const exponentMax = 32
const creditNameMaxLen = 32
const nameMinLen = 3
const nameMaxLen = 8
const descrMaxLen = 255
const creditTypeAbbrMaxLen = 3

var errBadReq = sdkerrors.ErrInvalidRequest

// first character must be alphabetic, the rest can be alphanumeric. We reduce length constraints by one to account for
// the first character being forced to alphabetic.
var reName = regexp.MustCompile(fmt.Sprintf("^[[:alpha:]][[:alnum:]]{%d,%d}$", nameMinLen-1, nameMaxLen-1))

// 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 start with an alphabetic character, and be between %d and %d alphanumeric characters long", nameMinLen, nameMaxLen)
}
if m.Exponent > exponentMax {
return errBadReq.Wrapf("exponent must not be bigger than %d", exponentMax)
}
if m.CreditTypeName == "" {
return errBadReq.Wrap("credit_type_name must be defined")
if _, err := ecocredit.ExponentToPrefix(m.Exponent); err != nil {
return err
}
if len(m.CreditTypeName) > creditNameMaxLen {
return errBadReq.Wrapf("credit_type_name must not be longer than %d", creditNameMaxLen)
if err := ecocredit.ValidateCreditTypeAbbreviation(m.CreditTypeAbbrev); err != nil {
return err
}
if err := validateDateCriteria(m.DateCriteria); err != nil {
return err
}
if len(m.Description) > descrMaxLen {
return errBadReq.Wrapf("description can't be longer than %d characters", descrMaxLen)
}
if len(m.AllowedClasses) == 0 {
return errBadReq.Wrap("allowed_classes is required")
}
Expand All @@ -56,9 +57,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 Expand Up @@ -100,3 +101,20 @@ func validateDateCriteria(d *DateCriteria) error {
}
return nil
}

// MsgCreateDenom formats denom and display denom:
// * denom: eco.<m.Exponent><m.CreditTypeAbbrev>.<m.Name>
// * display denom: eco.<m.Exponent><m.CreditTypeAbbrev>.<m.Name>
// Returns error if MsgCrete.Exponent is not supported
func MsgCreateDenom(m *MsgCreate) (string, string, error) {
const basketDenomPrefix = "eco."
denomPrefix, err := ecocredit.ExponentToPrefix(m.Exponent)
if err != nil {
return "", "", err
}

denomTail := m.CreditTypeAbbrev + "." + m.Name
displayDenomName := basketDenomPrefix + denomTail //
denom := basketDenomPrefix + denomPrefix + denomTail // eco.<credit-class>.<name>
return denom, displayDenomName, nil
}
Loading

0 comments on commit 1cb3728

Please sign in to comment.