-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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(x/protocolpool)!: allow any coins in continuous funds #21916
base: main
Are you sure you want to change the base?
Conversation
📝 Walkthrough📝 WalkthroughWalkthroughThe changes involve significant updates to the Changes
Possibly related PRs
Suggested labels
Suggested reviewers
📜 Recent review detailsConfiguration used: .coderabbit.yml 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
…/allow-all-coins-protopool
x.Amount = *clv.list | ||
default: | ||
if fd.IsExtension() { | ||
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.protocolpool.v1.DistributionAmount")) |
Check warning
Code scanning / CodeQL
Panic in BeginBock or EndBlock consensus methods Warning
if fd.IsExtension() { | ||
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.protocolpool.v1.DistributionAmount")) | ||
} | ||
panic(fmt.Errorf("message cosmos.protocolpool.v1.DistributionAmount does not contain field %s", fd.FullName())) |
Check warning
Code scanning / CodeQL
Panic in BeginBock or EndBlock consensus methods Warning
@facundomedica your pull request is missing a changelog! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
🧹 Outside diff range and nitpick comments (16)
x/protocolpool/keeper/genesis_test.go (3)
35-35
: LGTM! Consider adding a constant for the coin denom.The change to use
DistributionAmount
withsdk.NewCoins
aligns well with the PR objective of allowing any coins in continuous funds. This provides more flexibility in representing different coin types.Consider defining a constant for the "stake" denom at the package level to improve maintainability:
const testDenom = "stake"Then use it in the test:
Amount: types.DistributionAmount{Amount: sdk.NewCoins(sdk.NewCoin(testDenom, math.NewInt(100)))},
43-43
: LGTM! Consider using a variable for consistency.The change to use
DistributionAmount
forLastBalance
is consistent with the previous change and aligns with the PR objectives.For better consistency and to make the relationship between the distributed amount and last balance clearer, consider using a variable:
distributionAmount := math.NewInt(100) lastBalanceAmount := math.NewInt(1) gs.Distributions = append(gs.Distributions, &types.Distribution{ Amount: types.DistributionAmount{Amount: sdk.NewCoins(sdk.NewCoin(testDenom, distributionAmount))}, Time: &time.Time{}, }) gs.LastBalance = types.DistributionAmount{Amount: sdk.NewCoins(sdk.NewCoin(testDenom, lastBalanceAmount))}This makes it easier to adjust the test scenario and clearly shows that the last balance is less than the distribution amount.
52-52
: LGTM! Consider using a variable for the expected amount.The updated assertion correctly checks the specific coin amount in the new
LastBalance
structure.To improve clarity and maintain consistency with the earlier suggestions, consider using a variable for the expected amount:
expectedLastBalance := math.OneInt() suite.Require().Equal(expectedLastBalance, exportedGenState.LastBalance.Amount.AmountOf(testDenom))This makes the expected value more explicit and easier to update if needed.
x/protocolpool/types/genesis.go (1)
Line range hint
1-78
: Overall assessment: Changes look good, but ensure comprehensive testing.The modifications to the
NewGenesisState
function, particularly theLastBalance
field initialization, are consistent with the PR objectives of allowing any coins in continuous funds. The changes adhere to Golang coding standards and the Uber Golang style guide.However, given that this change affects a fundamental structure (
GenesisState
), it's crucial to:
- Thoroughly test the impact of this change on all components that interact with
GenesisState
.- Update any relevant documentation to reflect the new
LastBalance
type and initialization.- Consider adding or updating unit tests to cover the new
LastBalance
behavior.Consider adding a comment above the
NewGenesisState
function explaining the rationale behind initializingLastBalance
with an empty set of coins, as this might not be immediately obvious to other developers.x/protocolpool/proto/cosmos/protocolpool/v1/types.proto (1)
46-54
: LGTM: NewDistributionAmount
message added with appropriate options.The new
DistributionAmount
message is well-structured and aligns with the PR objective of allowing any coins in continuous funds. The use ofrepeated cosmos.base.v1beta1.Coin
with appropriate Gogoproto and Amino options ensures compatibility and consistent behavior.Consider adding a brief comment above the
amount
field to describe its purpose and any constraints (e.g., "Stores multiple coin types for distribution. Must not be empty."). This would enhance the self-documentation of the proto file.message DistributionAmount { + // Stores multiple coin types for distribution. Must not be empty. repeated cosmos.base.v1beta1.Coin amount = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (amino.dont_omitempty) = true, (amino.encoding) = "legacy_coins" ]; }
x/protocolpool/keeper/msg_server.go (1)
160-162
: LGTM with a minor suggestion for clarity.The initialization of
RecipientFundDistribution
with an empty coin set is correct and aligns with the new flexibility to handle multiple coin types. This change supports the PR objective of allowing any coins in continuous funds.For improved clarity and consistency with Go conventions, consider using a composite literal directly:
err = k.RecipientFundDistribution.Set(ctx, recipient, types.DistributionAmount{Amount: sdk.Coins{}})This minor change eliminates the need for the
NewCoins()
function call while achieving the same result.x/protocolpool/keeper/keeper_test.go (2)
143-150
: LGTM: Updated type handling in TestIterateAndUpdateFundsDistributionThe changes correctly reflect the transition from
math.Int
totypes.DistributionAmount
. The test logic has been appropriately updated to check theAmount
field of the new type.Consider adding a test case for a
DistributionAmount
with multiple coins to ensure the new type is fully exercised.
211-220
: LGTM: Updated type handling in TestSetToDistributeThe changes correctly reflect the transition to using
DistributionAmount
. The test logic has been appropriately updated to check theAmount
field of the new type.Consider adding a test case with multiple coins in the
DistributionAmount
to ensure the new type is fully tested.x/protocolpool/keeper/genesis.go (2)
58-58
: Consider renaming fields for clarityIn lines 58 and 60, the code references
distribution.Amount.Amount
, which can be confusing due to the repeated use ofAmount
. To improve readability and maintainability, consider renaming one of theAmount
fields in theDistributionAmount
struct. For example, you could rename the innerAmount
field toCoins
, resulting indistribution.Amount.Coins
.Apply this diff to rename the field:
-type DistributionAmount struct { - Amount sdk.Coins -} +type DistributionAmount struct { + Coins sdk.Coins +}This change will require updating all usages of
distribution.Amount.Amount
todistribution.Amount.Coins
.Also applies to: 60-60
Line range hint
121-127
: Avoid variable shadowing of theerr
variable in the closureIn the anonymous function passed to
k.Distributions.Walk
, the named return parametererr error
shadows theerr
variable in the outer scope. This can lead to confusion and potential errors. According to the Uber Go Style Guide, it's recommended to avoid shadowing variables.Consider removing the named return parameters or renaming them to prevent shadowing.
Apply this diff:
-err = k.Distributions.Walk(ctx, nil, func(key time.Time, value types.DistributionAmount) (stop bool, err error) { +err = k.Distributions.Walk(ctx, nil, func(key time.Time, value types.DistributionAmount) (stop bool, walkErr error) {Since the
err
variable is not used inside the function body, you could also omit the named return parameter:-err = k.Distributions.Walk(ctx, nil, func(key time.Time, value types.DistributionAmount) (stop bool, err error) { +err = k.Distributions.Walk(ctx, nil, func(key time.Time, value types.DistributionAmount) (bool, error) {This avoids shadowing the outer
err
variable and improves code clarity.x/protocolpool/keeper/keeper.go (1)
153-154
: Address the TODO comment regarding allowed denominationsThere is a TODO comment indicating the need to handle cases where the balance does not contain any of the allowed denominations. Please implement this logic to ensure proper functioning and prevent potential issues with unsupported denominations.
Would you like assistance in implementing this check? I can help draft the necessary code or open a GitHub issue to track this task.
x/protocolpool/keeper/msg_server_test.go (2)
486-488
: Redundant Setting of Zero Distribution AmountsIn lines 486-488, both
RecipientFundDistribution
andDistributions
are set tosdk.NewCoins()
, which represents an empty coin set. Since these are default zero values, consider removing these explicit initializations to reduce redundancy.
Line range hint
832-847
: Optimize Redundant Initializations in Test SetupIn lines 832-847,
RecipientFundDistribution
is set tosdk.NewCoins()
for multiple recipients during test setup. Since the distributions default to empty, these explicit initializations might be unnecessary. Removing them could simplify the test setup.api/cosmos/protocolpool/v1/types.pulsar.go (1)
1370-1370
: Avoid leading underscores and underscores in type names; prefer CamelCase.The type
_DistributionAmount_1_list
begins with an underscore and uses underscores in its name, which goes against Go naming conventions. According to the Uber Go Style Guide, underscores should be avoided in names. Consider renaming the type todistributionAmountList
orDistributionAmountList
.Apply this diff to rename the type:
-type _DistributionAmount_1_list struct { +type distributionAmountList struct { // fields... }Ensure all references to this type are updated accordingly.
api/cosmos/protocolpool/v1/tx.pulsar.go (2)
7467-7469
: Fix the indentation of thewithdrawn_allocated_fund
field.The
withdrawn_allocated_fund
field is not properly indented. It should be aligned with the other fields in theMsgCancelContinuousFundResponse
message.Apply this diff to fix the indentation:
- WithdrawnAllocatedFund []*v1beta1.Coin `protobuf:"bytes,4,rep,name=withdrawn_allocated_fund,json=withdrawnAllocatedFund,proto3" json:"withdrawn_allocated_fund,omitempty"` + WithdrawnAllocatedFund []*v1beta1.Coin `protobuf:"bytes,4,rep,name=withdrawn_allocated_fund,json=withdrawnAllocatedFund,proto3" json:"withdrawn_allocated_fund,omitempty"`
7561-7563
: Fix the indentation of theamount
field.The
amount
field is not properly indented. It should be aligned with the other fields in theMsgWithdrawContinuousFundResponse
message.Apply this diff to fix the indentation:
- Amount []*v1beta1.Coin `protobuf:"bytes,1,rep,name=amount,proto3" json:"amount,omitempty"` + Amount []*v1beta1.Coin `protobuf:"bytes,1,rep,name=amount,proto3" json:"amount,omitempty"`
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
🔇 Files ignored due to path filters (3)
x/protocolpool/types/genesis.pb.go
is excluded by!**/*.pb.go
x/protocolpool/types/tx.pb.go
is excluded by!**/*.pb.go
x/protocolpool/types/types.pb.go
is excluded by!**/*.pb.go
📒 Files selected for processing (16)
- api/cosmos/protocolpool/v1/genesis.pulsar.go (32 hunks)
- api/cosmos/protocolpool/v1/tx.pulsar.go (26 hunks)
- api/cosmos/protocolpool/v1/types.pulsar.go (6 hunks)
- x/protocolpool/depinject.go (1 hunks)
- x/protocolpool/keeper/genesis.go (2 hunks)
- x/protocolpool/keeper/genesis_test.go (2 hunks)
- x/protocolpool/keeper/keeper.go (10 hunks)
- x/protocolpool/keeper/keeper_test.go (4 hunks)
- x/protocolpool/keeper/msg_server.go (1 hunks)
- x/protocolpool/keeper/msg_server_test.go (18 hunks)
- x/protocolpool/proto/cosmos/protocolpool/v1/genesis.proto (2 hunks)
- x/protocolpool/proto/cosmos/protocolpool/v1/tx.proto (2 hunks)
- x/protocolpool/proto/cosmos/protocolpool/v1/types.proto (2 hunks)
- x/protocolpool/testutil/expected_keepers_mocks.go (0 hunks)
- x/protocolpool/types/expected_keepers.go (0 hunks)
- x/protocolpool/types/genesis.go (1 hunks)
💤 Files not reviewed due to no reviewable changes (2)
- x/protocolpool/testutil/expected_keepers_mocks.go
- x/protocolpool/types/expected_keepers.go
🧰 Additional context used
📓 Path-based instructions (11)
api/cosmos/protocolpool/v1/genesis.pulsar.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.api/cosmos/protocolpool/v1/tx.pulsar.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.api/cosmos/protocolpool/v1/types.pulsar.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.x/protocolpool/depinject.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.x/protocolpool/keeper/genesis.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.x/protocolpool/keeper/genesis_test.go (2)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"x/protocolpool/keeper/keeper.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.x/protocolpool/keeper/keeper_test.go (2)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"x/protocolpool/keeper/msg_server.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.x/protocolpool/keeper/msg_server_test.go (2)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"x/protocolpool/types/genesis.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
📓 Learnings (1)
x/protocolpool/keeper/genesis.go (1)
Learnt from: likhita-809 PR: cosmos/cosmos-sdk#18471 File: x/protocolpool/keeper/genesis.go:12-51 Timestamp: 2023-11-22T12:32:39.368Z Learning: - The user `likhita-809` has confirmed the changes suggested in the previous interaction. - The file in question is `x/protocolpool/keeper/genesis.go` from a Cosmos SDK module. - The changes involve optimizing the `InitGenesis` function by removing redundant code and ensuring proper handling of start times for budget proposals.
🔇 Additional comments not posted (64)
x/protocolpool/keeper/genesis_test.go (1)
Line range hint
1-52
: Overall, the changes effectively test the new multi-coin functionality.The updates to
TestInitGenesis
align well with the PR objective of allowing any coins in continuous funds. The test now usesDistributionAmount
withsdk.NewCoins
for bothDistributions
andLastBalance
, which provides more flexibility in representing different coin types.The test scenario effectively checks the case where the total to be distributed is greater than the last balance, and the assertion has been updated to check the specific coin amount in the new structure.
These changes ensure that the genesis functionality is properly tested with the new multi-coin support.
x/protocolpool/types/genesis.go (2)
9-10
: LGTM: Import changes are appropriate and well-structured.The addition of the SDK types import is consistent with the changes in the
NewGenesisState
function. The import statement follows the Uber Golang style guide recommendations for import grouping and aliasing.
17-17
: LGTM:LastBalance
initialization updated correctly, but verify impact.The change from
math.ZeroInt()
toDistributionAmount{Amount: sdk.NewCoins()}
forLastBalance
initialization is correct and aligns with the PR objectives of allowing any coins in continuous funds. This modification reflects the transition from a simple integer to a more flexible coin-based structure.To ensure this change doesn't introduce any issues, please run the following verification:
This will help identify any other parts of the codebase that might need to be updated to accommodate this change.
x/protocolpool/proto/cosmos/protocolpool/v1/types.proto (2)
11-11
: LGTM: Import statement for Amino codec added.The addition of the Amino import is appropriate for maintaining backwards compatibility in the Cosmos SDK ecosystem. This import will allow the use of Amino-specific annotations in the protocol definitions.
Line range hint
14-54
: Verify integration ofDistributionAmount
with existing messages.While the new
DistributionAmount
message allows for multiple coin types, the existingBudget
andContinuousFund
messages still use single-coin fields (e.g.,claimed_amount
,budget_per_tranche
). This might lead to inconsistencies in how funds are handled across different parts of the protocol.Please review and confirm:
- Whether
Budget
andContinuousFund
messages should be updated to useDistributionAmount
for consistency.- How
DistributionAmount
will be integrated with existing functionality.To assist in this verification, you can run the following script to check for potential inconsistencies:
This script will help identify areas where the new
DistributionAmount
might need to be integrated or where existing single-coin usage might need to be reviewed.x/protocolpool/depinject.go (1)
61-61
: LGTM. Verify impact on dependent modules.The removal of
StakingKeeper
from theNewKeeper
function call aligns with the changes in theModuleInputs
struct. This modification appears intentional and consistent with the module's new design.However, this is a breaking change that may affect other parts of the system relying on the old
Keeper
structure.To ensure this change doesn't introduce unintended side effects, please run the following script to check for any remaining references to
StakingKeeper
in theprotocolpool
module:Additionally, verify that all dependent modules have been updated to accommodate this change in the
Keeper
structure.✅ Verification successful
Change Verified: No remaining references to
StakingKeeper
inx/protocolpool
.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for remaining references to StakingKeeper in the protocolpool module # Test: Search for StakingKeeper references in the protocolpool module rg --type go 'StakingKeeper' x/protocolpoolLength of output: 43
Script:
#!/bin/bash # Description: Search the entire codebase for references to StakingKeeper rg --type go 'StakingKeeper'Length of output: 43919
x/protocolpool/proto/cosmos/protocolpool/v1/tx.proto (3)
158-160
: Approved: Enhanced flexibility for withdrawn fundsThe change from a single coin to a repeated field of coins for
withdrawn_allocated_fund
aligns well with the PR objective. This modification allows for multiple types of coins to be withdrawn when canceling a continuous fund, increasing the flexibility of the protocol.Note that this is a breaking change, as mentioned in the PR title, and will require updates to any code interacting with this message.
172-174
: Approved: Multi-coin support for withdrawalsThe modification of the
amount
field to a repeated field of coins inMsgWithdrawContinuousFundResponse
is consistent with the PR's goal. This change enables the withdrawal of multiple types of coins from a continuous fund, enhancing the protocol's flexibility.As with the previous change, this is a breaking change that will require updates to dependent code.
Line range hint
1-176
: Verify related code updatesThe changes in this file successfully implement multi-coin support for continuous funds in both cancellation and withdrawal operations. These modifications align well with the PR objectives and are correctly implemented in the Protocol Buffers definitions.
However, as these are breaking changes, it's crucial to ensure that:
- The corresponding Go code generated from these Proto definitions is updated accordingly.
- All parts of the codebase that interact with
MsgCancelContinuousFundResponse
andMsgWithdrawContinuousFundResponse
are updated to handle multiple coins.- Tests are updated or added to cover these new multi-coin scenarios.
- Documentation is updated to reflect these changes.
To verify the impact of these changes, you can run the following script:
This script will help identify areas of the codebase that might need to be updated in light of these changes.
x/protocolpool/keeper/keeper_test.go (3)
38-42
: LGTM: Removal of stakingKeeper fieldThe removal of the
stakingKeeper
field from theKeeperTestSuite
struct is consistent with the changes described in the AI summary. This modification streamlines the test suite by removing unnecessary dependencies.
Line range hint
231-235
: LGTM: Consistent type update in TestSetToDistributeThe change to use
types.DistributionAmount
in theWalk
function is consistent with the previous modifications. The test logic remains valid and continues to provide good coverage.
Line range hint
1-238
: Overall assessment: Changes are well-implemented and sufficiently testedThe modifications in this file consistently reflect the transition from using
math.Int
totypes.DistributionAmount
for handling distribution amounts. The test coverage has been appropriately updated to accommodate these changes, and the overall structure of the tests remains sound.Key points:
- Removal of
stakingKeeper
dependency aligns with the PR objectives.- Test logic has been correctly updated to work with the new
DistributionAmount
type.- Existing test coverage appears sufficient for the changes made.
Suggestions for improvement:
- Consider adding test cases that exercise
DistributionAmount
with multiple coins to ensure comprehensive coverage of the new type's capabilities.The changes adhere to Golang style guidelines and maintain the overall quality of the test suite.
x/protocolpool/keeper/keeper.go (16)
24-25
: LGTM!The definitions of
authKeeper
andbankKeeper
in theKeeper
struct are appropriate and follow standard conventions.
36-38
: LGTM!The addition of
RecipientFundDistribution
,Distributions
, andLastBalance
fields to theKeeper
struct is correctly implemented, and their types are appropriately defined using thecollections
package.
70-72
: LGTM!The initialization of the new collections maps and items in the
NewKeeper
function aligns with the existing code patterns and is correctly implemented.
165-168
: LGTM!The calculation of
amountToDistribute
usingSafeSub
and the handling of potential negative results are correctly implemented.
183-188
: LGTM!The logic for transferring funds to the community pool when there are no continuous funds, and resetting
LastBalance
, is correctly implemented.
194-194
: LGTM!Recording the distribution amount with the current block time is appropriate and correctly implemented.
199-199
: LGTM!Updating
LastBalance
with the current balance ensures accurate tracking for future distributions.
221-223
: LGTM!Initialization of variables
toDistribute
,poolFunds
, andfullAmountToDistribute
is properly set up for subsequent calculations.
225-225
: LGTM!Iterating over
k.Distributions
to calculate allocations is correctly implemented.
266-266
: LGTM!Resetting
LastBalance
after clearing distributions ensures consistent state for future calculations.
271-271
: LGTM!Transferring
streamAmt
to the stream account is correctly handled.
279-279
: LGTM!Transferring
poolFunds
to the community pool is appropriately implemented.
301-301
: LGTM!Initializing
toClaim
with zero coins for new recipients is correct.
307-308
: LGTM!Updating the recipient's claimable amount in
RecipientFundDistribution
is correctly implemented.
115-135
: Verify callers handle new return type ofwithdrawRecipientFunds
The
withdrawRecipientFunds
function now returnssdk.Coins
instead ofsdk.Coin
. Ensure that all callers of this function have been updated to handle the new return type to avoid potential runtime errors.Run the following script to find all usages of
withdrawRecipientFunds
and check for proper handling:#!/bin/bash # Description: Find all calls to `withdrawRecipientFunds` and verify they handle `sdk.Coins`. # Test: Search for function calls to `withdrawRecipientFunds`. Expect: Callers expect `sdk.Coins`. rg --type go 'withdrawRecipientFunds\(' -A 5
45-45
: Verify thatstakingKeeper
is no longer used in the codebaseThe
stakingKeeper
parameter has been removed from theNewKeeper
function signature. Ensure that all references tostakingKeeper
have been removed throughout the codebase to prevent any undefined references or build errors.Run the following script to confirm that
stakingKeeper
is not referenced elsewhere:x/protocolpool/keeper/msg_server_test.go (5)
398-398
: Correct Update towithdrawnAmount
TypeThe variable
withdrawnAmount
has been appropriately updated fromsdk.Coin
tosdk.Coins
to handle multiple coin types, aligning with the new data structures introduced in the codebase.
Line range hint
426-442
: Consistent Initialization ofRecipientFundDistribution
The initialization of
RecipientFundDistribution
withsdk.NewCoins()
ensures that the distribution amounts are correctly represented as empty coin sets for multiple coin types. This change maintains consistency across the codebase.
628-631
: Ensure Accurate Assertions After Multiple WithdrawalsAt lines 628-631, assertions are made on
toClaim.Amount
forrecipient2
andrecipient3
. Verify that these assertions correctly reflect the expected state after withdrawals, and ensure that funds are accurately distributed among all recipients.
991-1007
: Correct Handling of Expired Continuous FundsIn the
TestWithdrawExpiredFunds
function (lines 991-1007), the logic correctly prevents withdrawal of expired funds and handles cancellations without errors. The test accurately verifies that repeated cancellations do not result in errors or unintended fund distribution.
508-508
: Confirm Necessity of Empty Expiry in Test CaseIn line 508, the test case sets an empty expiry for the continuous fund. Verify whether an empty expiry is acceptable in the business logic and that it does not introduce unintended behavior.
Run the following script to search for uses of continuous funds without expiry:
api/cosmos/protocolpool/v1/genesis.pulsar.go (25)
265-266
: Handling ofLastBalance
inRange
method is appropriateThe check for
x.LastBalance != nil
and subsequent processing ensures that theLastBalance
field is correctly included during iteration. This follows standard practice and is compliant with the Uber Go Style Guide.
297-297
: Correct implementation ofHas
method forLastBalance
The
Has
method accurately checks the presence ofLastBalance
by verifying if it is not nil. This is the appropriate way to handle optional fields in Go.
321-321
: Proper clearing ofLastBalance
inClear
methodSetting
x.LastBalance = nil
correctly clears the field, ensuring that subsequent calls recognize it as unset. This adheres to best practices for managing optional fields.
354-354
: Accurate retrieval ofLastBalance
inGet
methodThe
Get
method correctly retrieves theLastBalance
field by returning its proto message representation. This implementation is standard and effective.
390-390
: Type assertion inSet
method is safe and appropriateAssigning
x.LastBalance
after asserting the value's type to*DistributionAmount
is appropriate here, assuming correct usage of the API. There is no immediate risk of a type assertion panic in this context.
427-431
: Correct initialization ofLastBalance
inMutable
methodThe method ensures that
LastBalance
is initialized when nil, which prevents potential nil pointer dereferences when accessing it later. Returning the proto message reflects standard practice.
458-459
: Proper creation of newDistributionAmount
inNewField
The creation of a new
DistributionAmount
instance and returning its proto message is correct and follows the expected pattern for this method.
544-545
: Efficient size calculation ofLastBalance
inProtoMethods
The
Size
function accurately includes the size ofLastBalance
when it is not nil. This contributes to correct serialization behavior.
599-609
: Correct marshaling ofLastBalance
The code properly marshals
LastBalance
when it is not nil, handling errors appropriately. The implementation aligns with the standard serialization process.
Line range hint
766-796
: Accurate unmarshaling ofLastBalance
During unmarshaling, the code correctly initializes
LastBalance
if it's nil and unmarshals data into it. Error handling is properly managed, ensuring robustness.
870-870
: Initialization offd_Distribution_amount
is correctThe field descriptor for
amount
in theDistribution
message is properly declared and initialized, which is essential for reflection operations.Also applies to: 877-877
951-956
: Appropriate handling ofAmount
inRange
method ofDistribution
The method correctly checks if
x.Amount
is not nil and processes it accordingly during iteration. This conforms to best practices.
974-975
: Correct implementation ofHas
method forAmount
The
Has
method properly determines the presence of theAmount
field by checking for nil, which is appropriate for optional fields.
994-995
: Proper clearing ofAmount
inClear
methodSetting
x.Amount = nil
effectively clears theAmount
field, ensuring it's unset in subsequent operations.
1040-1041
: Safe type assertion inSet
method forAmount
The assignment to
x.Amount
with type assertion to*DistributionAmount
is appropriate and assumes correct usage of proto reflection.
1068-1071
: Proper initialization ofAmount
inMutable
methodEnsuring
x.Amount
is initialized when nil prevents nil pointer exceptions and is a correct approach in theMutable
method.
1088-1090
: Correct instantiation inNewField
methodCreating a new
DistributionAmount
instance and returning its proto message aligns with standard implementation for creating new fields.
1164-1167
: Accurate size calculation ofAmount
Including the size of
x.Amount
in the total size when not nil is essential for accurate serialization.
1197-1198
: Proper marshaling ofAmount
The code marshals
x.Amount
correctly when it is present, handling potential errors suitably.
1211-1223
: Correct marshaling ofTime
inDistribution
Marshaling of
x.Time
is handled appropriately, ensuring that the timestamp is correctly serialized.
Line range hint
1274-1342
: Robust unmarshaling logic inDistribution
The unmarshaling code properly handles both
Time
andAmount
fields, initializing them when necessary and managing errors effectively.
1406-1406
: Definition ofLastBalance
field is appropriateChanging
LastBalance
to be of type*DistributionAmount
allows for richer data representation and aligns with the intended functionality.
1447-1451
: Correct implementation ofGetLastBalance
methodThe getter method accurately returns
x.LastBalance
and handles the case wherex
is nil, ensuring reliability.
1466-1467
: Proper definition ofTime
andAmount
fields inDistribution
Defining
Time
andAmount
as pointers allows for optional fields and aligns with protobuf conventions.
1490-1499
: Correct getter methods forDistribution
fieldsThe
GetTime
andGetAmount
methods correctly return their respective fields, handling nil cases appropriately.api/cosmos/protocolpool/v1/tx.pulsar.go (6)
5511-5515
: Verify the cardinality ofwithdrawn_allocated_fund
.The
withdrawn_allocated_fund
field is defined as a repeated field. Ensure that it is semantically correct for this field to contain multiple coins. If it should only hold a single coin amount, consider changing it to a non-repeated field.
Line range hint
7511-7515
: Verify the cardinality ofwithdrawn_allocated_fund
.Similar to the previous comment, ensure that the
withdrawn_allocated_fund
field should indeed be a repeated field semantically. If it should only hold a single coin amount, change it to a non-repeated field.
Line range hint
7584-7588
: Verify the cardinality ofamount
.The
amount
field is defined as a repeated field. Ensure that it is semantically correct for this field to contain multiple coins. If it should only hold a single coin amount, consider changing it to a non-repeated field.
7728-7730
: Fix the indentation of thewithdrawn_allocated_fund
field.The
withdrawn_allocated_fund
field is not properly indented. It should be aligned with the other fields in theMsgCancelContinuousFundResponse
message.Apply this diff to fix the indentation:
- WithdrawnAllocatedFund []*v1beta1.Coin `protobuf:"bytes,4,rep,name=withdrawn_allocated_fund,json=withdrawnAllocatedFund,proto3" json:"withdrawn_allocated_fund,omitempty"` + WithdrawnAllocatedFund []*v1beta1.Coin `protobuf:"bytes,4,rep,name=withdrawn_allocated_fund,json=withdrawnAllocatedFund,proto3" json:"withdrawn_allocated_fund,omitempty"`
7746-7748
: Fix the indentation of theamount
field.The
amount
field is not properly indented. It should be aligned with the other fields in theMsgWithdrawContinuousFundResponse
message.Apply this diff to fix the indentation:
- Amount []*v1beta1.Coin `protobuf:"bytes,1,rep,name=amount,proto3" json:"amount,omitempty"` + Amount []*v1beta1.Coin `protobuf:"bytes,1,rep,name=amount,proto3" json:"amount,omitempty"`
6465-6514
: 🛠️ Refactor suggestionRefactor the internal list type into a reusable utility.
Similar to the previous comment, consider extracting the
_MsgWithdrawContinuousFundResponse_1_list
type and its methods into a reusable utility type to improve code modularity and reduce duplication.
(gogoproto.customtype) = "cosmossdk.io/math.Int", | ||
(gogoproto.nullable) = false | ||
]; | ||
DistributionAmount last_balance = 3 [(gogoproto.nullable) = false]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing field type of last_balance
may cause backward compatibility issues
Modifying the type of the last_balance
field from string
to DistributionAmount
in the GenesisState
message can lead to serialization and deserialization issues with existing clients and persisted data that expect a string
. This can cause failures when parsing genesis files or communicating with nodes that haven't updated.
To preserve backward compatibility, consider deprecating the existing field and introducing a new field with a new field number and the desired type.
(gogoproto.customtype) = "cosmossdk.io/math.Int", | ||
(gogoproto.nullable) = false | ||
]; | ||
google.protobuf.Timestamp time = 1 [(gogoproto.stdtime) = true]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Altering field numbers in Protobuf messages breaks compatibility
Changing the field number of time
from 6
to 1
in the Distribution
message can result in data corruption or parsing errors. Field numbers in Protobuf are used to identify fields in the binary format, and modifying them disrupts compatibility with existing data and clients that use the previous numbering.
Instead of renumbering existing fields, add new fields with new field numbers, and, if necessary, deprecate the old fields to maintain backward compatibility.
|
||
google.protobuf.Timestamp time = 6 [(gogoproto.stdtime) = true]; | ||
DistributionAmount amount = 2 [(gogoproto.nullable) = false]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing field type of amount
may cause backward compatibility issues
Updating the type of the amount
field from string
to DistributionAmount
in the Distribution
message may lead to deserialization problems with existing data and clients expecting a string
. This could cause runtime errors or data loss when processing distributions.
It's advisable to add a new field with a new field number and the new type DistributionAmount
. You can retain the old amount
field for compatibility purposes and mark it as deprecated.
x/protocolpool/keeper/genesis.go
Outdated
if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) { | ||
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the logical inconsistency in the condition and error message
There's a mismatch between the condition being checked and the error message returned. The condition data.LastBalance.Amount.IsAnyGT(totalToBeDistributed)
checks if the last balance amount is greater than the total to be distributed. However, the error message states "total to be distributed is greater than the last balance," which implies the opposite.
To correct this, the condition should check if totalToBeDistributed.IsAnyGT(data.LastBalance.Amount)
instead.
Apply this diff to fix the condition:
-if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) {
+if totalToBeDistributed.IsAnyGT(data.LastBalance.Amount) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) {
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed))
}
This change ensures that the error is returned when the total to be distributed exceeds the last balance, aligning the condition with the error message.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) { | |
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed)) | |
} | |
if totalToBeDistributed.IsAnyGT(data.LastBalance.Amount) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) { | |
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed)) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused a bit about the 1st condition, should return an error when totalToBeDistributed > lastBalance
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hieuvubk, you're correct. The error should be returned when totalToBeDistributed
is greater than data.LastBalance.Amount
. Currently, the condition:
if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) {
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed))
}
checks if data.LastBalance.Amount
is greater than totalToBeDistributed
, which is the opposite of the intended logic based on the error message.
To fix this inconsistency, the condition should be:
if totalToBeDistributed.IsAnyGT(data.LastBalance.Amount) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) {
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed))
}
This change ensures that an error is returned when totalToBeDistributed
exceeds data.LastBalance.Amount
, aligning the condition with the error message and the expected behavior.
/_/\
( •.• )
🚀<
A curious rabbit pondering over the code!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not simply go with fmt.Errorf
instead which is typically used in these scenarios? For example:
fmt.Errorf("an amount to be distributed is greater than the last balance: %s > %s", totalToBeDistributed, data.LastBalance.Amount))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was actually for testing, but I think it can be useful if we ever encounter this, I'll modify it.
x/protocolpool/keeper/keeper.go
Outdated
for _, denom := range amount.Amount.Denoms() { | ||
am := sdk.NewCoin(denom, f.Percentage.MulInt(amount.Amount.AmountOf(denom)).TruncateInt()) | ||
toDistribute[f.Recipient] = toDistribute[f.Recipient].Add(am) | ||
fullAmountToDistribute = fullAmountToDistribute.Add(am) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review the use of TruncateInt()
in distribution calculations
When calculating each recipient's share, TruncateInt()
is used after multiplying by the percentage. This could lead to loss of fractional amounts. Consider whether this aligns with the expected financial logic, or if using RoundInt()
would be more appropriate to minimize discrepancies.
suite.Require().NoError(err) | ||
suite.mockStreamFunds(math.NewInt(0)) | ||
}, | ||
recipientAddress: []sdk.AccAddress{recipient}, | ||
expErr: false, | ||
withdrawnAmount: sdk.NewCoin(sdk.DefaultBondDenom, math.ZeroInt()), | ||
withdrawnAmount: nil, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Clarify Representation of Zero withdrawnAmount
The withdrawnAmount
is set to nil
on line 494. To maintain consistency and clarity, consider using sdk.NewCoins()
to represent zero amounts instead of nil
.
Apply this diff to standardize the representation:
- withdrawnAmount: nil,
+ withdrawnAmount: sdk.NewCoins(),
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
withdrawnAmount: nil, | |
withdrawnAmount: sdk.NewCoins(), |
case "cosmos.protocolpool.v1.Distribution.amount": | ||
value := x.Amount | ||
return protoreflect.ValueOfMessage(value.ProtoReflect()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible copy-paste error in Get
method for Distribution
struct
In the Get
method, the second case
for "cosmos.protocolpool.v1.Distribution.time"
incorrectly assigns x.Amount
instead of x.Time
. Additionally, there is no case
handling for "cosmos.protocolpool.v1.Distribution.amount"
, which is required for proper functionality.
Apply the following diff to fix the issue:
func (x *fastReflection_Distribution) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value {
switch descriptor.FullName() {
case "cosmos.protocolpool.v1.Distribution.time":
value := x.Time
return protoreflect.ValueOfMessage(value.ProtoReflect())
- case "cosmos.protocolpool.v1.Distribution.time":
+ case "cosmos.protocolpool.v1.Distribution.amount":
value := x.Amount
return protoreflect.ValueOfMessage(value.ProtoReflect())
default:
Committable suggestion was skipped due to low confidence.
type _DistributionAmount_1_list struct { | ||
list *[]*v1beta1.Coin | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using pointers to slices; slices are reference types in Go.
In the struct _DistributionAmount_1_list
, the field list
is declared as *[]*v1beta1.Coin
. Since slices in Go are reference types, using a pointer to a slice is unnecessary and adds complexity. Consider changing the field to use a slice directly.
Apply this diff to simplify the struct definition:
type _DistributionAmount_1_list struct {
- list *[]*v1beta1.Coin
+ list []*v1beta1.Coin
}
Adjust the methods accordingly to reflect this change.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
type _DistributionAmount_1_list struct { | |
list *[]*v1beta1.Coin | |
} | |
type _DistributionAmount_1_list struct { | |
list []*v1beta1.Coin | |
} |
value := &_DistributionAmount_1_list{list: &x.Amount} | ||
return protoreflect.ValueOfList(value) | ||
default: | ||
if fd.IsExtension() { | ||
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.protocolpool.v1.DistributionAmount")) | ||
} | ||
panic(fmt.Errorf("message cosmos.protocolpool.v1.DistributionAmount does not contain field %s", fd.FullName())) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using panic for error handling; return errors instead.
Using panic
in the Mutable
method for handling invalid field descriptors is discouraged. Panics can cause unexpected crashes and are harder to recover from. Instead, modify the method to return an error or handle the situation gracefully without panicking.
Consider refactoring the code as follows:
func (x *fastReflection_DistributionAmount) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.FullName() {
case "cosmos.protocolpool.v1.DistributionAmount.amount":
if x.Amount == nil {
x.Amount = []*v1beta1.Coin{}
}
value := &_DistributionAmount_1_list{list: &x.Amount}
return protoreflect.ValueOfList(value)
default:
if fd.IsExtension() {
- panic(fmt.Errorf("proto3 declared messages do not support extensions: %s", fd.FullName()))
+ // Handle the error appropriately without panicking
+ return protoreflect.Value{}
}
- panic(fmt.Errorf("message cosmos.protocolpool.v1.DistributionAmount does not contain field %s", fd.FullName()))
+ // Handle the error appropriately without panicking
+ return protoreflect.Value{}
}
}
Adjust the method's return type and callers as necessary to handle the absence of a valid value.
Committable suggestion was skipped due to low confidence.
var _ protoreflect.List = (*_MsgCancelContinuousFundResponse_4_list)(nil) | ||
|
||
type _MsgCancelContinuousFundResponse_4_list struct { | ||
list *[]*v1beta1.Coin | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) Len() int { | ||
if x.list == nil { | ||
return 0 | ||
} | ||
return len(*x.list) | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) Get(i int) protoreflect.Value { | ||
return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) Set(i int, value protoreflect.Value) { | ||
valueUnwrapped := value.Message() | ||
concreteValue := valueUnwrapped.Interface().(*v1beta1.Coin) | ||
(*x.list)[i] = concreteValue | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) Append(value protoreflect.Value) { | ||
valueUnwrapped := value.Message() | ||
concreteValue := valueUnwrapped.Interface().(*v1beta1.Coin) | ||
*x.list = append(*x.list, concreteValue) | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) AppendMutable() protoreflect.Value { | ||
v := new(v1beta1.Coin) | ||
*x.list = append(*x.list, v) | ||
return protoreflect.ValueOfMessage(v.ProtoReflect()) | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) Truncate(n int) { | ||
for i := n; i < len(*x.list); i++ { | ||
(*x.list)[i] = nil | ||
} | ||
*x.list = (*x.list)[:n] | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) NewElement() protoreflect.Value { | ||
v := new(v1beta1.Coin) | ||
return protoreflect.ValueOfMessage(v.ProtoReflect()) | ||
} | ||
|
||
func (x *_MsgCancelContinuousFundResponse_4_list) IsValid() bool { | ||
return x.list != nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Refactor the internal list type into a reusable utility.
Consider extracting the _MsgCancelContinuousFundResponse_4_list
type and its methods into a reusable utility type. This will make the code more modular and reduce duplication if similar list types are needed elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall lgtm, one condition in genesis need to check
x/protocolpool/keeper/genesis.go
Outdated
if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) { | ||
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused a bit about the 1st condition, should return an error when totalToBeDistributed > lastBalance
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!
I am not very familiar with the module but I added some comments that may be helpful.
Are you planning to add a migration? That would be very helpful for existing chains.
You also mentioned an accept list to prevent spam. How is this going to be implemented and maintained?
x/protocolpool/keeper/genesis.go
Outdated
|
||
if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
last balance should always be >= total to be distributed.
Simplest thing would be to flip the check: totalToBeDistributed.IsAnyGT(last balance)
This includes the denoms implicite so that you can drop the DenomsSubsetOf
check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right about the inverted comparison, but I still need DenomsSubsetOf
, see:
// IsAnyGT returns true iff for any denom in coins, the denom is present at a
// greater amount in coinsB.
//
// e.g.
// {2A, 3B}.IsAnyGT{A} = true
// {2A, 3B}.IsAnyGT{5C} = false
// {}.IsAnyGT{5C} = false
// {2A, 3B}.IsAnyGT{} = false
This case {}.IsAnyGT{5C} = false
shows that if totalToBeDistributed has 1foo but LastBalance contains 1bar
, it will be false.
x/protocolpool/keeper/genesis.go
Outdated
if data.LastBalance.Amount.IsAnyGT(totalToBeDistributed) || !totalToBeDistributed.DenomsSubsetOf(data.LastBalance.Amount) { | ||
return errors.New("total to be distributed is greater than the last balance" + fmt.Sprint(data.LastBalance.Amount, totalToBeDistributed)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not simply go with fmt.Errorf
instead which is typically used in these scenarios? For example:
fmt.Errorf("an amount to be distributed is greater than the last balance: %s > %s", totalToBeDistributed, data.LastBalance.Amount))
x/protocolpool/keeper/keeper.go
Outdated
remaining := math.LegacyOneDec().Sub(percentageToDistribute).MulInt(amount).RoundInt() | ||
poolFunds = poolFunds.Add(remaining) | ||
for _, denom := range amount.Amount.Denoms() { | ||
remaining := sdk.NewCoin(denom, math.LegacyOneDec().Sub(percentageToDistribute).MulInt(amount.Amount.AmountOf(denom)).TruncateInt()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar code was used before but is another round down which has a rest that is not distributed.
Better remaining = amount - distributed amount
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be fixed now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Outside diff range and nitpick comments (5)
x/protocolpool/keeper/genesis.go (1)
Line range hint
120-125
: Wrap error when exporting distributions for better contextWrapping errors with contextual information enhances debuggability and maintains consistency in error handling.
Apply this diff to wrap the error:
if err != nil { - return nil, err + return nil, fmt.Errorf("failed to export distributions: %w", err) }x/protocolpool/keeper/keeper.go (4)
37-37
: Update the field comment for accuracyThe comment for the
Distributions
field mentionskey: time.Time, denom | value: amounts
, but the key istime.Time
and the value istypes.DistributionAmount
. Consider updating the comment to accurately reflect the key and value types.
Line range hint
221-316
: RefactorIterateAndUpdateFundsDistribution
for clarityThe
IterateAndUpdateFundsDistribution
function is lengthy and handles multiple responsibilities, including collecting continuous funds, calculating distributions, updating recipient distributions, and removing expired funds. Consider refactoring this function into smaller, well-named helper functions to improve readability and maintainability.
194-199
: Check for errors when setting distributionsEnsure that the error returned by
k.Distributions.Set
includes sufficient context. Currently, the error message is:return fmt.Errorf("error while setting Distributions: %w", err)Consider providing more details about the key or the amount being set to aid in debugging.
253-253
: Duplicate percentage checkThe check for
percentageToDistribute
exceeding1.0
is performed earlier at line 247. Consider refactoring or removing redundant checks to streamline the code.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
📒 Files selected for processing (3)
- x/protocolpool/keeper/genesis.go (2 hunks)
- x/protocolpool/keeper/genesis_test.go (2 hunks)
- x/protocolpool/keeper/keeper.go (10 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
x/protocolpool/keeper/genesis.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.x/protocolpool/keeper/genesis_test.go (2)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"x/protocolpool/keeper/keeper.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
📓 Learnings (1)
x/protocolpool/keeper/genesis.go (2)
Learnt from: likhita-809 PR: cosmos/cosmos-sdk#18471 File: x/protocolpool/keeper/genesis.go:12-51 Timestamp: 2024-10-08T15:31:05.486Z Learning: - The user `likhita-809` has confirmed the changes suggested in the previous interaction. - The file in question is `x/protocolpool/keeper/genesis.go` from a Cosmos SDK module. - The changes involve optimizing the `InitGenesis` function by removing redundant code and ensuring proper handling of start times for budget proposals.
Learnt from: likhita-809 PR: cosmos/cosmos-sdk#18471 File: x/protocolpool/keeper/genesis.go:12-51 Timestamp: 2023-11-22T12:32:39.368Z Learning: - The user `likhita-809` has confirmed the changes suggested in the previous interaction. - The file in question is `x/protocolpool/keeper/genesis.go` from a Cosmos SDK module. - The changes involve optimizing the `InitGenesis` function by removing redundant code and ensuring proper handling of start times for budget proposals.
🔇 Additional comments (4)
x/protocolpool/keeper/genesis.go (2)
57-59
: Logic for accumulating total distribution amount is correctThe code correctly initializes
totalToBeDistributed
withsdk.NewCoins()
and aggregates each distribution amount appropriately.
67-69
: Validation logic for distribution amounts is accurateThe condition properly checks if
totalToBeDistributed
exceedsdata.LastBalance.Amount
or if there are denominations not present indata.LastBalance.Amount
. This ensures that the system does not distribute more than what is available.x/protocolpool/keeper/keeper.go (2)
115-135
: Ensure proper handling of multiple coins inwithdrawRecipientFunds
The function
withdrawRecipientFunds
now returnssdk.Coins
instead ofsdk.Coin
, indicating support for multiple coin denominations. Verify that all downstream code and callers of this function properly handle multiple coins to prevent potential issues with coin denomination mismatches.
Line range hint
225-255
: Ensure proper distribution whenpercentageToDistribute
sum is less than 1When the total
percentageToDistribute
is less than1.0
, the remaining funds are calculated and added topoolFunds
. Verify that this logic aligns with the expected financial distribution model, and that all fractions of the funds are accounted for accurately.
Amount: types.DistributionAmount{Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(100)))}, | ||
Time: &time.Time{}, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider adding test cases with multiple denominations
While the test initializes the Distribution
with a single coin of denomination "stake"
, the goal of the PR is to allow any coins in continuous funds. To ensure comprehensive test coverage, please add test cases that include multiple denominations. This will help verify that distributions handle various coin types correctly.
Time: &time.Time{}, | ||
}) | ||
|
||
err := suite.poolKeeper.InitGenesis(suite.ctx, gs) | ||
suite.Require().ErrorContains(err, "total to be distributed is greater than the last balance") | ||
|
||
// Set last balance | ||
gs.LastBalance = math.NewInt(1) | ||
gs.LastBalance = types.DistributionAmount{Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(101)))} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Extend LastBalance
to include multiple denominations in tests
Currently, gs.LastBalance
is set using a single coin with denomination "stake"
. To fully test the new functionality that permits any coins, consider including multiple denominations in LastBalance
. This will ensure that the initialization logic handles a variety of coins appropriately.
@@ -49,5 +49,5 @@ | |||
suite.Require().NoError(err) | |||
suite.Require().Equal(gs.ContinuousFund, exportedGenState.ContinuousFund) | |||
suite.Require().Equal(gs.Budget, exportedGenState.Budget) | |||
suite.Require().Equal(math.OneInt(), exportedGenState.LastBalance) | |||
suite.Require().Equal(math.NewInt(101), exportedGenState.LastBalance.Amount.AmountOf("stake")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance assertions to cover multiple denominations
The assertion on line 52 checks the amount of "stake"
in exportedGenState.LastBalance
. To validate that ExportGenesis
correctly handles multiple coin denominations, please add assertions for other denominations. This will help confirm that the exported state accurately reflects all types of coins in the LastBalance
.
lastBalance, err := k.LastBalance.Get(ctx) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Wrap error when retrieving last balance for better context
When returning errors, it's recommended to wrap them with additional context to aid in debugging and provide clarity.
Apply this diff to wrap the error:
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("failed to get last balance: %w", err)
}
Committable suggestion was skipped due to low confidence.
} | ||
|
||
return nil | ||
} | ||
|
||
if err = k.Distributions.Set(ctx, k.HeaderService.HeaderInfo(ctx).Time, amountToDistribute); err != nil { | ||
if err = k.Distributions.Set(ctx, k.HeaderService.HeaderInfo(ctx).Time, types.DistributionAmount{Amount: amountToDistribute}); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirm uniqueness of timestamp keys in Distributions
Using k.HeaderService.HeaderInfo(ctx).Time
as the key in Distributions.Set
may lead to key collisions if multiple distributions occur within the same timestamp granularity. Consider ensuring that the timestamps used as keys are unique or incorporate additional logic to prevent accidental overwrites.
x/protocolpool/keeper/keeper.go
Outdated
poolFunds = poolFunds.Add(amount.Amount.Sub(fullAmountToDistribute...)...) | ||
for _, denom := range amount.Amount.Denoms() { | ||
remaining := sdk.NewCoin(denom, math.LegacyOneDec().Sub(percentageToDistribute).MulInt(amount.Amount.AmountOf(denom)).TruncateInt()) | ||
poolFunds = poolFunds.Add(remaining) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review calculation of poolFunds
to avoid double-counting
In lines 251 and 254, poolFunds
is being adjusted twice:
- Line 251 subtracts
fullAmountToDistribute
fromamount.Amount
and adds the result topoolFunds
. - Lines 253-255 calculate
remaining
and add it topoolFunds
.
This may result in double-counting the remaining funds. Consider consolidating the calculations to ensure that poolFunds
accurately reflects the undistributed amounts without duplication.
x/protocolpool/keeper/keeper.go
Outdated
poolFunds = poolFunds.Add(remaining) | ||
poolFunds = poolFunds.Add(amount.Amount.Sub(fullAmountToDistribute...)...) | ||
for _, denom := range amount.Amount.Denoms() { | ||
remaining := sdk.NewCoin(denom, math.LegacyOneDec().Sub(percentageToDistribute).MulInt(amount.Amount.AmountOf(denom)).TruncateInt()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential negative values in remaining funds calculation
When calculating remaining
:
remaining := sdk.NewCoin(denom, math.LegacyOneDec().Sub(percentageToDistribute).MulInt(amount.Amount.AmountOf(denom)).TruncateInt())
If percentageToDistribute
exceeds 1.0
, the subtraction could result in a negative value, leading to incorrect coin amounts. Ensure that percentageToDistribute
does not exceed 1.0
before performing this calculation.
amountToDistribute, anyNegative := currentBalance.SafeSub(lastBalance.Amount...) | ||
if anyNegative { | ||
return errors.New("error while calculating the amount to distribute, result can't be negative") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate SafeSub
operation to prevent unexpected errors
The use of SafeSub
may produce unexpected results if lastBalance.Amount
contains denominations not present in currentBalance
. This could cause anyNegative
to be true
even if overall balances are positive. Consider aligning denominations before subtraction or handling missing denominations explicitly.
if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ProtocolPoolDistrAccount, types.ModuleName, amountToDistribute); err != nil { | ||
return err | ||
} | ||
|
||
if !lastBalance.IsZero() { // only reset if the last balance is not zero (so we leave it at zero/nil) | ||
return k.LastBalance.Set(ctx, math.ZeroInt()) | ||
if !lastBalance.Amount.IsZero() { // only reset if the last balance is not zero (so we leave it at zero) | ||
return k.LastBalance.Set(ctx, types.DistributionAmount{Amount: sdk.NewCoins()}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve condition nesting in SetToDistribute
The nested if
statements can be simplified to enhance readability:
if !hasContinuousFunds {
if err := ...; err != nil {
return err
}
if !lastBalance.Amount.IsZero() {
return k.LastBalance.Set(ctx, types.DistributionAmount{Amount: sdk.NewCoins()})
}
return nil
}
Consider flattening the conditions or adding comments to clarify the flow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (6)
x/protocolpool/keeper/keeper.go (6)
45-45
: Consistent updates to NewKeeper functionThe changes in the NewKeeper function signature and the initialization of collections are consistent with the modifications in the Keeper struct. This ensures proper handling of the new
DistributionAmount
type.Consider adding error handling for the
collections.NewMap
andcollections.NewItem
calls to improve robustness.Also applies to: 70-72
115-115
: Enhanced flexibility in fund withdrawalThe modifications to
withdrawRecipientFunds
function, particularly the change to returnsdk.Coins
, align well with the PR objective of allowing any coins in continuous funds. The error handling has been improved, and the use ofDistributionAmount
is consistent with earlier changes.Consider using a custom error type for the "error while distributing funds" case to improve error handling consistency.
Also applies to: 120-122, 125-127, 131-133, 135-135
149-154
: Improved multi-denomination support in SetToDistributeThe changes in the
SetToDistribute
function, particularly the use ofsdk.Coins
andIsZero()
, enhance the support for multiple denominations and align with the PR objective. The error handling has been improved, making the code more robust.Consider adding a comment explaining the TODO on line 153 to clarify the intended future improvement.
Also applies to: 158-158, 165-168, 183-188, 194-194, 199-199
221-229
: Enhanced multi-denomination support in fund distributionThe modifications to the
IterateAndUpdateFundsDistribution
function significantly improve the handling of multiple denominations, aligning with the PR objective. The introduction ofamountToDistribute
andtotalDistribution
provides clearer tracking of distributed amounts.Consider using
sdk.NewCoins()
instead ofsdk.NewCoins()
for initializing empty coin sets to potentially improve performance.Also applies to: 239-245
264-264
: Improved fund distribution logicThe changes in the fund distribution logic, particularly the use of
IsZero()
and the updated handling of multi-denomination amounts, enhance the function's robustness and align with the PR objective.Consider adding error handling for the
k.LastBalance.Set
call on line 264 to improve the overall robustness of the function.Also applies to: 269-270, 275-277
275-279
: Consider explicit handling of potential negative valuesWhile the use of
sdk.Coins
may prevent negative values, consider adding an explicit check to ensurepoolFunds
is not negative before sending coins to the module. This would improve the robustness of the function and prevent potential issues if the underlying implementation ofsdk.Coins
changes.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
📒 Files selected for processing (1)
- x/protocolpool/keeper/keeper.go (10 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
x/protocolpool/keeper/keeper.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
🔇 Additional comments (5)
x/protocolpool/keeper/keeper.go (5)
24-25
: Improved flexibility in fund handlingThe changes to the Keeper struct, particularly the use of
types.DistributionAmount
forRecipientFundDistribution
,Distributions
, andLastBalance
, align well with the PR objective of allowing any coins in continuous funds. This modification enhances the module's flexibility in handling various token types.Also applies to: 36-38
299-299
: Consistent handling of multi-denomination amountsThe changes in the handling of
toClaim
, particularly the initialization withsdk.NewCoins()
and the use of theAdd
method, ensure consistent and correct handling of multi-denomination amounts. This aligns well with the PR objective and improves the overall robustness of the function.Also applies to: 305-306
275-275
: Improved calculation of poolFundsThe calculation of
poolFunds
has been updated to usetotalDistribution.Sub(amountToDistribute...)
, which addresses the potential double-counting issue highlighted in a previous review. This change improves the accuracy of the fund distribution process.
165-168
: Improve handling of mismatched denominations in SafeSub operationWhile
SafeSub
prevents underflow errors, it may still produce unexpected results iflastBalance.Amount
contains denominations not present incurrentBalance
. Consider aligning the denominations ofcurrentBalance
andlastBalance.Amount
before performing the subtraction, or explicitly handle cases where denominations don't match.
243-243
:⚠️ Potential issueReconsider the use of
TruncateInt()
in distribution calculationsThe use of
TruncateInt()
when calculating each recipient's share could lead to loss of fractional amounts. This may result in discrepancies, especially over time or with large amounts. Consider usingRoundInt()
instead, or implementing a more precise distribution mechanism that accounts for and redistributes any remaining fractional amounts.
return nil | ||
} | ||
|
||
// if the balance does not have any of the allowed denoms, return early // TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall this check be implemented now?
if err != nil { | ||
return err | ||
} | ||
|
||
currentBalance := k.bankKeeper.GetAllBalances(ctx, moduleAccount.GetAddress()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we get the usual: WhaT iF tHe modUle aCCounT Has ManY DeNOM?
Which is that case will be relatively valid. Any way we can make the claimer pay for this call?
As this is call in begin block maybe not, but what prevents in a token factory enabled chain, to send to the module accounts 1 millions worthless tokens until it slows the chain.
Unless we make ProtocolPoolDistrAccount
a blocked module account, like FeeCollector is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is call in begin block maybe not, but what prevents in a token factory enabled chain, to send to the module accounts 1 millions worthless tokens until it slows the chain.
Yeah, I thought the same, realistically it shouldn't be needed but it could make things go wrong in the long run, so I guess I'll add the whitelist now :/
fullAmountToDistribute := math.ZeroInt() | ||
toDistribute := map[string]sdk.Coins{} | ||
poolFunds := sdk.NewCoins() | ||
amountToDistribute := sdk.NewCoins() // amount assigned to distributions |
Check warning
Code scanning / CodeQL
Useless assignment to local variable Warning
Description
Previously only the bond denom could be used for continuous funds, now we allow any token. We might want to add a param with a whitelist of tokens to avoid spam.
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!
in the type prefix if API or client breaking changeCHANGELOG.md
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
Please see Pull Request Reviewer section in the contributing guide for more information on how to review a pull request.
I have...
Summary by CodeRabbit
New Features
DistributionAmount
structure for handling multiple coins.Improvements
LastBalance
andAmount
fields to utilize structured types instead of primitive strings.poolKeeper
by removing theStakingKeeper
dependency.Bug Fixes
Chores
StakingKeeper
interface and its mock implementations, streamlining the codebase.