code.vegaprotocol.io/vega@v0.79.0/core/staking/account_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 staking_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/staking" 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/num" 25 26 "github.com/stretchr/testify/assert" 27 ) 28 29 const ( 30 testParty = "bob" 31 ) 32 33 func TestStakingAccount(t *testing.T) { 34 t.Run("account with no event have a zero balance", testGetZeroBalanceWithNoEvent) 35 t.Run("event error validation", testEventErrorValidation) 36 t.Run("test events sorting", testEventSorting) 37 t.Run("get available balance at", testGetAvailableBalanceAt) 38 t.Run("get available balance in range", testGetAvailableBalanceInRange) 39 } 40 41 func testGetAvailableBalanceInRange(t *testing.T) { 42 acc := staking.NewStakingAccount(testParty) 43 cases := []struct { 44 evt types.StakeLinking 45 expect error 46 }{ 47 { 48 evt: types.StakeLinking{ 49 ID: "someid1", 50 Type: types.StakeLinkingTypeDeposited, 51 TS: 100, 52 Party: testParty, 53 Amount: num.NewUint(10), 54 }, 55 expect: nil, 56 }, 57 { 58 evt: types.StakeLinking{ 59 ID: "someid2", 60 Type: types.StakeLinkingTypeRemoved, 61 TS: 110, 62 Party: testParty, 63 Amount: num.NewUint(1), 64 }, 65 expect: nil, 66 }, 67 { 68 evt: types.StakeLinking{ 69 ID: "someid3", 70 Type: types.StakeLinkingTypeDeposited, 71 TS: 120, 72 Party: testParty, 73 Amount: num.NewUint(5), 74 }, 75 expect: nil, 76 }, 77 { 78 evt: types.StakeLinking{ 79 ID: "someid4", 80 Type: types.StakeLinkingTypeRemoved, 81 TS: 125, 82 Party: testParty, 83 Amount: num.NewUint(6), 84 }, 85 expect: nil, 86 }, 87 } 88 89 for _, c := range cases { 90 c := c 91 err := acc.AddEvent(&c.evt) 92 assert.Equal(t, c.expect, err) 93 } 94 95 balance, err := acc.GetAvailableBalanceInRange( 96 time.Unix(0, 10), time.Unix(0, 20)) 97 assert.NoError(t, err) 98 assert.Equal(t, num.NewUint(0), balance) 99 100 balance, err = acc.GetAvailableBalanceInRange( 101 time.Unix(0, 10), time.Unix(0, 110)) 102 assert.NoError(t, err) 103 assert.Equal(t, num.NewUint(0), balance) 104 105 balance, err = acc.GetAvailableBalanceInRange( 106 time.Unix(0, 101), time.Unix(0, 109)) 107 assert.NoError(t, err) 108 assert.Equal(t, num.NewUint(10), balance) 109 110 balance, err = acc.GetAvailableBalanceInRange( 111 time.Unix(0, 101), time.Unix(0, 111)) 112 assert.NoError(t, err) 113 assert.Equal(t, num.NewUint(9), balance) 114 115 balance, err = acc.GetAvailableBalanceInRange( 116 time.Unix(0, 101), time.Unix(0, 121)) 117 assert.NoError(t, err) 118 assert.Equal(t, num.NewUint(9), balance) 119 120 balance, err = acc.GetAvailableBalanceInRange( 121 time.Unix(0, 101), time.Unix(0, 126)) 122 assert.NoError(t, err) 123 assert.Equal(t, num.NewUint(8), balance) 124 } 125 126 func testGetAvailableBalanceAt(t *testing.T) { 127 acc := staking.NewStakingAccount(testParty) 128 cases := []struct { 129 evt types.StakeLinking 130 expect error 131 }{ 132 { 133 evt: types.StakeLinking{ 134 ID: "someid1", 135 Type: types.StakeLinkingTypeDeposited, 136 TS: 100, 137 Party: testParty, 138 Amount: num.NewUint(10), 139 }, 140 expect: nil, 141 }, 142 { 143 evt: types.StakeLinking{ 144 ID: "someid2", 145 Type: types.StakeLinkingTypeRemoved, 146 TS: 110, 147 Party: testParty, 148 Amount: num.NewUint(1), 149 }, 150 expect: nil, 151 }, 152 { 153 evt: types.StakeLinking{ 154 ID: "someid3", 155 Type: types.StakeLinkingTypeDeposited, 156 TS: 120, 157 Party: testParty, 158 Amount: num.NewUint(5), 159 }, 160 expect: nil, 161 }, 162 } 163 164 for _, c := range cases { 165 c := c 166 err := acc.AddEvent(&c.evt) 167 assert.Equal(t, c.expect, err) 168 } 169 170 balance, err := acc.GetAvailableBalanceAt(time.Unix(0, 10)) 171 assert.NoError(t, err) 172 assert.Equal(t, num.NewUint(0), balance) 173 balance, err = acc.GetAvailableBalanceAt(time.Unix(0, 120)) 174 assert.NoError(t, err) 175 assert.Equal(t, num.NewUint(14), balance) 176 balance, err = acc.GetAvailableBalanceAt(time.Unix(0, 115)) 177 assert.NoError(t, err) 178 assert.Equal(t, num.NewUint(9), balance) 179 } 180 181 func testEventSorting(t *testing.T) { 182 acc := staking.NewStakingAccount(testParty) 183 184 // we have 2 events added for the same timestamp 185 // although the first one is a remove 186 // second one is a deposit 187 // so we would expect at the end for the events to 188 // be sorted and return the actual balance 189 evts := []types.StakeLinking{ 190 { 191 ID: "someid2", 192 Type: types.StakeLinkingTypeRemoved, 193 TS: 100, 194 Party: testParty, 195 Amount: num.NewUint(1), 196 }, 197 { 198 ID: "someid1", 199 Type: types.StakeLinkingTypeDeposited, 200 TS: 100, 201 Party: testParty, 202 Amount: num.NewUint(100), 203 }, 204 } 205 206 err := acc.AddEvent(&evts[0]) 207 assert.EqualError(t, staking.ErrNegativeBalance, err.Error()) 208 err = acc.AddEvent(&evts[1]) 209 assert.NoError(t, err) 210 // now assert the final balance 211 assert.Equal(t, num.NewUint(99), acc.GetAvailableBalance()) 212 } 213 214 func testGetZeroBalanceWithNoEvent(t *testing.T) { 215 acc := staking.NewStakingAccount(testParty) 216 assert.Equal(t, num.UintZero(), acc.GetAvailableBalance()) 217 } 218 219 func testEventErrorValidation(t *testing.T) { 220 acc := staking.NewStakingAccount(testParty) 221 222 cases := []struct { 223 evt types.StakeLinking 224 expect error 225 }{ 226 { // invalid id 227 evt: types.StakeLinking{ 228 ID: "", 229 Type: types.StakeLinkingTypeDeposited, 230 TS: 100, 231 Party: testParty, 232 Amount: num.NewUint(1), 233 }, 234 expect: staking.ErrMissingEventID, 235 }, 236 { 237 evt: types.StakeLinking{ 238 ID: "someid", 239 Type: 10, 240 TS: 100, 241 Party: testParty, 242 Amount: num.NewUint(1), 243 }, 244 expect: staking.ErrInvalidEventKind, 245 }, 246 { 247 evt: types.StakeLinking{ 248 ID: "someid", 249 Type: types.StakeLinkingTypeDeposited, 250 TS: 0, 251 Party: testParty, 252 Amount: num.NewUint(1), 253 }, 254 expect: staking.ErrMissingTimestamp, 255 }, 256 { 257 evt: types.StakeLinking{ 258 ID: "someid", 259 Type: types.StakeLinkingTypeDeposited, 260 TS: 100, 261 Party: testParty, 262 Amount: num.UintZero(), 263 }, 264 expect: staking.ErrInvalidAmount, 265 }, 266 { 267 evt: types.StakeLinking{ 268 ID: "someid", 269 Type: types.StakeLinkingTypeDeposited, 270 TS: 100, 271 Party: "not-a-party", 272 Amount: num.NewUint(10), 273 }, 274 expect: staking.ErrInvalidParty, 275 }, 276 { 277 evt: types.StakeLinking{ 278 ID: "someid", 279 Type: types.StakeLinkingTypeDeposited, 280 TS: 100, 281 Party: testParty, 282 Amount: num.NewUint(1), 283 }, 284 expect: nil, 285 }, 286 { 287 evt: types.StakeLinking{ 288 ID: "someid", 289 Type: types.StakeLinkingTypeDeposited, 290 TS: 100, 291 Party: testParty, 292 Amount: num.NewUint(1), 293 }, 294 expect: staking.ErrEventAlreadyExists, 295 }, 296 } 297 298 for _, c := range cases { 299 c := c 300 err := acc.AddEvent(&c.evt) 301 assert.Equal(t, c.expect, err) 302 } 303 }