code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/transfers_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package sqlstore_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/datanode/entities" 23 "code.vegaprotocol.io/vega/datanode/sqlstore" 24 "code.vegaprotocol.io/vega/libs/ptr" 25 vegapb "code.vegaprotocol.io/vega/protos/vega" 26 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 27 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 ) 31 32 func TestGetTransferByID(t *testing.T) { 33 ctx := tempTransaction(t) 34 35 blocksStore := sqlstore.NewBlocks(connectionSource) 36 assetsStore := sqlstore.NewAssets(connectionSource) 37 accountsStore := sqlstore.NewAccounts(connectionSource) 38 transfersStore := sqlstore.NewTransfers(connectionSource) 39 40 block := addTestBlockForTime(t, ctx, blocksStore, time.Now()) 41 42 asset := CreateAsset(t, ctx, assetsStore, block) 43 44 account1 := CreateAccount(t, ctx, accountsStore, block, 45 AccountForAsset(asset), 46 ) 47 account2 := CreateAccount(t, ctx, accountsStore, block, 48 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 49 AccountForAsset(asset), 50 ) 51 52 transfer := NewTransfer(t, ctx, accountsStore, block, 53 TransferWithAsset(asset), 54 TransferFromToAccounts(account1, account2), 55 TransferAsRecurring(&eventspb.RecurringTransfer{ 56 StartEpoch: 10, 57 EndEpoch: nil, 58 Factor: "0.1", 59 }), 60 ) 61 62 transferUpdateFromSameTx := NewTransfer(t, ctx, accountsStore, block, 63 TransferWithID(transfer.ID), 64 TransferWithAsset(asset), 65 TransferFromToAccounts(account1, account2), 66 TransferAsRecurring(&eventspb.RecurringTransfer{ 67 StartEpoch: 15, 68 EndEpoch: nil, 69 Factor: "0.15", 70 }), 71 ) 72 transferUpdateFromSameTx.TxHash = transfer.TxHash 73 74 transferUpdateFromDifferentTx := NewTransfer(t, ctx, accountsStore, block, 75 TransferWithID(transfer.ID), 76 TransferWithAsset(asset), 77 TransferFromToAccounts(account1, account2), 78 TransferAsRecurring(&eventspb.RecurringTransfer{ 79 StartEpoch: 20, 80 EndEpoch: ptr.From(uint64(25)), 81 Factor: "0.2", 82 }), 83 ) 84 85 // Ensure we have different transfers so the test is meaningful. 86 RequireAllDifferent(t, transfer, transferUpdateFromSameTx, transferUpdateFromDifferentTx) 87 88 t.Run("Save transfers", func(t *testing.T) { 89 require.NoError(t, transfersStore.Upsert(ctx, transfer)) 90 require.NoError(t, transfersStore.Upsert(ctx, transferUpdateFromSameTx)) 91 require.NoError(t, transfersStore.Upsert(ctx, transferUpdateFromDifferentTx)) 92 }) 93 94 t.Run("Retrieve the transfer by ID returns the latest version", func(t *testing.T) { 95 retrieved, err := transfersStore.GetByID(ctx, transfer.ID.String()) 96 require.NoError(t, err) 97 assert.Equal(t, *transferUpdateFromDifferentTx, retrieved.Transfer) 98 }) 99 } 100 101 func TestGetTransfersByHash(t *testing.T) { 102 ctx := tempTransaction(t) 103 104 blocksStore := sqlstore.NewBlocks(connectionSource) 105 assetsStore := sqlstore.NewAssets(connectionSource) 106 accountsStore := sqlstore.NewAccounts(connectionSource) 107 transfersStore := sqlstore.NewTransfers(connectionSource) 108 109 block1 := addTestBlockForTime(t, ctx, blocksStore, time.Now().Add(-2*time.Minute)) 110 block2 := addTestBlockForTime(t, ctx, blocksStore, time.Now().Add(-1*time.Minute)) 111 112 asset := CreateAsset(t, ctx, assetsStore, block1) 113 114 account1 := CreateAccount(t, ctx, accountsStore, block1, 115 AccountForAsset(asset), 116 ) 117 account2 := CreateAccount(t, ctx, accountsStore, block1, 118 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 119 AccountForAsset(asset), 120 ) 121 122 transfer1 := NewTransfer(t, ctx, accountsStore, block1, 123 TransferWithAsset(asset), 124 TransferFromToAccounts(account1, account2), 125 TransferAsRecurring(&eventspb.RecurringTransfer{ 126 StartEpoch: 10, 127 EndEpoch: nil, 128 Factor: "0.1", 129 }), 130 ) 131 132 transfer2 := NewTransfer(t, ctx, accountsStore, block1, 133 TransferWithAsset(asset), 134 TransferFromToAccounts(account1, account2), 135 TransferAsRecurring(&eventspb.RecurringTransfer{ 136 StartEpoch: 10, 137 EndEpoch: nil, 138 Factor: "0.1", 139 }), 140 ) 141 transfer2.TxHash = transfer1.TxHash 142 143 transfer1UpdateFromSameTx := NewTransfer(t, ctx, accountsStore, block1, 144 TransferWithID(transfer1.ID), 145 TransferWithAsset(asset), 146 TransferFromToAccounts(account1, account2), 147 TransferAsRecurring(&eventspb.RecurringTransfer{ 148 StartEpoch: 15, 149 EndEpoch: nil, 150 Factor: "0.15", 151 }), 152 ) 153 transfer1UpdateFromSameTx.TxHash = transfer1.TxHash 154 155 transfer1UpdateFromDifferentTx := NewTransfer(t, ctx, accountsStore, block2, 156 TransferWithID(transfer1.ID), 157 TransferWithAsset(asset), 158 TransferFromToAccounts(account1, account2), 159 TransferAsRecurring(&eventspb.RecurringTransfer{ 160 StartEpoch: 20, 161 EndEpoch: ptr.From(uint64(25)), 162 Factor: "0.2", 163 }), 164 ) 165 166 // Ensure we have different transfers so the test is meaningful. 167 RequireAllDifferent(t, transfer1, transfer2, transfer1UpdateFromSameTx, transfer1UpdateFromDifferentTx) 168 169 t.Run("Save transfers", func(t *testing.T) { 170 require.NoError(t, transfersStore.Upsert(ctx, transfer1)) 171 require.NoError(t, transfersStore.Upsert(ctx, transfer2)) 172 require.NoError(t, transfersStore.Upsert(ctx, transfer1UpdateFromSameTx)) 173 require.NoError(t, transfersStore.Upsert(ctx, transfer1UpdateFromDifferentTx)) 174 }) 175 176 t.Run("Retrieve the transfer by hash returns all matching the hash", func(t *testing.T) { 177 retrieved, err := transfersStore.GetByTxHash(ctx, transfer1.TxHash) 178 require.NoError(t, err) 179 assert.ElementsMatch(t, 180 []entities.Transfer{*transfer2, *transfer1UpdateFromSameTx}, 181 retrieved, 182 ) 183 }) 184 } 185 186 func TestGetTransfersToOrFromParty(t *testing.T) { 187 ctx := tempTransaction(t) 188 189 blocksStore := sqlstore.NewBlocks(connectionSource) 190 assetsStore := sqlstore.NewAssets(connectionSource) 191 accountsStore := sqlstore.NewAccounts(connectionSource) 192 transfersStore := sqlstore.NewTransfers(connectionSource) 193 194 block := addTestBlockForTime(t, ctx, blocksStore, time.Now()) 195 196 asset := CreateAsset(t, ctx, assetsStore, block) 197 198 account1 := CreateAccount(t, ctx, accountsStore, block, 199 AccountForAsset(asset), 200 ) 201 account2 := CreateAccount(t, ctx, accountsStore, block, 202 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 203 AccountForAsset(asset), 204 ) 205 account3 := CreateAccount(t, ctx, accountsStore, block, 206 AccountForAsset(asset), 207 ) 208 209 transfer1 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 210 TransferWithAsset(asset), 211 TransferFromToAccounts(account2, account1), 212 TransferAsRecurring(&eventspb.RecurringTransfer{ 213 StartEpoch: 5, 214 EndEpoch: ptr.From(uint64(15)), 215 Factor: "0.1", 216 DispatchStrategy: &vegapb.DispatchStrategy{ 217 AssetForMetric: "deadd0d0", 218 Markets: []string{"beefdead", "feebaad"}, 219 Metric: vegapb.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 220 }, 221 }), 222 ) 223 transfer2 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 224 TransferWithAsset(asset), 225 TransferFromToAccounts(account1, account2), 226 TransferAsRecurring(&eventspb.RecurringTransfer{ 227 StartEpoch: 10, 228 EndEpoch: ptr.From(uint64(20)), 229 Factor: "0.1", 230 }), 231 ) 232 transfer3 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 233 TransferWithAsset(asset), 234 TransferFromToAccounts(account1, account3), 235 TransferAsRecurring(&eventspb.RecurringTransfer{ 236 StartEpoch: 25, 237 EndEpoch: nil, 238 Factor: "0.1", 239 }), 240 ) 241 transfer4 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 242 TransferWithAsset(asset), 243 TransferFromToAccounts(account3, account2), 244 TransferAsRecurring(&eventspb.RecurringTransfer{ 245 StartEpoch: 15, 246 EndEpoch: ptr.From(uint64(20)), 247 Factor: "0.1", 248 }), 249 ) 250 251 t.Run("Retrieve all transfers from/to party", func(t *testing.T) { 252 retrieved, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), sqlstore.ListTransfersFilters{}, account2.PartyID) 253 require.NoError(t, err) 254 assert.ElementsMatch(t, 255 []entities.Transfer{*transfer1, *transfer2, *transfer4}, 256 TransferDetailsAsTransfers(t, retrieved), 257 ) 258 }) 259 260 t.Run("Retrieve transfers from/to party with epoch range", func(t *testing.T) { 261 filters := sqlstore.ListTransfersFilters{ 262 FromEpoch: ptr.From(uint64(16)), 263 ToEpoch: ptr.From(uint64(20)), 264 } 265 266 retrievedFromAccount1, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 267 require.NoError(t, err) 268 assert.ElementsMatch(t, 269 []entities.Transfer{*transfer2}, 270 TransferDetailsAsTransfers(t, retrievedFromAccount1), 271 ) 272 273 retrievedFromAccount3, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account3.PartyID) 274 require.NoError(t, err) 275 assert.ElementsMatch(t, 276 []entities.Transfer{*transfer4}, 277 TransferDetailsAsTransfers(t, retrievedFromAccount3), 278 ) 279 }) 280 281 t.Run("Retrieve transfers from/to party from epoch", func(t *testing.T) { 282 filters := sqlstore.ListTransfersFilters{ 283 FromEpoch: ptr.From(uint64(20)), 284 } 285 286 retrievedFromAccount1, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 287 require.NoError(t, err) 288 assert.ElementsMatch(t, 289 []entities.Transfer{*transfer2, *transfer3}, 290 TransferDetailsAsTransfers(t, retrievedFromAccount1), 291 ) 292 293 retrievedFromAccount3, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account3.PartyID) 294 require.NoError(t, err) 295 assert.ElementsMatch(t, 296 []entities.Transfer{*transfer3, *transfer4}, 297 TransferDetailsAsTransfers(t, retrievedFromAccount3), 298 ) 299 }) 300 301 t.Run("Retrieve transfers from/to party to epoch", func(t *testing.T) { 302 filters := sqlstore.ListTransfersFilters{ 303 ToEpoch: ptr.From(uint64(10)), 304 } 305 306 retrievedFromAccount1, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 307 require.NoError(t, err) 308 assert.ElementsMatch(t, 309 []entities.Transfer{*transfer1, *transfer2}, 310 TransferDetailsAsTransfers(t, retrievedFromAccount1), 311 ) 312 313 retrievedFromAccount3, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account3.PartyID) 314 require.NoError(t, err) 315 assert.Empty(t, retrievedFromAccount3) 316 }) 317 318 t.Run("Retrieve transfers from/to party by from account type", func(t *testing.T) { 319 filters := sqlstore.ListTransfersFilters{ 320 FromAccountType: ptr.From(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 321 } 322 323 retrieved, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account2.PartyID) 324 require.NoError(t, err) 325 assert.ElementsMatch(t, 326 []entities.Transfer{*transfer1}, 327 TransferDetailsAsTransfers(t, retrieved), 328 ) 329 }) 330 331 t.Run("Retrieve transfers from/to party by to account type", func(t *testing.T) { 332 filters := sqlstore.ListTransfersFilters{ 333 ToAccountType: ptr.From(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 334 } 335 336 retrieved, _, err := transfersStore.GetTransfersToOrFromParty(ctx, entities.DefaultCursorPagination(true), filters, account2.PartyID) 337 require.NoError(t, err) 338 assert.ElementsMatch(t, 339 []entities.Transfer{*transfer2, *transfer4}, 340 TransferDetailsAsTransfers(t, retrieved), 341 ) 342 }) 343 } 344 345 func TestGetTransfersByParty(t *testing.T) { 346 ctx := tempTransaction(t) 347 348 blocksStore := sqlstore.NewBlocks(connectionSource) 349 assetsStore := sqlstore.NewAssets(connectionSource) 350 accountsStore := sqlstore.NewAccounts(connectionSource) 351 transfersStore := sqlstore.NewTransfers(connectionSource) 352 353 block := addTestBlockForTime(t, ctx, blocksStore, time.Now()) 354 355 asset := CreateAsset(t, ctx, assetsStore, block) 356 357 account1 := CreateAccount(t, ctx, accountsStore, block, 358 AccountForAsset(asset), 359 ) 360 account2 := CreateAccount(t, ctx, accountsStore, block, 361 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 362 AccountForAsset(asset), 363 ) 364 365 transfer1 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 366 TransferWithAsset(asset), 367 TransferFromToAccounts(account1, account2), 368 TransferAsRecurring(&eventspb.RecurringTransfer{ 369 StartEpoch: 5, 370 EndEpoch: ptr.From(uint64(15)), 371 Factor: "0.1", 372 }), 373 ) 374 transfer2 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 375 TransferWithAsset(asset), 376 TransferFromToAccounts(account2, account1), 377 TransferAsRecurring(&eventspb.RecurringTransfer{ 378 StartEpoch: 10, 379 EndEpoch: ptr.From(uint64(17)), 380 Factor: "0.1", 381 }), 382 ) 383 transfer3 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 384 TransferWithAsset(asset), 385 TransferFromToAccounts(account2, account1), 386 TransferAsRecurring(&eventspb.RecurringTransfer{ 387 StartEpoch: 15, 388 EndEpoch: ptr.From(uint64(20)), 389 Factor: "0.1", 390 }), 391 ) 392 transfer4 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 393 TransferWithAsset(asset), 394 TransferFromToAccounts(account1, account2), 395 TransferAsRecurring(&eventspb.RecurringTransfer{ 396 StartEpoch: 15, 397 EndEpoch: ptr.From(uint64(20)), 398 Factor: "0.1", 399 }), 400 ) 401 402 t.Run("Retrieve transfers from party", func(t *testing.T) { 403 retrieved, _, err := transfersStore.GetTransfersFromParty(ctx, entities.DefaultCursorPagination(true), sqlstore.ListTransfersFilters{}, account1.PartyID) 404 405 require.NoError(t, err) 406 assert.ElementsMatch(t, 407 []entities.Transfer{*transfer1, *transfer4}, 408 TransferDetailsAsTransfers(t, retrieved), 409 ) 410 }) 411 412 t.Run("Retrieve transfers from party with epoch range", func(t *testing.T) { 413 filters := sqlstore.ListTransfersFilters{ 414 FromEpoch: ptr.From(uint64(5)), 415 ToEpoch: ptr.From(uint64(10)), 416 } 417 418 retrieved, _, err := transfersStore.GetTransfersFromParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 419 420 require.NoError(t, err) 421 assert.ElementsMatch(t, 422 []entities.Transfer{*transfer1}, 423 TransferDetailsAsTransfers(t, retrieved), 424 ) 425 }) 426 427 t.Run("Retrieve transfers from party from epoch", func(t *testing.T) { 428 filters := sqlstore.ListTransfersFilters{ 429 FromEpoch: ptr.From(uint64(17)), 430 } 431 432 retrieved, _, err := transfersStore.GetTransfersFromParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 433 require.NoError(t, err) 434 435 assert.ElementsMatch(t, 436 []entities.Transfer{*transfer4}, 437 TransferDetailsAsTransfers(t, retrieved), 438 ) 439 }) 440 441 t.Run("Retrieve transfers from party to epoch", func(t *testing.T) { 442 filters := sqlstore.ListTransfersFilters{ 443 ToEpoch: ptr.From(uint64(13)), 444 } 445 446 retrieved, _, err := transfersStore.GetTransfersFromParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 447 require.NoError(t, err) 448 449 assert.ElementsMatch(t, 450 []entities.Transfer{*transfer1}, 451 TransferDetailsAsTransfers(t, retrieved), 452 ) 453 }) 454 455 t.Run("Retrieve transfers to party", func(t *testing.T) { 456 retrieved, _, err := transfersStore.GetTransfersToParty(ctx, entities.DefaultCursorPagination(true), sqlstore.ListTransfersFilters{}, account1.PartyID) 457 458 require.NoError(t, err) 459 assert.ElementsMatch(t, 460 []entities.Transfer{*transfer2, *transfer3}, 461 TransferDetailsAsTransfers(t, retrieved), 462 ) 463 }) 464 465 t.Run("Retrieve transfers to party with epoch range", func(t *testing.T) { 466 filters := sqlstore.ListTransfersFilters{ 467 FromEpoch: ptr.From(uint64(5)), 468 ToEpoch: ptr.From(uint64(10)), 469 } 470 471 retrieved, _, err := transfersStore.GetTransfersToParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 472 473 require.NoError(t, err) 474 assert.ElementsMatch(t, 475 []entities.Transfer{*transfer2}, 476 TransferDetailsAsTransfers(t, retrieved), 477 ) 478 }) 479 480 t.Run("Retrieve transfers to party from epoch", func(t *testing.T) { 481 filters := sqlstore.ListTransfersFilters{ 482 FromEpoch: ptr.From(uint64(18)), 483 } 484 485 retrieved, _, err := transfersStore.GetTransfersToParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 486 require.NoError(t, err) 487 488 assert.ElementsMatch(t, 489 []entities.Transfer{*transfer3}, 490 TransferDetailsAsTransfers(t, retrieved), 491 ) 492 }) 493 494 t.Run("Retrieve transfers to party to epoch", func(t *testing.T) { 495 filters := sqlstore.ListTransfersFilters{ 496 ToEpoch: ptr.From(uint64(13)), 497 } 498 499 retrieved, _, err := transfersStore.GetTransfersToParty(ctx, entities.DefaultCursorPagination(true), filters, account1.PartyID) 500 require.NoError(t, err) 501 502 assert.ElementsMatch(t, 503 []entities.Transfer{*transfer2}, 504 TransferDetailsAsTransfers(t, retrieved), 505 ) 506 }) 507 508 t.Run("Retrieve transfers from party by from account type", func(t *testing.T) { 509 filters := sqlstore.ListTransfersFilters{ 510 FromAccountType: ptr.From(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 511 } 512 513 retrieved, _, err := transfersStore.GetTransfersFromParty(ctx, entities.DefaultCursorPagination(true), filters, account2.PartyID) 514 require.NoError(t, err) 515 516 assert.ElementsMatch(t, 517 []entities.Transfer{*transfer2, *transfer3}, 518 TransferDetailsAsTransfers(t, retrieved), 519 ) 520 }) 521 t.Run("Retrieve transfers to party by from account type", func(t *testing.T) { 522 filters := sqlstore.ListTransfersFilters{ 523 ToAccountType: ptr.From(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 524 } 525 526 retrieved, _, err := transfersStore.GetTransfersToParty(ctx, entities.DefaultCursorPagination(true), filters, account2.PartyID) 527 require.NoError(t, err) 528 529 assert.ElementsMatch(t, 530 []entities.Transfer{*transfer1, *transfer4}, 531 TransferDetailsAsTransfers(t, retrieved), 532 ) 533 }) 534 } 535 536 func TestGetAllTransfers(t *testing.T) { 537 ctx := tempTransaction(t) 538 539 blocksStore := sqlstore.NewBlocks(connectionSource) 540 assetsStore := sqlstore.NewAssets(connectionSource) 541 accountsStore := sqlstore.NewAccounts(connectionSource) 542 transfersStore := sqlstore.NewTransfers(connectionSource) 543 544 block := addTestBlockForTime(t, ctx, blocksStore, time.Now()) 545 546 asset := CreateAsset(t, ctx, assetsStore, block) 547 548 account1 := CreateAccount(t, ctx, accountsStore, block, 549 AccountForAsset(asset), 550 ) 551 account2 := CreateAccount(t, ctx, accountsStore, block, 552 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 553 AccountForAsset(asset), 554 ) 555 account3 := CreateAccount(t, ctx, accountsStore, block, 556 AccountForAsset(asset), 557 ) 558 559 transfer1 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 560 TransferWithAsset(asset), 561 TransferFromToAccounts(account2, account1), 562 TransferAsRecurring(&eventspb.RecurringTransfer{ 563 StartEpoch: 5, 564 EndEpoch: ptr.From(uint64(15)), 565 Factor: "0.1", 566 DispatchStrategy: &vegapb.DispatchStrategy{ 567 AssetForMetric: "deadd0d0", 568 Metric: vegapb.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 569 Markets: []string{"beefdead", "feebaad"}, 570 IndividualScope: vegapb.IndividualScope_INDIVIDUAL_SCOPE_IN_TEAM, 571 }, 572 }), 573 ) 574 transfer2 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 575 TransferWithAsset(asset), 576 TransferFromToAccounts(account1, account2), 577 TransferWithStatus(entities.TransferStatusDone), 578 TransferAsRecurring(&eventspb.RecurringTransfer{ 579 StartEpoch: 10, 580 EndEpoch: ptr.From(uint64(20)), 581 Factor: "0.1", 582 }), 583 ) 584 transfer3 := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 585 TransferWithAsset(asset), 586 TransferFromToAccounts(account1, account3), 587 TransferWithStatus(entities.TransferStatusCancelled), 588 TransferAsRecurring(&eventspb.RecurringTransfer{ 589 StartEpoch: 25, 590 EndEpoch: nil, 591 Factor: "0.1", 592 DispatchStrategy: &vegapb.DispatchStrategy{ 593 TeamScope: []string{ 594 "beefdeadfeebaad", 595 }, 596 }, 597 }), 598 TransferWithGameID(ptr.From("c001d00d")), 599 ) 600 601 t.Run("Retrieve all transfers", func(t *testing.T) { 602 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), sqlstore.ListTransfersFilters{}) 603 require.NoError(t, err) 604 assert.ElementsMatch(t, 605 []entities.Transfer{*transfer1, *transfer2, *transfer3}, 606 TransferDetailsAsTransfers(t, retrieved), 607 ) 608 }) 609 610 t.Run("Retrieve transfers with epoch range", func(t *testing.T) { 611 filters := sqlstore.ListTransfersFilters{ 612 FromEpoch: ptr.From(uint64(16)), 613 ToEpoch: ptr.From(uint64(28)), 614 } 615 616 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 617 require.NoError(t, err) 618 619 assert.ElementsMatch(t, 620 []entities.Transfer{*transfer2, *transfer3}, 621 TransferDetailsAsTransfers(t, retrieved), 622 ) 623 }) 624 625 t.Run("Retrieve all transfers from epoch", func(t *testing.T) { 626 filters := sqlstore.ListTransfersFilters{ 627 FromEpoch: ptr.From(uint64(20)), 628 } 629 630 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 631 require.NoError(t, err) 632 633 assert.ElementsMatch(t, 634 []entities.Transfer{*transfer2, *transfer3}, 635 TransferDetailsAsTransfers(t, retrieved), 636 ) 637 }) 638 639 t.Run("Retrieve transfers to epoch", func(t *testing.T) { 640 filters := sqlstore.ListTransfersFilters{ 641 ToEpoch: ptr.From(uint64(10)), 642 } 643 644 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 645 require.NoError(t, err) 646 647 assert.ElementsMatch(t, 648 []entities.Transfer{*transfer1, *transfer2}, 649 TransferDetailsAsTransfers(t, retrieved), 650 ) 651 }) 652 653 t.Run("Retrieve transfers by status", func(t *testing.T) { 654 matrix := map[entities.TransferStatus][]entities.Transfer{ 655 entities.TransferStatusPending: {*transfer1}, 656 entities.TransferStatusCancelled: {*transfer3}, 657 entities.TransferStatusRejected: {}, 658 } 659 660 for status, expected := range matrix { 661 filters := sqlstore.ListTransfersFilters{ 662 Status: ptr.From(status), 663 } 664 665 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 666 require.NoError(t, err) 667 assert.Equal(t, expected, TransferDetailsAsTransfers(t, retrieved)) 668 } 669 }) 670 671 t.Run("Retrieve transfers by scope", func(t *testing.T) { 672 matrix := map[entities.TransferScope][]entities.Transfer{ 673 entities.TransferScopeIndividual: {*transfer1}, 674 entities.TransferScopeTeam: {*transfer3}, 675 } 676 677 for scope, expected := range matrix { 678 filters := sqlstore.ListTransfersFilters{ 679 Scope: ptr.From(scope), 680 } 681 682 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 683 require.NoError(t, err) 684 assert.Equal(t, expected, TransferDetailsAsTransfers(t, retrieved)) 685 } 686 }) 687 688 t.Run("Retrieve transfers by game ID", func(t *testing.T) { 689 filters := sqlstore.ListTransfersFilters{ 690 GameID: ptr.From(entities.GameID("c001d00d")), 691 } 692 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 693 require.NoError(t, err) 694 assert.Equal(t, []entities.Transfer{*transfer3}, TransferDetailsAsTransfers(t, retrieved)) 695 }) 696 697 t.Run("Retrieve transfers by From account type", func(t *testing.T) { 698 filters := sqlstore.ListTransfersFilters{ 699 FromAccountType: ptr.From(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 700 } 701 702 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 703 require.NoError(t, err) 704 assert.Equal(t, []entities.Transfer{*transfer1}, TransferDetailsAsTransfers(t, retrieved)) 705 }) 706 707 t.Run("Retrieve transfers by To account type", func(t *testing.T) { 708 filters := sqlstore.ListTransfersFilters{ 709 ToAccountType: ptr.From(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 710 } 711 712 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(true), filters) 713 require.NoError(t, err) 714 assert.Equal(t, []entities.Transfer{*transfer2}, TransferDetailsAsTransfers(t, retrieved)) 715 }) 716 } 717 718 func TestGetAllTransfersWithPagination(t *testing.T) { 719 ctx := tempTransaction(t) 720 721 blocksStore := sqlstore.NewBlocks(connectionSource) 722 assetsStore := sqlstore.NewAssets(connectionSource) 723 accountsStore := sqlstore.NewAccounts(connectionSource) 724 transfersStore := sqlstore.NewTransfers(connectionSource) 725 726 block := addTestBlockForTime(t, ctx, blocksStore, time.Now()) 727 728 asset := CreateAsset(t, ctx, assetsStore, block) 729 730 account1 := CreateAccount(t, ctx, accountsStore, block, 731 AccountForAsset(asset), 732 ) 733 account2 := CreateAccount(t, ctx, accountsStore, block, 734 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 735 AccountForAsset(asset), 736 ) 737 738 transfers := make([]entities.Transfer, 0, 10) 739 for i := 0; i < 10; i++ { 740 block := addTestBlockForTime(t, ctx, blocksStore, time.Now().Add(time.Duration(i)*time.Second)) 741 transfer := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 742 TransferWithAsset(asset), 743 TransferFromToAccounts(account1, account2), 744 TransferAsRecurring(&eventspb.RecurringTransfer{ 745 StartEpoch: 5, 746 EndEpoch: ptr.From(uint64(15)), 747 Factor: "0.1", 748 }), 749 ) 750 transfers = append(transfers, *transfer) 751 } 752 753 noFilters := sqlstore.ListTransfersFilters{} 754 755 t.Run("Paginate with oldest first", func(t *testing.T) { 756 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false) 757 require.NoError(t, err) 758 759 retrieved, pageInfo, err := transfersStore.GetAll(ctx, pagination, noFilters) 760 require.NoError(t, err) 761 assert.Equal(t, transfers, TransferDetailsAsTransfers(t, retrieved)) 762 assert.Equal(t, entities.PageInfo{ 763 HasNextPage: false, 764 HasPreviousPage: false, 765 StartCursor: transfers[0].Cursor().Encode(), 766 EndCursor: transfers[9].Cursor().Encode(), 767 }, pageInfo) 768 }) 769 770 t.Run("Paginate first 3 transfers", func(t *testing.T) { 771 first := int32(3) 772 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 773 require.NoError(t, err) 774 775 retrieved, pageInfo, err := transfersStore.GetAll(ctx, pagination, noFilters) 776 require.NoError(t, err) 777 assert.Equal(t, transfers[:3], TransferDetailsAsTransfers(t, retrieved)) 778 assert.Equal(t, entities.PageInfo{ 779 HasNextPage: true, 780 HasPreviousPage: false, 781 StartCursor: transfers[0].Cursor().Encode(), 782 EndCursor: transfers[2].Cursor().Encode(), 783 }, pageInfo) 784 }) 785 786 t.Run("Paginate last 3 transfers", func(t *testing.T) { 787 last := int32(3) 788 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 789 require.NoError(t, err) 790 791 retrieved, pageInfo, err := transfersStore.GetAll(ctx, pagination, noFilters) 792 require.NoError(t, err) 793 assert.Equal(t, transfers[7:], TransferDetailsAsTransfers(t, retrieved)) 794 assert.Equal(t, entities.PageInfo{ 795 HasNextPage: false, 796 HasPreviousPage: true, 797 StartCursor: transfers[7].Cursor().Encode(), 798 EndCursor: transfers[9].Cursor().Encode(), 799 }, pageInfo) 800 }) 801 802 t.Run("Paginate first 3 transfers after third one", func(t *testing.T) { 803 first := int32(3) 804 after := transfers[2].Cursor().Encode() 805 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 806 require.NoError(t, err) 807 808 retrieved, pageInfo, err := transfersStore.GetAll(ctx, pagination, noFilters) 809 require.NoError(t, err) 810 assert.Equal(t, transfers[3:6], TransferDetailsAsTransfers(t, retrieved)) 811 assert.Equal(t, entities.PageInfo{ 812 HasNextPage: true, 813 HasPreviousPage: true, 814 StartCursor: transfers[3].Cursor().Encode(), 815 EndCursor: transfers[5].Cursor().Encode(), 816 }, pageInfo) 817 }) 818 819 t.Run("Paginate last 3 transfers before seventh one", func(t *testing.T) { 820 last := int32(3) 821 before := transfers[7].Cursor().Encode() 822 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 823 require.NoError(t, err) 824 825 retrieved, pageInfo, err := transfersStore.GetAll(ctx, pagination, noFilters) 826 require.NoError(t, err) 827 assert.Equal(t, transfers[4:7], TransferDetailsAsTransfers(t, retrieved)) 828 assert.Equal(t, entities.PageInfo{ 829 HasNextPage: true, 830 HasPreviousPage: true, 831 StartCursor: transfers[4].Cursor().Encode(), 832 EndCursor: transfers[6].Cursor().Encode(), 833 }, pageInfo) 834 }) 835 } 836 837 func TestGetAllRewardTransfers(t *testing.T) { 838 ctx := tempTransaction(t) 839 840 blocksStore := sqlstore.NewBlocks(connectionSource) 841 assetsStore := sqlstore.NewAssets(connectionSource) 842 accountsStore := sqlstore.NewAccounts(connectionSource) 843 transfersStore := sqlstore.NewTransfers(connectionSource) 844 845 vegaTime := time.Now().Truncate(time.Microsecond) 846 847 block := addTestBlockForTime(t, ctx, blocksStore, vegaTime) 848 849 asset := CreateAsset(t, ctx, assetsStore, block) 850 851 account1 := CreateAccount(t, ctx, accountsStore, block, 852 AccountForAsset(asset), 853 ) 854 account2 := CreateAccount(t, ctx, accountsStore, block, 855 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 856 AccountForAsset(asset), 857 ) 858 859 allTransfers := make([]entities.Transfer, 0, 20) 860 for i := 0; i < 10; i++ { 861 vegaTime = vegaTime.Add(time.Second) 862 block := addTestBlockForTime(t, ctx, blocksStore, vegaTime) 863 864 transfer := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 865 TransferWithAsset(asset), 866 TransferFromToAccounts(account1, account2), 867 TransferAsOneOff(eventspb.OneOffTransfer{ 868 DeliverOn: vegaTime.UnixNano(), 869 }), 870 ) 871 allTransfers = append(allTransfers, *transfer) 872 } 873 874 rewardTransfers := make([]entities.Transfer, 0, 10) 875 for i := 0; i < 10; i++ { 876 vegaTime = vegaTime.Add(time.Second) 877 block := addTestBlockForTime(t, ctx, blocksStore, vegaTime) 878 879 var kindOption TransferOption 880 var statusOption TransferOption 881 if i%2 == 0 { 882 kindOption = TransferAsRecurringGovernance(eventspb.RecurringGovernanceTransfer{ 883 StartEpoch: 15, 884 EndEpoch: nil, 885 DispatchStrategy: &vegapb.DispatchStrategy{ 886 Metric: vegapb.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 887 LockPeriod: uint64((i % 7) + 1), 888 IndividualScope: vegapb.IndividualScope_INDIVIDUAL_SCOPE_ALL, 889 }, 890 }) 891 statusOption = TransferWithStatus(entities.TransferStatusDone) 892 } else { 893 kindOption = TransferAsRecurring(&eventspb.RecurringTransfer{ 894 StartEpoch: 15, 895 EndEpoch: nil, 896 Factor: "0.15", 897 DispatchStrategy: &vegapb.DispatchStrategy{ 898 Metric: vegapb.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 899 LockPeriod: uint64((i % 7) + 1), 900 TeamScope: []string{"deadfbeefc0ffeed00d"}, 901 }, 902 }) 903 904 statusOption = TransferWithStatus(entities.TransferStatusPending) 905 } 906 907 transfer := CreateTransfer(t, ctx, transfersStore, accountsStore, block, 908 TransferWithAsset(asset), 909 TransferFromToAccounts(account1, account2), 910 kindOption, 911 statusOption, 912 ) 913 rewardTransfers = append(rewardTransfers, *transfer) 914 allTransfers = append(allTransfers, *transfer) 915 } 916 917 noFilters := sqlstore.ListTransfersFilters{} 918 919 t.Run("Get all transfers", func(t *testing.T) { 920 retrieved, _, err := transfersStore.GetAll(ctx, entities.DefaultCursorPagination(false), noFilters) 921 require.NoError(t, err) 922 assert.Equal(t, allTransfers, TransferDetailsAsTransfers(t, retrieved)) 923 }) 924 925 t.Run("Get only reward transfers", func(t *testing.T) { 926 retrieved, _, err := transfersStore.GetAllRewards(ctx, entities.DefaultCursorPagination(false), noFilters) 927 require.NoError(t, err) 928 assert.Equal(t, rewardTransfers, TransferDetailsAsTransfers(t, retrieved)) 929 }) 930 931 t.Run("Retrieve transfers by status pending", func(t *testing.T) { 932 filters := sqlstore.ListTransfersFilters{ 933 Status: ptr.From(entities.TransferStatusDone), 934 } 935 936 retrieved, _, err := transfersStore.GetAllRewards(ctx, entities.DefaultCursorPagination(false), filters) 937 require.NoError(t, err) 938 assert.Equal(t, 939 []entities.Transfer{rewardTransfers[0], rewardTransfers[2], rewardTransfers[4], rewardTransfers[6], rewardTransfers[8]}, 940 TransferDetailsAsTransfers(t, retrieved)) 941 }) 942 943 t.Run("Retrieve transfers by scope", func(t *testing.T) { 944 matrix := map[entities.TransferScope][]entities.Transfer{ 945 entities.TransferScopeIndividual: {rewardTransfers[0], rewardTransfers[2], rewardTransfers[4], rewardTransfers[6], rewardTransfers[8]}, 946 entities.TransferScopeTeam: {rewardTransfers[1], rewardTransfers[3], rewardTransfers[5], rewardTransfers[7], rewardTransfers[9]}, 947 } 948 949 for scope, expected := range matrix { 950 filters := sqlstore.ListTransfersFilters{ 951 Scope: ptr.From(scope), 952 } 953 954 retrieved, _, err := transfersStore.GetAllRewards(ctx, entities.DefaultCursorPagination(false), filters) 955 require.NoError(t, err) 956 assert.Equal(t, expected, TransferDetailsAsTransfers(t, retrieved)) 957 } 958 }) 959 } 960 961 func TestTransferTypeEnums(t *testing.T) { 962 t.Run("Should be able to save and retrieve transfers with all states", testTransferStateEnum) 963 } 964 965 func testTransferStateEnum(t *testing.T) { 966 var transferStatus eventspb.Transfer_Status 967 states := getEnums(t, transferStatus) 968 assert.Len(t, states, 6) 969 for s, state := range states { 970 t.Run(state, func(t *testing.T) { 971 ctx := tempTransaction(t) 972 973 blocksStore := sqlstore.NewBlocks(connectionSource) 974 assetsStore := sqlstore.NewAssets(connectionSource) 975 accountsStore := sqlstore.NewAccounts(connectionSource) 976 transfersStore := sqlstore.NewTransfers(connectionSource) 977 978 block := addTestBlockForTime(t, ctx, blocksStore, time.Now()) 979 980 asset := CreateAsset(t, ctx, assetsStore, block) 981 982 account1 := CreateAccount(t, ctx, accountsStore, block, 983 AccountForAsset(asset), 984 ) 985 account2 := CreateAccount(t, ctx, accountsStore, block, 986 AccountWithType(vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD), 987 AccountForAsset(asset), 988 ) 989 990 transfer := NewTransfer(t, ctx, accountsStore, block, 991 TransferWithAsset(asset), 992 TransferFromToAccounts(account1, account2), 993 TransferAsRecurring(&eventspb.RecurringTransfer{ 994 StartEpoch: 10, 995 EndEpoch: nil, 996 Factor: "0.1", 997 }), 998 TransferWithStatus(entities.TransferStatus(s)), 999 ) 1000 1001 require.NoError(t, transfersStore.Upsert(ctx, transfer)) 1002 retrieved, err := transfersStore.GetByID(ctx, transfer.ID.String()) 1003 require.NoError(t, err) 1004 assert.Equal(t, transfer.Status, retrieved.Status) 1005 }) 1006 } 1007 }