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

[LUM-807] Claim & Compound #52

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
12 changes: 12 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,13 @@ func (app *App) registerUpgradeHandlers() {
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})

app.UpgradeKeeper.SetUpgradeHandler("v1.6.1", func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
app.Logger().Info("Starting v1.6.1 upgrade")

app.Logger().Info("v1.6.1 upgrade applied")
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})

upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
if err != nil {
panic(fmt.Sprintf("failed to read upgrade info from disk %s", err))
Expand Down Expand Up @@ -985,4 +992,9 @@ func (app *App) registerUpgradeHandlers() {
storeUpgrades := storetypes.StoreUpgrades{}
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
}

if upgradeInfo.Name == "v1.6.1" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
storeUpgrades := storetypes.StoreUpgrades{}
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
}
}
12 changes: 11 additions & 1 deletion proto/lum/network/millions/deposit.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ enum DepositState {
DEPOSIT_STATE_FAILURE = 4 [ (gogoproto.enumvalue_customname) = "Failure" ];
}

enum DepositOrigin {
option (gogoproto.goproto_enum_prefix) = true;

DEPOSIT_ORIGIN_UNSPECIFIED = 0
[ (gogoproto.enumvalue_customname) = "Unspecified" ];
DEPOSIT_ORIGIN_DIRECT = 1 [ (gogoproto.enumvalue_customname) = "Direct" ];
DEPOSIT_ORIGIN_AUTOCOMPOUND = 2
[ (gogoproto.enumvalue_customname) = "Autocompound" ];
}

message Deposit {
uint64 pool_id = 1;
uint64 deposit_id = 2;
Expand All @@ -35,7 +45,7 @@ message Deposit {

string winner_address = 7 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
bool is_sponsor = 8;
reserved 9;
DepositOrigin origin = 9;

int64 created_at_height = 10;
int64 updated_at_height = 11;
Expand Down
2 changes: 2 additions & 0 deletions proto/lum/network/millions/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ message MsgClaimPrize {
uint64 draw_id = 2;
uint64 prize_id = 3;
string winner_address = 4 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
bool is_auto_compound = 5;
bool is_sponsor = 6;
}

message MsgClaimPrizeResponse {}
Expand Down
26 changes: 23 additions & 3 deletions x/millions/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,20 @@ $ %s tx %s deposit-edit <pool_id> <deposit_id> --winner_address=<address> --spon

func CmdTxClaimPrize() *cobra.Command {
cmd := &cobra.Command{
Use: "claim-prize <pool_id> <draw_id> <prize_id>",
Use: "claim-prize <pool_id> <draw_id> <prize_id> [autocompound] [sponsor]",
Short: "Claim a millions prize",
Long: strings.TrimSpace(
fmt.Sprintf(`Claim a millions prize to send the funds to the prize winner address.

Example:
$ %s tx %s claim-prize <pool_id> <draw_id> <prize_id>`,
version.AppName, types.ModuleName),
$ %s tx %s claim-prize <pool_id> <draw_id> <prize_id>

To claim a prize and auto compound it (create a new deposit with the prize amount)
$ %s tx %s claim-prize <pool_id> <draw_id> <prize_id> --autocompound=true

To claim a prize and create a sponsorship from the auto compound deposit (no drawing chances at all)
$ %s tx %s claim-prize <pool_id> <draw_id> <prize_id> --autocompound=true --sponsor=true`,
version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName),
),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -275,13 +281,27 @@ $ %s tx %s claim-prize <pool_id> <draw_id> <prize_id>`,
return err
}

isAutoCompound, err := cmd.Flags().GetBool("autocompound")
if err != nil {
return err
}

isSponsor, err := cmd.Flags().GetBool("sponsor")
if err != nil {
return err
}

// Build the message
msg := types.NewMsgMsgClaimPrize(clientCtx.GetFromAddress().String(), poolID, drawID, prizeID)
msg.IsAutoCompound = isAutoCompound
msg.IsSponsor = isSponsor

// Generate the transaction
return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg)
},
}
cmd.Flags().Bool("autocompound", false, "(optional) creates a new auto compound deposit with the prize amount")
cmd.Flags().Bool("sponsor", false, "(optional) active sponsor mode for the new auto compound deposit")
flags.AddTxFlagsToCmd(cmd)
_ = cmd.MarkFlagRequired(flags.FlagFrom)
return cmd
Expand Down
22 changes: 11 additions & 11 deletions x/millions/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ var testGenesis = millionstypes.GenesisState{
},
},
Deposits: []millionstypes.Deposit{
{PoolId: 1, DepositId: 1, DepositorAddress: testAccs[0], WinnerAddress: testAccs[0], Amount: sdk.NewCoin("denom-1", sdk.NewInt(100)), State: millionstypes.DepositState_IbcTransfer},
{PoolId: 1, DepositId: 2, DepositorAddress: testAccs[0], WinnerAddress: testAccs[0], Amount: sdk.NewCoin("denom-1", sdk.NewInt(101)), State: millionstypes.DepositState_IcaDelegate},
{PoolId: 1, DepositId: 3, DepositorAddress: testAccs[1], WinnerAddress: testAccs[1], Amount: sdk.NewCoin("denom-1", sdk.NewInt(102)), State: millionstypes.DepositState_Success},
{PoolId: 1, DepositId: 4, DepositorAddress: testAccs[1], WinnerAddress: testAccs[1], Amount: sdk.NewCoin("denom-1", sdk.NewInt(103)), State: millionstypes.DepositState_Failure},
{PoolId: 1, DepositId: 5, DepositorAddress: testAccs[2], WinnerAddress: testAccs[2], Amount: sdk.NewCoin("denom-1", sdk.NewInt(104)), State: millionstypes.DepositState_IbcTransfer},
{PoolId: 2, DepositId: 6, DepositorAddress: testAccs[2], WinnerAddress: testAccs[2], Amount: sdk.NewCoin("denom-2", sdk.NewInt(200)), IsSponsor: true, State: millionstypes.DepositState_IbcTransfer},
{PoolId: 2, DepositId: 7, DepositorAddress: testAccs[3], WinnerAddress: testAccs[3], Amount: sdk.NewCoin("denom-2", sdk.NewInt(201)), IsSponsor: true, State: millionstypes.DepositState_IbcTransfer},
{PoolId: 2, DepositId: 8, DepositorAddress: testAccs[3], WinnerAddress: testAccs[3], Amount: sdk.NewCoin("denom-2", sdk.NewInt(202)), State: millionstypes.DepositState_IbcTransfer},
{PoolId: 3, DepositId: 9, DepositorAddress: testAccs[4], WinnerAddress: testAccs[4], Amount: sdk.NewCoin("denom-3", sdk.NewInt(300)), State: millionstypes.DepositState_Success},
{PoolId: 3, DepositId: 10, DepositorAddress: testAccs[4], WinnerAddress: testAccs[4], Amount: sdk.NewCoin("denom-3", sdk.NewInt(301)), State: millionstypes.DepositState_Success},
{PoolId: 4, DepositId: 11, DepositorAddress: testAccs[5], WinnerAddress: testAccs[5], Amount: sdk.NewCoin("denom-4", sdk.NewInt(400)), State: millionstypes.DepositState_Success},
{PoolId: 1, DepositId: 1, DepositorAddress: testAccs[0], WinnerAddress: testAccs[0], Amount: sdk.NewCoin("denom-1", sdk.NewInt(100)), State: millionstypes.DepositState_IbcTransfer, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 1, DepositId: 2, DepositorAddress: testAccs[0], WinnerAddress: testAccs[0], Amount: sdk.NewCoin("denom-1", sdk.NewInt(101)), State: millionstypes.DepositState_IcaDelegate, Origin: millionstypes.DepositOrigin_Autocompound},
{PoolId: 1, DepositId: 3, DepositorAddress: testAccs[1], WinnerAddress: testAccs[1], Amount: sdk.NewCoin("denom-1", sdk.NewInt(102)), State: millionstypes.DepositState_Success, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 1, DepositId: 4, DepositorAddress: testAccs[1], WinnerAddress: testAccs[1], Amount: sdk.NewCoin("denom-1", sdk.NewInt(103)), State: millionstypes.DepositState_Failure, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 1, DepositId: 5, DepositorAddress: testAccs[2], WinnerAddress: testAccs[2], Amount: sdk.NewCoin("denom-1", sdk.NewInt(104)), State: millionstypes.DepositState_IbcTransfer, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 2, DepositId: 6, DepositorAddress: testAccs[2], WinnerAddress: testAccs[2], Amount: sdk.NewCoin("denom-2", sdk.NewInt(200)), IsSponsor: true, State: millionstypes.DepositState_IbcTransfer, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 2, DepositId: 7, DepositorAddress: testAccs[3], WinnerAddress: testAccs[3], Amount: sdk.NewCoin("denom-2", sdk.NewInt(201)), IsSponsor: true, State: millionstypes.DepositState_IbcTransfer, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 2, DepositId: 8, DepositorAddress: testAccs[3], WinnerAddress: testAccs[3], Amount: sdk.NewCoin("denom-2", sdk.NewInt(202)), State: millionstypes.DepositState_IbcTransfer, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 3, DepositId: 9, DepositorAddress: testAccs[4], WinnerAddress: testAccs[4], Amount: sdk.NewCoin("denom-3", sdk.NewInt(300)), State: millionstypes.DepositState_Success, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 3, DepositId: 10, DepositorAddress: testAccs[4], WinnerAddress: testAccs[4], Amount: sdk.NewCoin("denom-3", sdk.NewInt(301)), State: millionstypes.DepositState_Success, Origin: millionstypes.DepositOrigin_Direct},
{PoolId: 4, DepositId: 11, DepositorAddress: testAccs[5], WinnerAddress: testAccs[5], Amount: sdk.NewCoin("denom-4", sdk.NewInt(400)), State: millionstypes.DepositState_Success, Origin: millionstypes.DepositOrigin_Autocompound},
},
Draws: []millionstypes.Draw{
{PoolId: 1, DrawId: 1, RandSeed: 10, TotalWinCount: 100, TotalWinAmount: sdk.NewInt(1000)},
Expand Down
116 changes: 116 additions & 0 deletions x/millions/keeper/keeper_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package keeper

import (
"fmt"
"strconv"
"strings"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -213,6 +215,101 @@ func (k Keeper) AddDeposit(ctx sdk.Context, deposit *types.Deposit) {
k.updatePool(ctx, &pool)
}

// CreateDeposit creates a deposit from the transaction message
// Holds the internal validation logic
func (k Keeper) CreateDeposit(ctx sdk.Context, msg *types.MsgDeposit, depositOrigin types.DepositOrigin) (*types.Deposit, error) {
// Get the pool to validate id and denom
pool, err := k.GetPool(ctx, msg.GetPoolId())
if err != nil {
return nil, types.ErrPoolNotFound
}

if pool.State != types.PoolState_Ready && pool.State != types.PoolState_Paused {
return nil, errorsmod.Wrapf(
types.ErrInvalidPoolState, "cannot deposit in pool during state %s", pool.State.String(),
)
}

depositorAddr, err := sdk.AccAddressFromBech32(msg.GetDepositorAddress())
if err != nil {
return nil, types.ErrInvalidDepositorAddress
}

if msg.Amount.Denom != pool.Denom {
return nil, types.ErrInvalidDepositDenom
}

// Make sure the deposit is sufficient for direct deposits
if depositOrigin == types.DepositOrigin_Direct {
if msg.GetAmount().Amount.LT(pool.MinDepositAmount) {
return nil, types.ErrInsufficientDepositAmount
}
}

winnerAddress := depositorAddr
if strings.TrimSpace(msg.GetWinnerAddress()) != "" {
winnerAddress, err = sdk.AccAddressFromBech32(msg.GetWinnerAddress())
if err != nil {
return nil, types.ErrInvalidWinnerAddress
}
}

if !depositorAddr.Equals(winnerAddress) && msg.GetIsSponsor() {
return nil, types.ErrInvalidSponsorWinnerCombo
}

// New deposit instance
deposit := types.Deposit{
PoolId: pool.PoolId,
State: types.DepositState_IbcTransfer,
DepositorAddress: depositorAddr.String(),
Amount: msg.Amount,
WinnerAddress: winnerAddress.String(),
IsSponsor: msg.GetIsSponsor(),
Origin: depositOrigin,
CreatedAtHeight: ctx.BlockHeight(),
UpdatedAtHeight: ctx.BlockHeight(),
CreatedAt: ctx.BlockTime(),
UpdatedAt: ctx.BlockTime(),
}

// Move funds
poolRunner, err := k.GetPoolRunner(pool.PoolType)
if err != nil {
return nil, errorsmod.Wrapf(types.ErrInvalidPoolType, err.Error())
}
if err := poolRunner.SendDepositToPool(ctx, pool, deposit); err != nil {
return nil, err
}

// Store deposit
k.AddDeposit(ctx, &deposit)

if err := k.TransferDepositToRemoteZone(ctx, deposit.GetPoolId(), deposit.GetDepositId()); err != nil {
return nil, err
}

// Emit event
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
),
sdk.NewEvent(
types.EventTypeDeposit,
sdk.NewAttribute(types.AttributeKeyPoolID, strconv.FormatUint(deposit.DepositId, 10)),
sdk.NewAttribute(types.AttributeKeyDepositID, strconv.FormatUint(deposit.DepositId, 10)),
sdk.NewAttribute(types.AttributeKeyDepositor, deposit.GetDepositorAddress()),
sdk.NewAttribute(types.AttributeKeyWinner, deposit.GetWinnerAddress()),
sdk.NewAttribute(sdk.AttributeKeyAmount, deposit.Amount.String()),
sdk.NewAttribute(types.AttributeKeySponsor, strconv.FormatBool(deposit.IsSponsor)),
sdk.NewAttribute(types.AttributeKeyOrigin, deposit.Origin.String()),
),
})

return &deposit, nil
}

// RemoveDeposit removes a deposit from a pool
// - removes it from the {pool_id, deposit_id}
// - removes it from the {address, pool_id, deposit_id} deposits
Expand Down Expand Up @@ -329,6 +426,25 @@ func (k Keeper) hasPoolDeposit(ctx sdk.Context, address string, poolID uint64) b
return iterator.Valid()
}

// UnsafeUpdateAutoCompoundDeposits raw updates deposit's origin
// It's heavily unsafe and should only be used by store migrations
func (k Keeper) UnsafeUpdateAutoCompoundDeposits(ctx sdk.Context, poolID uint64, depositID uint64, depositOrigin types.DepositOrigin) (types.Deposit, error) {
// Acquire the deposit
deposit, err := k.GetPoolDeposit(ctx, poolID, depositID)
if err != nil {
return types.Deposit{}, err
}

deposit.Origin = depositOrigin
deposit.UpdatedAtHeight = ctx.BlockHeight()
deposit.UpdatedAt = ctx.BlockTime()
Ricardo-Remy marked this conversation as resolved.
Show resolved Hide resolved

k.setPoolDeposit(ctx, &deposit)
k.setAccountDeposit(ctx, &deposit)

return deposit, nil
}

// ListPoolDeposits returns all deposits for a given poolID
// Warning: expensive operation
func (k Keeper) ListPoolDeposits(ctx sdk.Context, poolID uint64) (deposits []types.Deposit) {
Expand Down
Loading