Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Inject lacking hooks in nftbackedloan #649

Merged
merged 2 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 70 additions & 76 deletions x/ecosystemincentive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,7 @@ The subjects put the required information in somewhare (current idea is memo fie

## Contents

[Concepts](https://github.com/UnUniFi/chain/blob/design/spec/x/ecosystem-incentive/spec/01_concepts.md)
[State](https://github.com/UnUniFi/chain/blob/design/spec/x/ecosystem-incentive/spec/02_state.md)
[Messages and Queries](https://github.com/UnUniFi/chain/blob/design/spec/x/ecosystem-incentive/spec/03_messages.md)
[Hooks](https://github.com/UnUniFi/chain/blob/design/spec/x/ecosystem-incentive/spec/04_hooks.md)
[Memo Structure](https://github.com/UnUniFi/chain/blob/design/spec/x/ecosystem-incentive/spec/05_memo_structure.md)
[Events](https://github.com/UnUniFi/chain/blob/design/spec/x/ecosystem-incentive/spec/06_events.md)

### For developers in the core team

[ADR of this module](https://github.com/UnUniFi/chain/blob/design/spec/doc/architecture/adr-ecosystem-incentive.md)
There's info about the requirement to achieve the purpose of this module.
TODO: contents

# Concepts

Expand Down Expand Up @@ -189,6 +179,74 @@ message IncentiveUnitIdsByAddr {
}
```

# Hooks

**NOTE: This is early draft.**

All rewards accumulation are executed when the according hooks function is called.

The example hooks functions interfaces in x/nftbackedloan module:

```go
type nftbackedloanHooks interface {
AfterNftListed(ctx sdk.Context, nftIdentifier NftIdentifier, txMemo string)
AfterNftPaymentWithCommission(ctx sdk.Context, nftIdentifier NftIdentifier, fee sdk.Coin)
AfterNftUnlistedWithoutPayment(ctx sdk.Context, nftIdentifier NftIdentifier)
}
```

## AfterNftListed

This hook function is called for the resistration for the `ecosystem-incentive` with the `txMemo` and `nftIdentifiler`.
To pass the `txMemo` from the memo data of `MsgListNft` requires a method to get memo data in the process of `MsgListNft` in `x/nftbackedloan` module.

### Location to be inserted

- `ListNft(ctx sdk.Context, msg *types.MsgListNft)` from x/nftbackedloan in nft_listing.go

## AfterNftPaymentWithCommission

This hook function is called for the accumulation of the reward for the subjects which are connected with the `nftIdentifiler` in the argument.
The calculation of the actual reward amount is executed in methods which this hook function calls in this module.

### Location to be inserted

- `ProcessPaymentWithCommissionFee(ctx sdk.Context, listingOwner sdk.AccAddress, denom string, amount sdk.Int)` from x/nftbackedloan in nft_listing.go

## AfterNftUnlistedWithoutPayment

This hook function is called when a nft is unlisted for some reason like liquidation.
The purpose is to remove the unlisted nft information from `nftbackedloanFrontendIncentiveIdTable` KVStore to keep the data consystent.

### Location to be inserted

- `CancelNftListing(ctx sdk.Context, msg *types.MsgCancelNftListing)` from x/nftbackedloan in nft_listing.go
- Case which bid's length for the listing is 0 in `SetLiquidation(ctx sdk.Context, msg *types.MsgEndNftListing)` from x/nftbackedloan in nft_listing.go

# Data structure for the memo field

We use tx memo field data to identify what incentive will be distributed to what `incentive-unit` by putting the correct formatted json data into that.

The v1's formal data archtecture is:

```json
{
"version": "v1",
"incentive_unit_id": "incentive_unit-1"
}
```

NOTE: There's a lot of chances to be changed this structure with the change of the version. Please note it when to use.

## Frontends

We use memo field data to know which frontend a lisetd nft used in the case of frontend-incentive model.
So we have to use the organized data structure of memo field in a listing tx (MsgListNft) to distingush it as a legitimate entry or not.

Even if you put the wrong formatted data in the memo of tx contains MsgListNft, the MsgListNft itself will still succeed. The registration of the information which nft-id relates to what `incentive-unit-id` will just fail.



# Messages and Queries

**NOTE: This is early draft.**
Expand Down Expand Up @@ -355,71 +413,7 @@ message QueryIncentiveUnitIdsByAddrResponse {
}
```

# Hooks

**NOTE: This is early draft.**

All rewards accumulation are executed when the according hooks function is called.

The example hooks functions interfaces in x/nftbackedloan module:

```go
type nftbackedloanHooks interface {
AfterNftListed(ctx sdk.Context, nftIdentifier NftIdentifier, txMemo string)
AfterNftPaymentWithCommission(ctx sdk.Context, nftIdentifier NftIdentifier, fee sdk.Coin)
AfterNftUnlistedWithoutPayment(ctx sdk.Context, nftIdentifier NftIdentifier)
}
```

## AfterNftListed

This hook function is called for the resistration for the `ecosystem-incentive` with the `txMemo` and `nftIdentifiler`.
To pass the `txMemo` from the memo data of `MsgListNft` requires a method to get memo data in the process of `MsgListNft` in `x/nftbackedloan` module.

### Location to be inserted

- `ListNft(ctx sdk.Context, msg *types.MsgListNft)` from x/nftbackedloan in nft_listing.go

## AfterNftPaymentWithCommission

This hook function is called for the accumulation of the reward for the subjects which are connected with the `nftIdentifiler` in the argument.
The calculation of the actual reward amount is executed in methods which this hook function calls in this module.

### Location to be inserted

- `ProcessPaymentWithCommissionFee(ctx sdk.Context, listingOwner sdk.AccAddress, denom string, amount sdk.Int)` from x/nftbackedloan in nft_listing.go

## AfterNftUnlistedWituoutPayment

This hook function is called when a nft is unlisted for some reason like liquidation.
The purpose is to remove the unlisted nft information from `nftbackedloanFrontendIncentiveIdTable` KVStore to keep the data consystent.

### Location to be inserted

- `CancelNftListing(ctx sdk.Context, msg *types.MsgCancelNftListing)` from x/nftbackedloan in nft_listing.go
- Case which bid's length for the listing is 0 in `EndNftListing(ctx sdk.Context, msg *types.MsgEndNftListing)` from x/nftbackedloan in nft_listing.go

# Data structure for the memo field

We use tx memo field data to identify what incentive will be distributed to what `incentive-unit` by putting the correct formatted json data into that.

The v1's formal data archtecture is:

```json
{
"version": "v1",
"incentive_unit_id": "incentive_unit-1"
}
```

NOTE: There's a lot of chances to be changed this structure with the change of the version. Please note it when to use.

## Frontends

We use memo field data to know which frontend a lisetd nft used in the case of frontend-incentive model.
So we have to use the organized data structure of memo field in a listing tx (MsgListNft) to distingush it as a legitimate entry or not.

Even if you put the wrong formatted data in the memo of tx contains MsgListNft, the MsgListNft itself will still succeed. The registration of the information which nft-id relates to what `incentive-unit-id` will just fail.
# Events

```protobuf
message EventRegister {
Expand Down
13 changes: 7 additions & 6 deletions x/nftbackedloan/keeper/liquidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ func (k Keeper) SetLiquidation(ctx sdk.Context, msg *types.MsgEndNftListing) err
return err
}
k.DeleteNftListings(ctx, listing)

// Call AfterNftUnlistedWithoutPayment to delete NFT ID from the ecosystem-incentive KVStore
// since it's unlisted.
if _, err := k.GetNftListingByIdBytes(ctx, msg.NftId.IdBytes()); err != nil {
k.AfterNftUnlistedWithoutPayment(ctx, listing.NftId)
}

} else {
params := k.GetParamSet(ctx)
listing.State = types.ListingState_LIQUIDATION
Expand Down Expand Up @@ -82,12 +89,6 @@ func (k Keeper) SetLiquidation(ctx sdk.Context, msg *types.MsgEndNftListing) err
NftId: msg.NftId.NftId,
})

// Call AfterNftUnlistedWithoutPayment to delete NFT ID from the ecosystem-incentive KVStore
// since it's unlisted.
if _, err := k.GetNftListingByIdBytes(ctx, msg.NftId.IdBytes()); err != nil {
k.AfterNftUnlistedWithoutPayment(ctx, listing.NftId)
}

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions x/nftbackedloan/keeper/nft_listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ func (k Keeper) ListNft(ctx sdk.Context, msg *types.MsgListNft) error {
return err
}

// get the memo data from Tx contains MsgListNft
k.AfterNftListed(ctx, msg.NftId, GetMemo(ctx.TxBytes(), k.txCfg))

// Emit event for nft listing
_ = ctx.EventManager().EmitTypedEvent(&types.EventListingNft{
Owner: msg.Sender,
Expand Down Expand Up @@ -283,6 +286,10 @@ func (k Keeper) CancelNftListing(ctx sdk.Context, msg *types.MsgCancelNftListing
// delete listing
k.DeleteNftListings(ctx, listing)

// Call AfterNftUnlistedWithoutPayment to delete NFT ID from the ecosystem-incentive KVStore
// since it's unlisted.
k.AfterNftUnlistedWithoutPayment(ctx, listing.NftId)

// Emit event for nft listing cancel
_ = ctx.EventManager().EmitTypedEvent(&types.EventCancelListingNft{
Owner: msg.Sender,
Expand Down
17 changes: 9 additions & 8 deletions x/nftbackedloan/keeper/nft_listing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestListNft() {
mintBefore: true,
listBefore: true,
expectPass: false,
statusListedHook: false,
statusListedHook: true,
},
{
testCase: "not owned nft",
Expand Down Expand Up @@ -87,7 +87,7 @@ func (suite *KeeperTestSuite) TestListNft() {
mintBefore: true,
listBefore: false,
expectPass: true,
statusListedHook: false,
statusListedHook: true,
},
{
testCase: "successful listing with non-default active rank",
Expand All @@ -99,7 +99,7 @@ func (suite *KeeperTestSuite) TestListNft() {
mintBefore: true,
listBefore: false,
expectPass: true,
statusListedHook: false,
statusListedHook: true,
},
{
testCase: "successful anther owner",
Expand All @@ -111,7 +111,7 @@ func (suite *KeeperTestSuite) TestListNft() {
mintBefore: true,
listBefore: false,
expectPass: true,
statusListedHook: false,
statusListedHook: true,
},
}

Expand All @@ -134,15 +134,16 @@ func (suite *KeeperTestSuite) TestListNft() {
suite.Require().NoError(err)
}
if tc.listBefore {
err := suite.app.NftbackedloanKeeper.ListNft(suite.ctx, &types.MsgListNft{
// use keeper directly to be executed with hooks structs
err := keeper.ListNft(suite.ctx, &types.MsgListNft{
Sender: tc.lister.String(),
NftId: types.NftIdentifier{ClassId: tc.classId, NftId: tc.nftId},
BidDenom: tc.BidDenom,
MinimumDepositRate: sdk.MustNewDecFromStr("0.1"),
})
suite.Require().NoError(err)
}
err := suite.app.NftbackedloanKeeper.ListNft(suite.ctx, &types.MsgListNft{
err := keeper.ListNft(suite.ctx, &types.MsgListNft{
Sender: tc.lister.String(),
NftId: types.NftIdentifier{ClassId: tc.classId, NftId: tc.nftId},
BidDenom: tc.BidDenom,
Expand Down Expand Up @@ -237,7 +238,7 @@ func (suite *KeeperTestSuite) TestCancelNftListing() {
numBids: 0,
listBefore: true,
expectPass: true,
statusUnlistedHook: false,
statusUnlistedHook: true,
},
{
testCase: "successful cancel with cancel fee",
Expand All @@ -249,7 +250,7 @@ func (suite *KeeperTestSuite) TestCancelNftListing() {
numBids: 0,
listBefore: true,
expectPass: true,
statusUnlistedHook: false,
statusUnlistedHook: true,
},
}

Expand Down
24 changes: 24 additions & 0 deletions x/nftbackedloan/keeper/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package keeper

import (
"fmt"

"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/UnUniFi/chain/x/nftbackedloan/types"
Expand Down Expand Up @@ -48,3 +51,24 @@ func checkListNft(k Keeper, ctx sdk.Context, sender sdk.AccAddress, nftId types.

return nil
}

func GetMemo(txBytes []byte, txCfg client.TxConfig) string {
/// NOTE: this way requires txConfig by importing it into keeper struct
txData, err := txCfg.TxDecoder()(txBytes)
if err != nil {
fmt.Printf("err: %v\n", err)

txData, err = txCfg.TxJSONDecoder()(txBytes)
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

txBldr, err := txCfg.WrapTxBuilder(txData)
if err != nil {
return ""
}
memo := txBldr.GetTx().GetMemo()

return memo
}