github.com/KiraCore/sekai@v0.3.43/x/tokens/handler_test.go (about) 1 package tokens_test 2 3 import ( 4 "bytes" 5 "os" 6 "strconv" 7 "strings" 8 "testing" 9 "time" 10 11 simapp "github.com/KiraCore/sekai/app" 12 appparams "github.com/KiraCore/sekai/app/params" 13 "github.com/KiraCore/sekai/x/gov" 14 "github.com/KiraCore/sekai/x/gov/types" 15 govtypes "github.com/KiraCore/sekai/x/gov/types" 16 tokens "github.com/KiraCore/sekai/x/tokens" 17 tokenstypes "github.com/KiraCore/sekai/x/tokens/types" 18 tmproto "github.com/cometbft/cometbft/proto/tendermint/types" 19 sdk "github.com/cosmos/cosmos-sdk/types" 20 "github.com/cosmos/cosmos-sdk/types/errors" 21 "github.com/gogo/protobuf/proto" 22 "github.com/stretchr/testify/require" 23 ) 24 25 func TestMain(m *testing.M) { 26 appparams.SetConfig() 27 os.Exit(m.Run()) 28 } 29 30 func NewAccountByIndex(accNum int) sdk.AccAddress { 31 var buffer bytes.Buffer 32 i := accNum + 100 33 numString := strconv.Itoa(i) 34 buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string 35 36 buffer.WriteString(numString) //adding on final two digits to make addresses unique 37 res, _ := sdk.AccAddressFromHexUnsafe(buffer.String()) 38 bech := res.String() 39 addr, _ := simapp.TestAddr(buffer.String(), bech) 40 buffer.Reset() 41 return addr 42 } 43 44 func setPermissionToAddr(t *testing.T, app *simapp.SekaiApp, ctx sdk.Context, addr sdk.AccAddress, perm types.PermValue) error { 45 proposerActor := govtypes.NewDefaultActor(addr) 46 err := proposerActor.Permissions.AddToWhitelist(perm) 47 require.NoError(t, err) 48 49 app.CustomGovKeeper.SaveNetworkActor(ctx, proposerActor) 50 51 return nil 52 } 53 54 func TestNewHandler_MsgUpsertTokenAlias(t *testing.T) { 55 app := simapp.Setup(false) 56 ctx := app.NewContext(false, tmproto.Header{}) 57 handler := tokens.NewHandler(app.TokensKeeper, app.CustomGovKeeper) 58 59 tests := []struct { 60 name string 61 constructor func(sdk.AccAddress) (*tokenstypes.MsgUpsertTokenAlias, error) 62 handlerErr string 63 }{ 64 { 65 name: "good permission test", 66 constructor: func(addr sdk.AccAddress) (*tokenstypes.MsgUpsertTokenAlias, error) { 67 err := setPermissionToAddr(t, app, ctx, addr, types.PermUpsertTokenAlias) 68 require.NoError(t, err) 69 return tokenstypes.NewMsgUpsertTokenAlias( 70 addr, 71 "ETH", 72 "Ethereum", 73 "icon", 74 6, 75 []string{"finney"}, 76 false, 77 ), nil 78 }, 79 }, 80 { 81 name: "lack permission test", 82 constructor: func(addr sdk.AccAddress) (*tokenstypes.MsgUpsertTokenAlias, error) { 83 return tokenstypes.NewMsgUpsertTokenAlias( 84 addr, 85 "ETH", 86 "Ethereum", 87 "icon", 88 6, 89 []string{"finney"}, 90 false, 91 ), nil 92 }, 93 handlerErr: "PERMISSION_UPSERT_TOKEN_ALIAS: not enough permissions", 94 }, 95 } 96 for i, tt := range tests { 97 addr := NewAccountByIndex(i) 98 theMsg, err := tt.constructor(addr) 99 require.NoError(t, err) 100 101 _, err = handler(ctx, theMsg) 102 if len(tt.handlerErr) != 0 { 103 require.Error(t, err) 104 require.Contains(t, err.Error(), tt.handlerErr) 105 } else { 106 require.NoError(t, err) 107 108 // test various query commands 109 alias := app.TokensKeeper.GetTokenAlias(ctx, theMsg.Symbol) 110 require.True(t, alias != nil) 111 aliasesAll := app.TokensKeeper.ListTokenAlias(ctx) 112 require.True(t, len(aliasesAll) > 0) 113 aliasesByDenom := app.TokensKeeper.GetTokenAliasesByDenom(ctx, theMsg.Denoms) 114 require.True(t, aliasesByDenom[theMsg.Denoms[0]] != nil) 115 116 // try different alias for same denom 117 theMsg.Symbol += "V2" 118 _, err = handler(ctx, theMsg) 119 require.Error(t, err) 120 require.True(t, strings.Contains(err.Error(), "denom is already registered")) 121 } 122 } 123 } 124 125 func TestNewHandler_MsgUpsertTokenRate(t *testing.T) { 126 127 app := simapp.Setup(false) 128 ctx := app.NewContext(false, tmproto.Header{}) 129 handler := tokens.NewHandler(app.TokensKeeper, app.CustomGovKeeper) 130 131 tests := []struct { 132 name string 133 constructor func(sdk.AccAddress) (*tokenstypes.MsgUpsertTokenRate, error) 134 handlerErr string 135 }{ 136 { 137 name: "good permission test", 138 constructor: func(addr sdk.AccAddress) (*tokenstypes.MsgUpsertTokenRate, error) { 139 err := setPermissionToAddr(t, app, ctx, addr, types.PermUpsertTokenRate) 140 require.NoError(t, err) 141 return tokenstypes.NewMsgUpsertTokenRate( 142 addr, 143 "finney", sdk.NewDecWithPrec(1, 3), // 0.001 144 true, 145 sdk.ZeroDec(), 146 sdk.ZeroInt(), 147 false, 148 false, 149 ), nil 150 }, 151 }, 152 { 153 name: "lack permission test", 154 constructor: func(addr sdk.AccAddress) (*tokenstypes.MsgUpsertTokenRate, error) { 155 return tokenstypes.NewMsgUpsertTokenRate( 156 addr, 157 "finney", sdk.NewDecWithPrec(1, 3), // 0.001 158 true, 159 sdk.ZeroDec(), 160 sdk.ZeroInt(), 161 false, 162 false, 163 ), nil 164 }, 165 handlerErr: "PERMISSION_UPSERT_TOKEN_RATE: not enough permissions", 166 }, 167 { 168 name: "negative rate value test", 169 constructor: func(addr sdk.AccAddress) (*tokenstypes.MsgUpsertTokenRate, error) { 170 return tokenstypes.NewMsgUpsertTokenRate( 171 addr, 172 "finney", sdk.NewDec(-1), // -1 173 true, 174 sdk.ZeroDec(), 175 sdk.ZeroInt(), 176 false, 177 false, 178 ), nil 179 }, 180 handlerErr: "rate should be positive", 181 }, 182 { 183 name: "bond denom rate change test", 184 constructor: func(addr sdk.AccAddress) (*tokenstypes.MsgUpsertTokenRate, error) { 185 err := setPermissionToAddr(t, app, ctx, addr, types.PermUpsertTokenRate) 186 require.NoError(t, err) 187 return tokenstypes.NewMsgUpsertTokenRate( 188 addr, 189 "ukex", sdk.NewDec(10), 190 true, 191 sdk.ZeroDec(), 192 sdk.ZeroInt(), 193 false, 194 false, 195 ), nil 196 }, 197 handlerErr: "bond denom rate is read-only", 198 }, 199 } 200 for i, tt := range tests { 201 addr := NewAccountByIndex(i) 202 theMsg, err := tt.constructor(addr) 203 require.NoError(t, err) 204 205 _, err = handler(ctx, theMsg) 206 if len(tt.handlerErr) != 0 { 207 require.Error(t, err) 208 require.Contains(t, err.Error(), tt.handlerErr) 209 } else { 210 require.NoError(t, err) 211 212 // test various query commands 213 rate := app.TokensKeeper.GetTokenRate(ctx, theMsg.Denom) 214 require.True(t, rate != nil) 215 ratesAll := app.TokensKeeper.GetAllTokenRates(ctx) 216 require.True(t, len(ratesAll) > 0) 217 ratesByDenom := app.TokensKeeper.GetTokenRatesByDenom(ctx, []string{theMsg.Denom}) 218 require.True(t, ratesByDenom[theMsg.Denom] != nil) 219 } 220 } 221 } 222 223 func TestHandler_CreateProposalUpsertTokenAliases_Errors(t *testing.T) { 224 proposerAddr, err := sdk.AccAddressFromBech32("kira1alzyfq40zjsveat87jlg8jxetwqmr0a29sgd0f") 225 require.NoError(t, err) 226 227 tests := []struct { 228 name string 229 content govtypes.Content 230 preparePerms func(t *testing.T, app *simapp.SekaiApp, ctx sdk.Context) 231 expectedErr error 232 }{ 233 { 234 "Proposer does not have Perm", 235 tokenstypes.NewUpsertTokenAliasProposal( 236 "BTC", 237 "Bitcoin", 238 "http://theicon.com", 239 18, 240 []string{}, 241 false, 242 ), 243 func(t *testing.T, app *simapp.SekaiApp, ctx sdk.Context) {}, 244 errors.Wrap(types.ErrNotEnoughPermissions, types.PermCreateUpsertTokenAliasProposal.String()), 245 }, 246 } 247 248 for _, tt := range tests { 249 tt := tt 250 t.Run(tt.name, func(t *testing.T) { 251 app := simapp.Setup(false) 252 ctx := app.NewContext(false, tmproto.Header{}) 253 254 tt.preparePerms(t, app, ctx) 255 256 handler := gov.NewHandler(app.CustomGovKeeper) 257 msg, err := govtypes.NewMsgSubmitProposal(proposerAddr, "title", "some desc", tt.content) 258 require.NoError(t, err) 259 _, err = handler(ctx, msg) 260 require.EqualError(t, err, tt.expectedErr.Error()) 261 }) 262 } 263 } 264 265 func TestHandler_CreateProposalUpsertTokenAliases(t *testing.T) { 266 proposerAddr, err := sdk.AccAddressFromBech32("kira1alzyfq40zjsveat87jlg8jxetwqmr0a29sgd0f") 267 require.NoError(t, err) 268 269 app := simapp.Setup(false) 270 ctx := app.NewContext(false, tmproto.Header{ 271 Time: time.Now(), 272 }) 273 274 // Set proposer Permissions 275 proposerActor := types.NewDefaultActor(proposerAddr) 276 err2 := app.CustomGovKeeper.AddWhitelistPermission(ctx, proposerActor, types.PermCreateUpsertTokenAliasProposal) 277 require.NoError(t, err2) 278 279 properties := app.CustomGovKeeper.GetNetworkProperties(ctx) 280 properties.MinimumProposalEndTime = 10 281 app.CustomGovKeeper.SetNetworkProperties(ctx, properties) 282 283 handler := gov.NewHandler(app.CustomGovKeeper) 284 proposal := tokenstypes.NewUpsertTokenAliasProposal( 285 "BTC", 286 "Bitcoin", 287 "http://sdlkfjalsdk.es", 288 18, 289 []string{ 290 "atom", 291 }, 292 false, 293 ) 294 msg, err := govtypes.NewMsgSubmitProposal(proposerAddr, "title", "some desc", proposal) 295 require.NoError(t, err) 296 res, err := handler( 297 ctx, 298 msg, 299 ) 300 require.NoError(t, err) 301 expData, _ := proto.Marshal(&govtypes.MsgSubmitProposalResponse{ProposalID: 1}) 302 require.Equal(t, expData, res.Data) 303 304 savedProposal, found := app.CustomGovKeeper.GetProposal(ctx, 1) 305 require.True(t, found) 306 307 expectedSavedProposal, err := types.NewProposal( 308 1, 309 "title", 310 "some desc", 311 tokenstypes.NewUpsertTokenAliasProposal( 312 "BTC", 313 "Bitcoin", 314 "http://sdlkfjalsdk.es", 315 18, 316 []string{ 317 "atom", 318 }, 319 false, 320 ), 321 ctx.BlockTime(), 322 ctx.BlockTime().Add(time.Second*time.Duration(properties.MinimumProposalEndTime)), 323 ctx.BlockTime().Add(time.Second*time.Duration(properties.MinimumProposalEndTime)+ 324 time.Second*time.Duration(properties.ProposalEnactmentTime), 325 ), 326 ctx.BlockHeight()+2, 327 ctx.BlockHeight()+3, 328 ) 329 require.NoError(t, err) 330 require.Equal(t, expectedSavedProposal, savedProposal) 331 332 // Next proposal ID is increased. 333 id := app.CustomGovKeeper.GetNextProposalID(ctx) 334 require.Equal(t, uint64(2), id) 335 336 // Is not on finished active proposals. 337 iterator := app.CustomGovKeeper.GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx, ctx.BlockTime()) 338 require.False(t, iterator.Valid()) 339 340 ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Minute * 10)) 341 iterator = app.CustomGovKeeper.GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx, ctx.BlockTime()) 342 require.True(t, iterator.Valid()) 343 } 344 345 func TestHandler_CreateProposalUpsertTokenRates_Errors(t *testing.T) { 346 proposerAddr, err := sdk.AccAddressFromBech32("kira1alzyfq40zjsveat87jlg8jxetwqmr0a29sgd0f") 347 require.NoError(t, err) 348 349 tests := []struct { 350 name string 351 content govtypes.Content 352 preparePerms func(t *testing.T, app *simapp.SekaiApp, ctx sdk.Context) 353 expectedErr error 354 }{ 355 { 356 "Proposer does not have Perm", 357 tokenstypes.NewUpsertTokenRatesProposal( 358 "btc", 359 sdk.NewDec(1234), 360 false, 361 sdk.ZeroDec(), 362 sdk.ZeroInt(), 363 false, 364 false, 365 ), 366 func(t *testing.T, app *simapp.SekaiApp, ctx sdk.Context) {}, 367 errors.Wrap(types.ErrNotEnoughPermissions, types.PermCreateUpsertTokenRateProposal.String()), 368 }, 369 } 370 371 for _, tt := range tests { 372 tt := tt 373 t.Run(tt.name, func(t *testing.T) { 374 app := simapp.Setup(false) 375 ctx := app.NewContext(false, tmproto.Header{}) 376 377 tt.preparePerms(t, app, ctx) 378 379 handler := gov.NewHandler(app.CustomGovKeeper) 380 msg, err := govtypes.NewMsgSubmitProposal(proposerAddr, "title", "some desc", tt.content) 381 require.NoError(t, err) 382 _, err = handler(ctx, msg) 383 require.EqualError(t, err, tt.expectedErr.Error()) 384 }) 385 } 386 } 387 388 func TestHandler_CreateProposalUpsertTokenRates(t *testing.T) { 389 proposerAddr, err := sdk.AccAddressFromBech32("kira1alzyfq40zjsveat87jlg8jxetwqmr0a29sgd0f") 390 require.NoError(t, err) 391 392 app := simapp.Setup(false) 393 ctx := app.NewContext(false, tmproto.Header{ 394 Time: time.Now(), 395 }) 396 397 // Set proposer Permissions 398 proposerActor := types.NewDefaultActor(proposerAddr) 399 err2 := app.CustomGovKeeper.AddWhitelistPermission(ctx, proposerActor, types.PermCreateUpsertTokenRateProposal) 400 require.NoError(t, err2) 401 402 properties := app.CustomGovKeeper.GetNetworkProperties(ctx) 403 properties.MinimumProposalEndTime = 10 404 app.CustomGovKeeper.SetNetworkProperties(ctx, properties) 405 406 handler := gov.NewHandler(app.CustomGovKeeper) 407 proposal := tokenstypes.NewUpsertTokenRatesProposal( 408 "btc", 409 sdk.NewDec(1234), 410 false, 411 sdk.ZeroDec(), 412 sdk.ZeroInt(), 413 false, 414 false, 415 ) 416 msg, err := govtypes.NewMsgSubmitProposal(proposerAddr, "title", "some desc", proposal) 417 require.NoError(t, err) 418 res, err := handler( 419 ctx, 420 msg, 421 ) 422 require.NoError(t, err) 423 expData, _ := proto.Marshal(&govtypes.MsgSubmitProposalResponse{ProposalID: 1}) 424 require.Equal(t, expData, res.Data) 425 426 savedProposal, found := app.CustomGovKeeper.GetProposal(ctx, 1) 427 require.True(t, found) 428 429 expectedSavedProposal, err := types.NewProposal( 430 1, 431 "title", 432 "some desc", 433 tokenstypes.NewUpsertTokenRatesProposal( 434 "btc", 435 sdk.NewDec(1234), 436 false, 437 sdk.ZeroDec(), 438 sdk.ZeroInt(), 439 false, 440 false, 441 ), 442 ctx.BlockTime(), 443 ctx.BlockTime().Add(time.Second*time.Duration(properties.MinimumProposalEndTime)), 444 ctx.BlockTime().Add(time.Second*time.Duration(properties.MinimumProposalEndTime)+ 445 time.Second*time.Duration(properties.ProposalEnactmentTime), 446 ), 447 ctx.BlockHeight()+2, 448 ctx.BlockHeight()+3, 449 ) 450 require.NoError(t, err) 451 require.Equal(t, expectedSavedProposal, savedProposal) 452 453 // Next proposal ID is increased. 454 id := app.CustomGovKeeper.GetNextProposalID(ctx) 455 require.Equal(t, uint64(2), id) 456 457 // Is not on finished active proposals. 458 iterator := app.CustomGovKeeper.GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx, ctx.BlockTime()) 459 require.False(t, iterator.Valid()) 460 461 ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Minute * 10)) 462 iterator = app.CustomGovKeeper.GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx, ctx.BlockTime()) 463 require.True(t, iterator.Valid()) 464 } 465 466 func TestHandler_CreateProposalTokensWhiteBlackChange(t *testing.T) { 467 proposerAddr, err := sdk.AccAddressFromBech32("kira1alzyfq40zjsveat87jlg8jxetwqmr0a29sgd0f") 468 require.NoError(t, err) 469 470 app := simapp.Setup(false) 471 ctx := app.NewContext(false, tmproto.Header{ 472 Time: time.Now(), 473 }) 474 475 // Set proposer Permissions 476 proposerActor := types.NewDefaultActor(proposerAddr) 477 err = app.CustomGovKeeper.AddWhitelistPermission(ctx, proposerActor, types.PermCreateTokensWhiteBlackChangeProposal) 478 require.NoError(t, err) 479 480 properties := app.CustomGovKeeper.GetNetworkProperties(ctx) 481 properties.MinimumProposalEndTime = 10 482 app.CustomGovKeeper.SetNetworkProperties(ctx, properties) 483 484 handler := gov.NewHandler(app.CustomGovKeeper) 485 proposal := tokenstypes.NewTokensWhiteBlackChangeProposal( 486 false, 487 true, 488 []string{"atom"}, 489 ) 490 msg, err := govtypes.NewMsgSubmitProposal(proposerAddr, "title", "some desc", proposal) 491 require.NoError(t, err) 492 res, err := handler( 493 ctx, 494 msg, 495 ) 496 require.NoError(t, err) 497 expData, _ := proto.Marshal(&govtypes.MsgSubmitProposalResponse{ProposalID: 1}) 498 require.Equal(t, expData, res.Data) 499 500 savedProposal, found := app.CustomGovKeeper.GetProposal(ctx, 1) 501 require.True(t, found) 502 503 expectedSavedProposal, err := types.NewProposal( 504 1, 505 "title", 506 "some desc", 507 proposal, 508 ctx.BlockTime(), 509 ctx.BlockTime().Add(time.Second*time.Duration(properties.MinimumProposalEndTime)), 510 ctx.BlockTime().Add(time.Second*time.Duration(properties.MinimumProposalEndTime)+ 511 time.Second*time.Duration(properties.ProposalEnactmentTime), 512 ), 513 ctx.BlockHeight()+2, 514 ctx.BlockHeight()+3, 515 ) 516 require.NoError(t, err) 517 require.Equal(t, expectedSavedProposal, savedProposal) 518 519 // Next proposal ID is increased. 520 id := app.CustomGovKeeper.GetNextProposalID(ctx) 521 require.Equal(t, uint64(2), id) 522 523 // Is not on finished active proposals. 524 iterator := app.CustomGovKeeper.GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx, ctx.BlockTime()) 525 require.False(t, iterator.Valid()) 526 527 ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Minute * 10)) 528 iterator = app.CustomGovKeeper.GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx, ctx.BlockTime()) 529 require.True(t, iterator.Valid()) 530 }