feat: add community cdp withdraw collateral proposal (#1567)

* Initial proposal types

* Add withdraw cdp proposal handler

* Add codec registration for proposal type

* Update CommunityCDPWithdrawCollateralProposal name

* Rename CommunityCDPWithdrawCollateralProposal

* Add changelog entry

* Add proposal registration, unit tests

* Register CommunityCDPWithdrawCollateralProposal proposal type codec
This commit is contained in:
drklee3 2023-04-20 16:08:53 -07:00 committed by GitHub
parent 14a0860ddb
commit 31eae1c6d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 648 additions and 28 deletions

View File

@ -45,10 +45,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (x/incentive) [#1512] Add grpc query service.
- (deps) [#1544] Bump confio/ics23/go to v0.9.0, cosmos/keyring to v1.2.0.
- (x/committee) [#1562] Add CommunityPoolLendWithdrawPermission
- (x/community) [#1563] Include x/community module pool balance in x/distribution
community_pool query response.
- (x/community) [#1563] Include x/community module pool balance in
x/distribution community_pool query response.
- (x/community) [#1565] Add CommunityCDPRepayDebtProposal
- (x/committee) [#1566] Add CommunityCDPRepayDebtPermission
- (x/community) [#1567] Add CommunityCDPWithdrawCollateralProposal
### Deprecated
@ -234,6 +235,7 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
large-scale simulations remotely using aws-batch
[#1567]: https://github.com/Kava-Labs/kava/pull/1567
[#1566]: https://github.com/Kava-Labs/kava/pull/1566
[#1565]: https://github.com/Kava-Labs/kava/pull/1565
[#1563]: https://github.com/Kava-Labs/kava/pull/1563

View File

@ -182,6 +182,7 @@
- [kava/community/v1beta1/proposal.proto](#kava/community/v1beta1/proposal.proto)
- [CommunityCDPRepayDebtProposal](#kava.community.v1beta1.CommunityCDPRepayDebtProposal)
- [CommunityCDPWithdrawCollateralProposal](#kava.community.v1beta1.CommunityCDPWithdrawCollateralProposal)
- [CommunityPoolLendDepositProposal](#kava.community.v1beta1.CommunityPoolLendDepositProposal)
- [CommunityPoolLendWithdrawProposal](#kava.community.v1beta1.CommunityPoolLendWithdrawProposal)
@ -2888,6 +2889,25 @@ This proposal exists primarily to allow committees to repay community module cdp
<a name="kava.community.v1beta1.CommunityCDPWithdrawCollateralProposal"></a>
### CommunityCDPWithdrawCollateralProposal
CommunityCDPWithdrawCollateralProposal withdraws cdp collateral owned by the community module
This proposal exists primarily to allow committees to withdraw community module cdp collateral.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `title` | [string](#string) | | |
| `description` | [string](#string) | | |
| `collateral_type` | [string](#string) | | |
| `collateral` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
<a name="kava.community.v1beta1.CommunityPoolLendDepositProposal"></a>
### CommunityPoolLendDepositProposal

View File

@ -43,3 +43,15 @@ message CommunityCDPRepayDebtProposal {
string collateral_type = 3;
cosmos.base.v1beta1.Coin payment = 4 [(gogoproto.nullable) = false];
}
// CommunityCDPWithdrawCollateralProposal withdraws cdp collateral owned by the community module
// This proposal exists primarily to allow committees to withdraw community module cdp collateral.
message CommunityCDPWithdrawCollateralProposal {
option (gogoproto.goproto_stringer) = false;
option (gogoproto.goproto_getters) = false;
string title = 1;
string description = 2;
string collateral_type = 3;
cosmos.base.v1beta1.Coin collateral = 4 [(gogoproto.nullable) = false];
}

View File

@ -49,6 +49,7 @@ func init() {
RegisterProposalTypeCodec(upgradetypes.SoftwareUpgradeProposal{}, "cosmos-sdk/SoftwareUpgradeProposal")
RegisterProposalTypeCodec(upgradetypes.CancelSoftwareUpgradeProposal{}, "cosmos-sdk/CancelSoftwareUpgradeProposal")
RegisterProposalTypeCodec(communitytypes.CommunityCDPRepayDebtProposal{}, "kava/CommunityCDPRepayDebtProposal")
RegisterProposalTypeCodec(communitytypes.CommunityCDPWithdrawCollateralProposal{}, "kava/CommunityCDPWithdrawCollateralProposal")
RegisterProposalTypeCodec(communitytypes.CommunityPoolLendWithdrawProposal{}, "kava/CommunityPoolLendWithdrawProposal")
RegisterProposalTypeCodec(kavadisttypes.CommunityPoolMultiSpendProposal{}, "kava/CommunityPoolMultiSpendProposal")
}
@ -126,6 +127,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
&upgradetypes.SoftwareUpgradeProposal{},
&upgradetypes.CancelSoftwareUpgradeProposal{},
&communitytypes.CommunityCDPRepayDebtProposal{},
&communitytypes.CommunityCDPWithdrawCollateralProposal{},
&communitytypes.CommunityPoolLendWithdrawProposal{},
)

View File

@ -16,6 +16,8 @@ func NewCommunityPoolProposalHandler(k keeper.Keeper) govv1beta1.Handler {
switch c := content.(type) {
case *types.CommunityCDPRepayDebtProposal:
return keeper.HandleCommunityCDPRepayDebtProposal(ctx, k, c)
case *types.CommunityCDPWithdrawCollateralProposal:
return keeper.HandleCommunityCDPWithdrawCollateralProposal(ctx, k, c)
case *types.CommunityPoolLendDepositProposal:
return keeper.HandleCommunityPoolLendDepositProposal(ctx, k, c)
case *types.CommunityPoolLendWithdrawProposal:

View File

@ -42,3 +42,14 @@ func HandleCommunityCDPRepayDebtProposal(ctx sdk.Context, k Keeper, p *types.Com
// make debt repayment
return k.cdpKeeper.RepayPrincipal(ctx, k.moduleAddress, p.CollateralType, p.Payment)
}
// HandleCommunityCDPWithdrawCollateralProposal is a handler for executing a
// passed community pool cdp withdraw collateral proposal.
func HandleCommunityCDPWithdrawCollateralProposal(
ctx sdk.Context,
k Keeper,
p *types.CommunityCDPWithdrawCollateralProposal,
) error {
// withdraw collateral
return k.cdpKeeper.WithdrawCollateral(ctx, k.moduleAddress, k.moduleAddress, p.Collateral, p.CollateralType)
}

View File

@ -440,3 +440,108 @@ func (suite *proposalTestSuite) TestCommunityCDPRepayDebtProposal() {
})
}
}
// expectation: funds in the community module used as cdp collateral will be
// withdrawn and stays in the community module.
func (suite *proposalTestSuite) TestCommunityCDPWithdrawCollateralProposal() {
initialModuleFunds := ukava(2e10).Add(otherdenom(1e9)...)
collateralType := "kava-a"
type debt struct {
collateral sdk.Coin
principal sdk.Coin
}
testcases := []struct {
name string
initialDebt *debt
proposal *types.CommunityCDPWithdrawCollateralProposal
expectedErr string
expectedWithdrawn sdk.Coin
}{
{
name: "valid - withdrawing max collateral",
initialDebt: &debt{
c("ukava", 1e10),
c("usdx", 1e9),
},
proposal: types.NewCommunityCDPWithdrawCollateralProposal(
"withdrawing max collateral",
"i might get liquidated",
collateralType,
c("ukava", 8e9-1), // Withdraw all collateral except 2*principal-1 amount
),
expectedErr: "",
expectedWithdrawn: c("ukava", 8e9-1),
},
{
name: "valid - withdrawing partial collateral",
initialDebt: &debt{
c("ukava", 1e10),
c("usdx", 1e9),
},
proposal: types.NewCommunityCDPWithdrawCollateralProposal(
"title goes here",
"description goes here",
collateralType,
c("ukava", 1e9),
),
expectedErr: "",
expectedWithdrawn: c("ukava", 1e9),
},
{
name: "invalid - withdrawing too much collateral",
initialDebt: &debt{
c("ukava", 1e10),
c("usdx", 1e9),
},
proposal: types.NewCommunityCDPWithdrawCollateralProposal(
"title goes here",
"description goes here",
collateralType,
c("ukava", 9e9), // <-- would be under collateralized
),
expectedErr: "proposed collateral ratio is below liquidation ratio",
expectedWithdrawn: c("ukava", 0),
},
}
for _, tc := range testcases {
suite.Run(tc.name, func() {
var err error
suite.SetupTest()
// setup the community module with some initial funds
err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, initialModuleFunds)
suite.NoError(err, "failed to initially fund module account for cdp creation")
// setup initial debt position
err = suite.cdpKeeper.AddCdp(suite.Ctx, suite.MaccAddress, tc.initialDebt.collateral, tc.initialDebt.principal, collateralType)
suite.NoError(err, "unexpected error while creating initial cdp")
balanceBefore := suite.Keeper.GetModuleAccountBalance(suite.Ctx)
// submit proposal
err = keeper.HandleCommunityCDPWithdrawCollateralProposal(suite.Ctx, suite.Keeper, tc.proposal)
if tc.expectedErr == "" {
suite.NoError(err)
} else {
suite.Require().ErrorContains(err, tc.expectedErr)
}
suite.NextBlock()
cdps := suite.cdpKeeper.GetAllCdpsByCollateralType(suite.Ctx, collateralType)
expectedRemainingCollateral := tc.initialDebt.collateral.Sub(tc.expectedWithdrawn)
// expect withdrawn funds to add to community module account
expectedModuleBalance := balanceBefore.Add(tc.expectedWithdrawn)
suite.Len(cdps, 1, "expected debt position to remain open")
suite.Equal(suite.MaccAddress, cdps[0].Owner, "sanity check: unexpected owner")
// check the remaining principle on the cdp
suite.Equal(expectedRemainingCollateral, cdps[0].Collateral)
// verify the balance changed as expected
moduleBalanceAfter := suite.Keeper.GetModuleAccountBalance(suite.Ctx)
suite.True(expectedModuleBalance.IsEqual(moduleBalanceAfter), "module balance changed unexpectedly")
})
}
}

View File

@ -16,6 +16,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&CommunityPoolLendDepositProposal{}, "kava/CommunityPoolLendDepositProposal", nil)
cdc.RegisterConcrete(&CommunityPoolLendWithdrawProposal{}, "kava/CommunityPoolLendWithdrawProposal", nil)
cdc.RegisterConcrete(&CommunityCDPRepayDebtProposal{}, "kava/CommunityCDPRepayDebtProposal", nil)
cdc.RegisterConcrete(&CommunityCDPWithdrawCollateralProposal{}, "kava/CommunityCDPWithdrawCollateralProposal", nil)
}
// RegisterInterfaces registers proto messages under their interfaces for unmarshalling,
@ -28,6 +29,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
&CommunityPoolLendDepositProposal{},
&CommunityPoolLendWithdrawProposal{},
&CommunityCDPRepayDebtProposal{},
&CommunityCDPWithdrawCollateralProposal{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)

View File

@ -22,6 +22,7 @@ type BankKeeper interface {
// CdpKeeper defines the contract needed to be fulfilled for cdp dependencies.
type CdpKeeper interface {
RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateralType string, payment sdk.Coin) error
WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddress, collateral sdk.Coin, collateralType string) error
}
// HardKeeper defines the contract needed to be fulfilled for Kava Lend dependencies.

View File

@ -18,6 +18,8 @@ const (
ProposalTypeCommunityPoolLendWithdraw = "CommunityPoolLendWithdraw"
// ProposalTypeCommunityCDPRepayDebt defines the type for a CommunityCDPRepayDebtProposal
ProposalTypeCommunityCDPRepayDebt = "CommunityCDPRepayDebt"
// ProposalTypeCommunityCDPWithdrawCollateral defines the type for a CommunityCDPWithdrawCollateralProposal
ProposalTypeCommunityCDPWithdrawCollateral = "CommunityCDPWithdrawCollateral"
)
// Assert CommunityPoolLendDepositProposal implements govtypes.Content at compile-time
@ -25,6 +27,7 @@ var (
_ govv1beta1.Content = &CommunityPoolLendDepositProposal{}
_ govv1beta1.Content = &CommunityPoolLendWithdrawProposal{}
_ govv1beta1.Content = &CommunityCDPRepayDebtProposal{}
_ govv1beta1.Content = &CommunityCDPWithdrawCollateralProposal{}
)
func init() {
@ -34,6 +37,8 @@ func init() {
govv1beta1.ModuleCdc.Amino.RegisterConcrete(&CommunityPoolLendWithdrawProposal{}, "kava/CommunityPoolLendWithdrawProposal", nil)
govv1beta1.RegisterProposalType(ProposalTypeCommunityCDPRepayDebt)
govv1beta1.ModuleCdc.Amino.RegisterConcrete(&CommunityCDPRepayDebtProposal{}, "kava/CommunityCDPRepayDebtProposal", nil)
govv1beta1.RegisterProposalType(ProposalTypeCommunityCDPWithdrawCollateral)
govv1beta1.ModuleCdc.Amino.RegisterConcrete(&CommunityCDPWithdrawCollateralProposal{}, "kava/CommunityCDPWithdrawCollateralProposal", nil)
}
//////////////////
@ -192,3 +197,62 @@ func (p *CommunityCDPRepayDebtProposal) ValidateBasic() error {
}
return nil
}
// NewCommunityCDPRepayDebtProposal creates a new community pool cdp debt repay proposal.
func NewCommunityCDPWithdrawCollateralProposal(
title string,
description string,
collateralType string,
collateral sdk.Coin,
) *CommunityCDPWithdrawCollateralProposal {
return &CommunityCDPWithdrawCollateralProposal{
Title: title,
Description: description,
CollateralType: collateralType,
Collateral: collateral,
}
}
// GetTitle returns the title of the proposal.
func (p *CommunityCDPWithdrawCollateralProposal) GetTitle() string { return p.Title }
// GetDescription returns the description of the proposal.
func (p *CommunityCDPWithdrawCollateralProposal) GetDescription() string { return p.Description }
// GetDescription returns the routing key of the proposal.
func (p *CommunityCDPWithdrawCollateralProposal) ProposalRoute() string { return ModuleName }
// ProposalType returns the type of the proposal.
func (p *CommunityCDPWithdrawCollateralProposal) ProposalType() string {
return ProposalTypeCommunityCDPWithdrawCollateral
}
// String implements fmt.Stringer
func (p *CommunityCDPWithdrawCollateralProposal) String() string {
var b strings.Builder
b.WriteString(fmt.Sprintf(`Community CDP Withdraw Collateral Proposal:
Title: %s
Description: %s
Collateral Type: %s
Collateral: %s
`, p.Title, p.Description, p.CollateralType, p.Collateral))
return b.String()
}
// ValidateBasic stateless validation of the proposal.
func (p *CommunityCDPWithdrawCollateralProposal) ValidateBasic() error {
if err := govv1beta1.ValidateAbstract(p); err != nil {
return err
}
// ensure collateral type is set
if strings.TrimSpace(p.CollateralType) == "" {
return errors.New("cdp collateral type cannot be blank")
}
// ensure the proposal has collateral amount
if !p.Collateral.IsValid() || p.Collateral.IsZero() {
return errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", p.Collateral)
}
return nil
}

View File

@ -144,10 +144,54 @@ func (m *CommunityCDPRepayDebtProposal) XXX_DiscardUnknown() {
var xxx_messageInfo_CommunityCDPRepayDebtProposal proto.InternalMessageInfo
// CommunityCDPWithdrawCollateralProposal withdraws cdp collateral owned by the community module
// This proposal exists primarily to allow committees to withdraw community module cdp collateral.
type CommunityCDPWithdrawCollateralProposal struct {
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
CollateralType string `protobuf:"bytes,3,opt,name=collateral_type,json=collateralType,proto3" json:"collateral_type,omitempty"`
Collateral types.Coin `protobuf:"bytes,4,opt,name=collateral,proto3" json:"collateral"`
}
func (m *CommunityCDPWithdrawCollateralProposal) Reset() {
*m = CommunityCDPWithdrawCollateralProposal{}
}
func (*CommunityCDPWithdrawCollateralProposal) ProtoMessage() {}
func (*CommunityCDPWithdrawCollateralProposal) Descriptor() ([]byte, []int) {
return fileDescriptor_64aa83b2ed448ec1, []int{3}
}
func (m *CommunityCDPWithdrawCollateralProposal) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *CommunityCDPWithdrawCollateralProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_CommunityCDPWithdrawCollateralProposal.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *CommunityCDPWithdrawCollateralProposal) XXX_Merge(src proto.Message) {
xxx_messageInfo_CommunityCDPWithdrawCollateralProposal.Merge(m, src)
}
func (m *CommunityCDPWithdrawCollateralProposal) XXX_Size() int {
return m.Size()
}
func (m *CommunityCDPWithdrawCollateralProposal) XXX_DiscardUnknown() {
xxx_messageInfo_CommunityCDPWithdrawCollateralProposal.DiscardUnknown(m)
}
var xxx_messageInfo_CommunityCDPWithdrawCollateralProposal proto.InternalMessageInfo
func init() {
proto.RegisterType((*CommunityPoolLendDepositProposal)(nil), "kava.community.v1beta1.CommunityPoolLendDepositProposal")
proto.RegisterType((*CommunityPoolLendWithdrawProposal)(nil), "kava.community.v1beta1.CommunityPoolLendWithdrawProposal")
proto.RegisterType((*CommunityCDPRepayDebtProposal)(nil), "kava.community.v1beta1.CommunityCDPRepayDebtProposal")
proto.RegisterType((*CommunityCDPWithdrawCollateralProposal)(nil), "kava.community.v1beta1.CommunityCDPWithdrawCollateralProposal")
}
func init() {
@ -155,32 +199,34 @@ func init() {
}
var fileDescriptor_64aa83b2ed448ec1 = []byte{
// 399 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcd, 0x4e, 0x2c, 0x4b,
0xd4, 0x4f, 0xce, 0xcf, 0xcd, 0x2d, 0xcd, 0xcb, 0x2c, 0xa9, 0xd4, 0x2f, 0x33, 0x4c, 0x4a, 0x2d,
0x49, 0x34, 0xd4, 0x2f, 0x28, 0xca, 0x2f, 0xc8, 0x2f, 0x4e, 0xcc, 0xd1, 0x2b, 0x28, 0xca, 0x2f,
0xc9, 0x17, 0x12, 0x03, 0x29, 0xd3, 0x83, 0x2b, 0xd3, 0x83, 0x2a, 0x93, 0x92, 0x4b, 0xce, 0x2f,
0xce, 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0x85, 0xeb, 0x4d, 0xce, 0xcf, 0xcc, 0x83, 0xe8,
0x93, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x33, 0xf5, 0x41, 0x2c, 0x88, 0xa8, 0xd2, 0x49, 0x46,
0x2e, 0x05, 0x67, 0x98, 0x59, 0x01, 0xf9, 0xf9, 0x39, 0x3e, 0xa9, 0x79, 0x29, 0x2e, 0xa9, 0x05,
0xf9, 0xc5, 0x99, 0x25, 0x01, 0x50, 0x8b, 0x85, 0x44, 0xb8, 0x58, 0x4b, 0x32, 0x4b, 0x72, 0x52,
0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x20, 0x1c, 0x21, 0x05, 0x2e, 0xee, 0x94, 0xd4, 0xe2,
0xe4, 0xa2, 0xcc, 0x82, 0x92, 0xcc, 0xfc, 0x3c, 0x09, 0x26, 0xb0, 0x1c, 0xb2, 0x90, 0x50, 0x32,
0x17, 0x5b, 0x62, 0x6e, 0x7e, 0x69, 0x5e, 0x89, 0x04, 0xb3, 0x02, 0xb3, 0x06, 0xb7, 0x91, 0xa4,
0x1e, 0xc4, 0x8d, 0x7a, 0x20, 0x37, 0xc2, 0x1c, 0xae, 0xe7, 0x9c, 0x9f, 0x99, 0xe7, 0x64, 0x70,
0xe2, 0x9e, 0x3c, 0xc3, 0xaa, 0xfb, 0xf2, 0x1a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x20, 0xff,
0xe9, 0x43, 0x3d, 0x04, 0xa1, 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0xc1,
0x1a, 0x8a, 0x83, 0xa0, 0x46, 0x5b, 0x71, 0x74, 0x2c, 0x90, 0x67, 0x98, 0xb1, 0x40, 0x9e, 0x41,
0xe9, 0x14, 0x23, 0x97, 0x22, 0x86, 0x5f, 0xc2, 0x33, 0x4b, 0x32, 0x52, 0x8a, 0x12, 0xcb, 0x87,
0x9a, 0x67, 0x8e, 0x32, 0x72, 0xc9, 0xc2, 0x3d, 0xe3, 0xec, 0x12, 0x10, 0x94, 0x5a, 0x90, 0x58,
0xe9, 0x92, 0x9a, 0x44, 0x79, 0xac, 0xa8, 0x73, 0xf1, 0x27, 0xe7, 0xe7, 0xe4, 0x24, 0x96, 0xa4,
0x16, 0x25, 0xe6, 0xc4, 0x83, 0x5c, 0x21, 0xc1, 0x0c, 0x56, 0xc5, 0x87, 0x10, 0x0e, 0xa9, 0x2c,
0x48, 0x15, 0xb2, 0xe4, 0x62, 0x2f, 0x48, 0xac, 0xcc, 0x4d, 0xcd, 0x2b, 0x91, 0x60, 0x51, 0x60,
0xc4, 0xef, 0x65, 0x16, 0x90, 0x97, 0x83, 0x60, 0xea, 0x11, 0xfe, 0x70, 0x72, 0x3d, 0xf1, 0x48,
0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0,
0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x6d, 0xa4, 0xd0, 0x01, 0xa5, 0x69, 0xdd, 0x9c,
0xc4, 0xa4, 0x62, 0x30, 0x4b, 0xbf, 0x02, 0x29, 0x1b, 0x80, 0x83, 0x29, 0x89, 0x0d, 0x9c, 0x5c,
0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4a, 0xf3, 0xc5, 0x33, 0x25, 0x03, 0x00, 0x00,
// 419 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x93, 0x3f, 0x0b, 0xd3, 0x40,
0x18, 0xc6, 0x73, 0xb6, 0x56, 0xbd, 0x82, 0x42, 0x28, 0x12, 0x0b, 0x26, 0xb1, 0xa0, 0x16, 0xa4,
0x39, 0xab, 0x93, 0x2e, 0x42, 0x53, 0x37, 0x87, 0x12, 0x04, 0xc1, 0x45, 0x2e, 0xc9, 0xd1, 0x1e,
0x4d, 0xf2, 0x1e, 0xb9, 0x6b, 0x35, 0xdf, 0xc0, 0xd1, 0xd1, 0xb1, 0xb3, 0xdf, 0x43, 0xa8, 0x4e,
0x1d, 0x1c, 0x9c, 0x54, 0xda, 0x2f, 0x22, 0xf9, 0xdb, 0x80, 0x20, 0x82, 0x20, 0x38, 0xe5, 0xcd,
0x7b, 0xcf, 0x7b, 0xf7, 0xfc, 0x78, 0x78, 0xf1, 0xed, 0x35, 0xdd, 0x52, 0x12, 0x40, 0x1c, 0x6f,
0x12, 0xae, 0x32, 0xb2, 0x9d, 0xfa, 0x4c, 0xd1, 0x29, 0x11, 0x29, 0x08, 0x90, 0x34, 0x72, 0x44,
0x0a, 0x0a, 0xf4, 0xeb, 0xb9, 0xcc, 0x69, 0x64, 0x4e, 0x25, 0x1b, 0x9a, 0x01, 0xc8, 0x18, 0x24,
0xf1, 0xa9, 0x64, 0xcd, 0x6c, 0x00, 0x3c, 0x29, 0xe7, 0x86, 0x83, 0x25, 0x2c, 0xa1, 0x28, 0x49,
0x5e, 0x95, 0xdd, 0xd1, 0x27, 0x84, 0x6d, 0xb7, 0xbe, 0x6b, 0x01, 0x10, 0x3d, 0x63, 0x49, 0x38,
0x67, 0x02, 0x24, 0x57, 0x8b, 0xea, 0x61, 0x7d, 0x80, 0x2f, 0x2a, 0xae, 0x22, 0x66, 0x20, 0x1b,
0x8d, 0xaf, 0x78, 0xe5, 0x8f, 0x6e, 0xe3, 0x7e, 0xc8, 0x64, 0x90, 0x72, 0xa1, 0x38, 0x24, 0xc6,
0x85, 0xe2, 0xac, 0xdd, 0xd2, 0x03, 0xdc, 0xa3, 0x31, 0x6c, 0x12, 0x65, 0x74, 0xec, 0xce, 0xb8,
0xff, 0xe0, 0x86, 0x53, 0x7a, 0x74, 0x72, 0x8f, 0xb5, 0x71, 0xc7, 0x05, 0x9e, 0xcc, 0xee, 0xef,
0xbf, 0x59, 0xda, 0x87, 0xef, 0xd6, 0x78, 0xc9, 0xd5, 0x6a, 0xe3, 0xe7, 0x7c, 0xa4, 0x02, 0x2a,
0x3f, 0x13, 0x19, 0xae, 0x89, 0xca, 0x04, 0x93, 0xc5, 0x80, 0xf4, 0xaa, 0xab, 0x1f, 0x5f, 0x7e,
0xbb, 0xb3, 0xb4, 0xf7, 0x3b, 0x4b, 0x1b, 0x7d, 0x46, 0xf8, 0xd6, 0x2f, 0x2c, 0x2f, 0xb8, 0x5a,
0x85, 0x29, 0x7d, 0xfd, 0xbf, 0xc1, 0x7c, 0x44, 0xf8, 0x66, 0x03, 0xe3, 0xce, 0x17, 0x1e, 0x13,
0x34, 0x9b, 0x33, 0xff, 0xef, 0x53, 0xb9, 0x8b, 0xaf, 0x05, 0x10, 0x45, 0x54, 0xb1, 0x94, 0x46,
0xaf, 0x72, 0x17, 0x46, 0xa7, 0x50, 0x5d, 0x3d, 0xb7, 0x9f, 0x67, 0x82, 0xe9, 0x8f, 0xf0, 0x25,
0x41, 0xb3, 0x98, 0x25, 0xca, 0xe8, 0xda, 0xe8, 0xf7, 0xc8, 0xdd, 0x1c, 0xd9, 0xab, 0xf5, 0x2d,
0x8e, 0x2f, 0x08, 0xdf, 0x69, 0x73, 0xd4, 0x79, 0xb8, 0xcd, 0x5b, 0xff, 0x0e, 0xe8, 0x09, 0xc6,
0xe7, 0xce, 0x9f, 0x32, 0xb5, 0x46, 0xce, 0x58, 0xb3, 0xa7, 0xfb, 0xa3, 0x89, 0x0e, 0x47, 0x13,
0xfd, 0x38, 0x9a, 0xe8, 0xdd, 0xc9, 0xd4, 0x0e, 0x27, 0x53, 0xfb, 0x7a, 0x32, 0xb5, 0x97, 0xf7,
0x5a, 0xa1, 0xe7, 0xab, 0x3a, 0x89, 0xa8, 0x2f, 0x8b, 0x8a, 0xbc, 0x69, 0x6d, 0x77, 0x91, 0xbe,
0xdf, 0x2b, 0xb6, 0xf0, 0xe1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0x58, 0xb9, 0x21, 0xfc,
0x03, 0x00, 0x00,
}
func (m *CommunityPoolLendDepositProposal) Marshal() (dAtA []byte, err error) {
@ -339,6 +385,60 @@ func (m *CommunityCDPRepayDebtProposal) MarshalToSizedBuffer(dAtA []byte) (int,
return len(dAtA) - i, nil
}
func (m *CommunityCDPWithdrawCollateralProposal) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CommunityCDPWithdrawCollateralProposal) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *CommunityCDPWithdrawCollateralProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
{
size, err := m.Collateral.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintProposal(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x22
if len(m.CollateralType) > 0 {
i -= len(m.CollateralType)
copy(dAtA[i:], m.CollateralType)
i = encodeVarintProposal(dAtA, i, uint64(len(m.CollateralType)))
i--
dAtA[i] = 0x1a
}
if len(m.Description) > 0 {
i -= len(m.Description)
copy(dAtA[i:], m.Description)
i = encodeVarintProposal(dAtA, i, uint64(len(m.Description)))
i--
dAtA[i] = 0x12
}
if len(m.Title) > 0 {
i -= len(m.Title)
copy(dAtA[i:], m.Title)
i = encodeVarintProposal(dAtA, i, uint64(len(m.Title)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintProposal(dAtA []byte, offset int, v uint64) int {
offset -= sovProposal(v)
base := offset
@ -419,6 +519,29 @@ func (m *CommunityCDPRepayDebtProposal) Size() (n int) {
return n
}
func (m *CommunityCDPWithdrawCollateralProposal) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Title)
if l > 0 {
n += 1 + l + sovProposal(uint64(l))
}
l = len(m.Description)
if l > 0 {
n += 1 + l + sovProposal(uint64(l))
}
l = len(m.CollateralType)
if l > 0 {
n += 1 + l + sovProposal(uint64(l))
}
l = m.Collateral.Size()
n += 1 + l + sovProposal(uint64(l))
return n
}
func sovProposal(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -900,6 +1023,185 @@ func (m *CommunityCDPRepayDebtProposal) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *CommunityCDPWithdrawCollateralProposal) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProposal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: CommunityCDPWithdrawCollateralProposal: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CommunityCDPWithdrawCollateralProposal: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProposal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthProposal
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthProposal
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Title = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProposal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthProposal
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthProposal
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CollateralType", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProposal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthProposal
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthProposal
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CollateralType = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Collateral", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProposal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthProposal
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthProposal
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Collateral.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipProposal(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthProposal
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipProposal(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0

View File

@ -231,3 +231,100 @@ func TestCommunityCDPRepayDebtProposal_Stringer(t *testing.T) {
Payment: 42ukava
`, proposal.String())
}
func TestCommunityCDPWithdrawCollateralProposal_ValidateBasic(t *testing.T) {
type proposalData struct {
Title string
Description string
CollateralType string
Collateral sdk.Coin
}
testCases := []struct {
name string
proposal proposalData
expectedErr string
}{
{
name: "valid proposal",
proposal: proposalData{
Title: "withdraw my collateral plz",
Description: "I interact with cdp",
CollateralType: "type-a",
Collateral: sdk.NewInt64Coin("ukava", 1e6),
},
expectedErr: "",
},
{
name: "invalid - fails gov validation",
proposal: proposalData{
Description: "I have no title.",
},
expectedErr: "invalid proposal content",
},
{
name: "invalid - empty collateral type",
proposal: proposalData{
Title: "Error profoundly",
Description: "I have no collateral type",
},
expectedErr: "collateral type cannot be blank",
},
{
name: "invalid - empty coins",
proposal: proposalData{
Title: "Error profoundly",
Description: "My coins are empty",
CollateralType: "type-a",
Collateral: sdk.Coin{},
},
expectedErr: "invalid coins",
},
{
name: "invalid - zero coins",
proposal: proposalData{
Title: "Error profoundly",
Description: "My coins are zero",
CollateralType: "type-a",
Collateral: sdk.NewInt64Coin("ukava", 0),
},
expectedErr: "invalid coins",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
repayDebt := types.NewCommunityCDPWithdrawCollateralProposal(
tc.proposal.Title,
tc.proposal.Description,
tc.proposal.CollateralType,
tc.proposal.Collateral,
)
err := repayDebt.ValidateBasic()
if tc.expectedErr != "" {
require.ErrorContains(t, err, tc.expectedErr)
return
}
require.NoError(t, err)
require.Equal(t, repayDebt.Title, repayDebt.GetTitle())
require.Equal(t, repayDebt.Description, repayDebt.GetDescription())
require.Equal(t, types.ModuleName, repayDebt.ProposalRoute())
require.Equal(t, types.ProposalTypeCommunityCDPWithdrawCollateral, repayDebt.ProposalType())
})
}
}
func TestCommunityCDPWithdrawCollateralProposal_Stringer(t *testing.T) {
proposal := types.NewCommunityCDPWithdrawCollateralProposal(
"title",
"description",
"collateral-type",
sdk.NewInt64Coin("ukava", 42),
)
require.Equal(t, `Community CDP Withdraw Collateral Proposal:
Title: title
Description: description
Collateral Type: collateral-type
Collateral: 42ukava
`, proposal.String())
}