code.vegaprotocol.io/vega@v0.79.0/commands/proposal_submission_new_transfer_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 commands_test 17 18 import ( 19 "errors" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/commands" 24 "code.vegaprotocol.io/vega/libs/crypto" 25 types "code.vegaprotocol.io/vega/protos/vega" 26 commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" 27 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestCheckProposalSubmissionForNewTransfer(t *testing.T) { 32 t.Run("Submitting a new transfer change without a transfer market fails", testNewTransferChangeSubmissionWithoutTransferFails) 33 t.Run("Submitting a new transfer change without changes fails", testNewTransferChangeSubmissionWithoutChangesFails) 34 t.Run("Submitting a new transfer change without source account type fails", testNewTransferChangeSubmissionWithoutSourceTypeFails) 35 t.Run("Submitting a new transfer change with an invalid source account type fails", testNewTransferChangeSubmissionInvalidSourceTypeFails) 36 t.Run("Submitting a new transfer change without destination account type fails", testNewTransferChangeSubmissionWithoutDestinationTypeFails) 37 t.Run("Submitting a new transfer change with an invalid destination account type fails", testNewTransferChangeSubmissionInvalidDestinationTypeFails) 38 t.Run("Submitting a new transfer change with an invalid source fails", testNewTransferChangeSubmissionInvalidSourceFails) 39 t.Run("Submitting a new transfer change with an invalid destination fails", testNewTransferChangeSubmissionInvalidDestinationFails) 40 t.Run("Submitting a new transfer change with an invalid governance transfer type fails", testNewTransferChangeSubmissionInvalidTransferTypeFails) 41 t.Run("Submitting a new transfer change with an invalid amounts fails", testNewTransferChangeSubmissionInvalidAmountFails) 42 t.Run("Submitting a new transfer change with an invalid asset fails", testNewTransferChangeSubmissionInvalidAseetFails) 43 t.Run("Submitting a new transfer change with an invalid fraction fails", testNewTransferChangeSubmissionInvalidFractionFails) 44 t.Run("Submitting a new transfer change with neither one off nor recurring fails", testNewTransferWithNoKind) 45 t.Run("Submitting a new transfer change with recurring end epoch before the start epoch", testNewRecurringGovernanceTransferInvalidEndEpoch) 46 t.Run("Submitting a new transfer change with identical source/destination accounts", testNewTransferChangeSubmissionIneffectualTransferFails) 47 t.Run("Submitting a cancel transfer change with missing transfer id fails", testCancelTransferChangeSubmission) 48 t.Run("Submitting a new transfer change with an invalid destination type for one off transfer", testOneOffWithInvalidDestinationType) 49 t.Run("Submitting a new transfer change with an negative deliverOn", testOneOffWithNegativeDeliverOn) 50 t.Run("Submitting a new recurring transfer change with a dispatch strategy and destination party", testRecurringWithDestinationAndDispatch) 51 t.Run("Submitting a new recurring transfer change with a dispatch strategy and an invalid type", testRecurringWithDispatchInvalidTypes) 52 t.Run("Submitting a new recurring transfer change with a dispatch strategy and incompatible empty asset for metric", testInvalidAssetForMetric) 53 t.Run("Submitting a new recurring transfer change with a dispatch strategy and mismatching destination type for metric", testInvalidDestForMetric) 54 t.Run("Submitting a new transfer change with destination type general and an invalid vega public key", testInvalidGeneralPubKey) 55 t.Run("Submitting a new transfer change with destination type general and an invalid vega public key", testOnlyGeneralValid) 56 t.Run("Submitting a new transfer change with invalid decay factor", testInvalidDecayFactor) 57 } 58 59 func testInvalidDestForMetric(t *testing.T) { 60 metricsMismatches := map[types.AccountType][]types.DispatchMetric{ 61 types.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: { 62 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 63 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 64 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 65 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 66 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 67 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 68 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 69 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 70 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 71 }, 72 types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: { 73 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 74 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 75 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 76 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 77 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 78 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 79 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 80 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 81 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 82 }, 83 types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: { 84 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 85 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 86 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 87 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 88 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 89 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 90 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 91 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 92 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 93 }, 94 types.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: { 95 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 96 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 97 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 98 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 99 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 100 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 101 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 102 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 103 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 104 }, 105 types.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL: { 106 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 107 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 108 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 109 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 110 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 111 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 112 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 113 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 114 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 115 }, 116 types.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN: { 117 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 118 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 119 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 120 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 121 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 122 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 123 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 124 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 125 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 126 }, 127 types.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: { 128 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 129 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 130 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 131 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 132 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 133 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 134 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 135 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 136 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 137 }, 138 types.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: { 139 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 140 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 141 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 142 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 143 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 144 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 145 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 146 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 147 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 148 }, 149 types.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN: { 150 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 151 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 152 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 153 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 154 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 155 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 156 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 157 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 158 types.DispatchMetric_DISPATCH_METRIC_ELIGIBLE_ENTITIES, 159 }, 160 types.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES: { 161 types.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED, 162 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, 163 types.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, 164 types.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE, 165 types.DispatchMetric_DISPATCH_METRIC_AVERAGE_NOTIONAL, 166 types.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 167 types.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, 168 types.DispatchMetric_DISPATCH_METRIC_VALIDATOR_RANKING, 169 types.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN, 170 }, 171 } 172 173 for tp, metrics := range metricsMismatches { 174 for _, metric := range metrics { 175 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 176 Terms: &types.ProposalTerms{ 177 Change: &types.ProposalTerms_NewTransfer{ 178 NewTransfer: &types.NewTransfer{ 179 Changes: &types.NewTransferConfiguration{ 180 FractionOfBalance: "0.5", 181 Amount: "1000", 182 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 183 DestinationType: tp, 184 Destination: "", 185 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 186 Asset: "abcde", 187 Kind: &types.NewTransferConfiguration_Recurring{ 188 Recurring: &types.RecurringTransfer{ 189 StartEpoch: 10, 190 DispatchStrategy: &types.DispatchStrategy{ 191 Metric: metric, 192 }, 193 }, 194 }, 195 }, 196 }, 197 }, 198 }, 199 }) 200 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.recurring.dispatch_strategy.dispatch_metric"), errors.New("cannot set toAccountType to "+tp.String()+" when dispatch metric is set to "+metric.String())) 201 } 202 } 203 } 204 205 func testInvalidAssetForMetric(t *testing.T) { 206 invalidTypes := []types.AccountType{ 207 types.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES, 208 types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES, 209 types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES, 210 types.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL, 211 types.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN, 212 types.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY, 213 types.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN, 214 } 215 216 for _, inv := range invalidTypes { 217 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 218 Terms: &types.ProposalTerms{ 219 Change: &types.ProposalTerms_NewTransfer{ 220 NewTransfer: &types.NewTransfer{ 221 Changes: &types.NewTransferConfiguration{ 222 FractionOfBalance: "0.5", 223 Amount: "1000", 224 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 225 DestinationType: inv, 226 Destination: "", 227 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 228 Asset: "abcde", 229 Kind: &types.NewTransferConfiguration_Recurring{ 230 Recurring: &types.RecurringTransfer{ 231 StartEpoch: 10, 232 DispatchStrategy: &types.DispatchStrategy{}, 233 }, 234 }, 235 }, 236 }, 237 }, 238 }, 239 }) 240 241 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.recurring.dispatch_strategy.asset_for_metric"), commands.ErrIsRequired) 242 } 243 244 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 245 Terms: &types.ProposalTerms{ 246 Change: &types.ProposalTerms_NewTransfer{ 247 NewTransfer: &types.NewTransfer{ 248 Changes: &types.NewTransferConfiguration{ 249 FractionOfBalance: "0.5", 250 Amount: "1000", 251 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 252 DestinationType: types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES, 253 Destination: "", 254 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 255 Asset: "abcde", 256 Kind: &types.NewTransferConfiguration_Recurring{ 257 Recurring: &types.RecurringTransfer{ 258 StartEpoch: 10, 259 DispatchStrategy: &types.DispatchStrategy{ 260 AssetForMetric: "zohar", 261 }, 262 }, 263 }, 264 }, 265 }, 266 }, 267 }, 268 }) 269 270 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.recurring.dispatch_strategy.asset_for_metric"), commands.ErrShouldBeAValidVegaID, err.Error()) 271 } 272 273 func testRecurringWithDispatchInvalidTypes(t *testing.T) { 274 invalidTypes := make(map[types.AccountType]struct{}, len(types.AccountType_name)) 275 for k := range types.AccountType_name { 276 invalidTypes[types.AccountType(k)] = struct{}{} 277 } 278 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES) 279 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES) 280 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES) 281 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS) 282 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING) 283 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY) 284 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN) 285 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN) 286 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL) 287 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES) 288 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_INSURANCE) 289 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_GENERAL) 290 291 delete(invalidTypes, types.AccountType_ACCOUNT_TYPE_UNSPECIFIED) 292 293 for inv := range invalidTypes { 294 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 295 Terms: &types.ProposalTerms{ 296 Change: &types.ProposalTerms_NewTransfer{ 297 NewTransfer: &types.NewTransfer{ 298 Changes: &types.NewTransferConfiguration{ 299 FractionOfBalance: "0.5", 300 Amount: "1000", 301 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 302 DestinationType: inv, 303 Destination: "", 304 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 305 Asset: "abcde", 306 Kind: &types.NewTransferConfiguration_Recurring{ 307 Recurring: &types.RecurringTransfer{ 308 StartEpoch: 10, 309 DispatchStrategy: &types.DispatchStrategy{}, 310 }, 311 }, 312 }, 313 }, 314 }, 315 }, 316 }) 317 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination_type"), commands.ErrIsNotValid, inv.String()) 318 } 319 } 320 321 func testRecurringWithDestinationAndDispatch(t *testing.T) { 322 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 323 Terms: &types.ProposalTerms{ 324 Change: &types.ProposalTerms_NewTransfer{ 325 NewTransfer: &types.NewTransfer{ 326 Changes: &types.NewTransferConfiguration{ 327 FractionOfBalance: "0.5", 328 Amount: "1000", 329 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 330 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 331 Destination: "zohar", 332 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 333 Asset: "abcde", 334 Kind: &types.NewTransferConfiguration_Recurring{ 335 Recurring: &types.RecurringTransfer{ 336 StartEpoch: 10, 337 DispatchStrategy: &types.DispatchStrategy{}, 338 }, 339 }, 340 }, 341 }, 342 }, 343 }, 344 }) 345 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination"), commands.ErrIsNotValid) 346 } 347 348 func testOneOffWithNegativeDeliverOn(t *testing.T) { 349 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 350 Terms: &types.ProposalTerms{ 351 Change: &types.ProposalTerms_NewTransfer{ 352 NewTransfer: &types.NewTransfer{ 353 Changes: &types.NewTransferConfiguration{ 354 FractionOfBalance: "0.5", 355 Amount: "1000", 356 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 357 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 358 Destination: "zohar", 359 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 360 Asset: "abcde", 361 Kind: &types.NewTransferConfiguration_OneOff{ 362 OneOff: &types.OneOffTransfer{ 363 DeliverOn: -100, 364 }, 365 }, 366 }, 367 }, 368 }, 369 }, 370 }) 371 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.oneoff.deliveron"), commands.ErrMustBePositiveOrZero) 372 } 373 374 func testInvalidDecayFactor(t *testing.T) { 375 decayFactors := []string{"", "-0.1", "bc", "0"} 376 errors := []string{ 377 "proposal_submission.terms.change.new_transfer.changes.recurring.factor (not a valid float)", 378 "proposal_submission.terms.change.new_transfer.changes.recurring.factor (must be positive)", 379 "proposal_submission.terms.change.new_transfer.changes.recurring.factor (not a valid float)", 380 "proposal_submission.terms.change.new_transfer.changes.recurring.factor (must be positive)", 381 } 382 for i, decay := range decayFactors { 383 prop := &commandspb.ProposalSubmission{ 384 Rationale: &types.ProposalRationale{ 385 Description: "valid", 386 Title: "test", 387 }, 388 Terms: &types.ProposalTerms{ 389 ClosingTimestamp: time.Now().Unix() + 100, 390 EnactmentTimestamp: time.Now().Unix() + 200, 391 Change: &types.ProposalTerms_NewTransfer{ 392 NewTransfer: &types.NewTransfer{ 393 Changes: &types.NewTransferConfiguration{ 394 FractionOfBalance: "0.5", 395 Amount: "1000", 396 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 397 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 398 Destination: crypto.RandomHash(), 399 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 400 Asset: "abcde", 401 Kind: &types.NewTransferConfiguration_Recurring{ 402 Recurring: &types.RecurringTransfer{ 403 StartEpoch: 0, 404 Factor: decay, 405 }, 406 }, 407 }, 408 }, 409 }, 410 }, 411 } 412 err := checkProposalSubmission(prop) 413 require.Equal(t, errors[i], err.Error()) 414 } 415 prop := &commandspb.ProposalSubmission{ 416 Rationale: &types.ProposalRationale{ 417 Description: "valid", 418 Title: "test", 419 }, 420 Terms: &types.ProposalTerms{ 421 ClosingTimestamp: time.Now().Unix() + 100, 422 EnactmentTimestamp: time.Now().Unix() + 200, 423 Change: &types.ProposalTerms_NewTransfer{ 424 NewTransfer: &types.NewTransfer{ 425 Changes: &types.NewTransferConfiguration{ 426 FractionOfBalance: "0.5", 427 Amount: "1000", 428 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 429 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 430 Destination: crypto.RandomHash(), 431 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 432 Asset: "abcde", 433 Kind: &types.NewTransferConfiguration_Recurring{ 434 Recurring: &types.RecurringTransfer{ 435 StartEpoch: 0, 436 Factor: "0.5", 437 }, 438 }, 439 }, 440 }, 441 }, 442 }, 443 } 444 err := checkProposalSubmission(prop) 445 require.True(t, err.Empty()) 446 } 447 448 func testOnlyGeneralValid(t *testing.T) { 449 partyAccs := []types.AccountType{ 450 types.AccountType_ACCOUNT_TYPE_MARGIN, 451 types.AccountType_ACCOUNT_TYPE_BOND, 452 } 453 // start with a valid transfer to the general account 454 prop := &commandspb.ProposalSubmission{ 455 Rationale: &types.ProposalRationale{ 456 Description: "valid", 457 Title: "test", 458 }, 459 Terms: &types.ProposalTerms{ 460 ClosingTimestamp: time.Now().Unix() + 100, 461 EnactmentTimestamp: time.Now().Unix() + 200, 462 Change: &types.ProposalTerms_NewTransfer{ 463 NewTransfer: &types.NewTransfer{ 464 Changes: &types.NewTransferConfiguration{ 465 FractionOfBalance: "0.5", 466 Amount: "1000", 467 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 468 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 469 Destination: crypto.RandomHash(), 470 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 471 Asset: "abcde", 472 Kind: &types.NewTransferConfiguration_OneOff{ 473 OneOff: &types.OneOffTransfer{ 474 DeliverOn: 0, 475 }, 476 }, 477 }, 478 }, 479 }, 480 }, 481 } 482 err := checkProposalSubmission(prop) 483 require.True(t, err.Empty()) 484 // none of the other accounts are valid destination types: 485 for _, at := range partyAccs { 486 prop := &commandspb.ProposalSubmission{ 487 Rationale: &types.ProposalRationale{ 488 Description: "invalid", 489 Title: "test", 490 }, 491 Terms: &types.ProposalTerms{ 492 ClosingTimestamp: time.Now().Unix() + 100, 493 EnactmentTimestamp: time.Now().Unix() + 200, 494 Change: &types.ProposalTerms_NewTransfer{ 495 NewTransfer: &types.NewTransfer{ 496 Changes: &types.NewTransferConfiguration{ 497 FractionOfBalance: "0.5", 498 Amount: "1000", 499 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 500 DestinationType: at, 501 Destination: crypto.RandomHash(), // ensure a valid hash 502 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 503 Asset: "abcde", 504 Kind: &types.NewTransferConfiguration_OneOff{ 505 OneOff: &types.OneOffTransfer{ 506 DeliverOn: 0, 507 }, 508 }, 509 }, 510 }, 511 }, 512 }, 513 } 514 err = checkProposalSubmission(prop) 515 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination_type"), commands.ErrIsNotValid) 516 } 517 } 518 519 func testInvalidGeneralPubKey(t *testing.T) { 520 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 521 Terms: &types.ProposalTerms{ 522 Change: &types.ProposalTerms_NewTransfer{ 523 NewTransfer: &types.NewTransfer{ 524 Changes: &types.NewTransferConfiguration{ 525 FractionOfBalance: "0.5", 526 Amount: "1000", 527 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 528 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 529 Destination: "zohar", 530 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 531 Asset: "abcde", 532 Kind: &types.NewTransferConfiguration_OneOff{ 533 OneOff: &types.OneOffTransfer{ 534 DeliverOn: -100, 535 }, 536 }, 537 }, 538 }, 539 }, 540 }, 541 }) 542 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination"), commands.ErrShouldBeAValidVegaPublicKey) 543 } 544 545 func testOneOffWithInvalidDestinationType(t *testing.T) { 546 dests := []types.AccountType{ 547 types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 548 types.AccountType_ACCOUNT_TYPE_SETTLEMENT, 549 types.AccountType_ACCOUNT_TYPE_MARGIN, 550 types.AccountType_ACCOUNT_TYPE_BOND, 551 types.AccountType_ACCOUNT_TYPE_FEES_MAKER, 552 types.AccountType_ACCOUNT_TYPE_FEES_INFRASTRUCTURE, 553 types.AccountType_ACCOUNT_TYPE_FEES_LIQUIDITY, 554 } 555 556 for _, dest := range dests { 557 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 558 Terms: &types.ProposalTerms{ 559 Change: &types.ProposalTerms_NewTransfer{ 560 NewTransfer: &types.NewTransfer{ 561 Changes: &types.NewTransferConfiguration{ 562 FractionOfBalance: "0.5", 563 Amount: "1000", 564 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 565 DestinationType: dest, 566 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 567 Asset: "abcde", 568 Kind: &types.NewTransferConfiguration_OneOff{ 569 OneOff: &types.OneOffTransfer{}, 570 }, 571 }, 572 }, 573 }, 574 }, 575 }) 576 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination_type"), commands.ErrIsNotValid) 577 } 578 } 579 580 func testNewRecurringGovernanceTransferInvalidEndEpoch(t *testing.T) { 581 endEpoch := uint64(8) 582 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 583 Terms: &types.ProposalTerms{ 584 Change: &types.ProposalTerms_NewTransfer{ 585 NewTransfer: &types.NewTransfer{ 586 Changes: &types.NewTransferConfiguration{ 587 FractionOfBalance: "0.5", 588 Amount: "1000", 589 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 590 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 591 Destination: crypto.RandomHash(), 592 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 593 Asset: "abcde", 594 Kind: &types.NewTransferConfiguration_Recurring{ 595 Recurring: &types.RecurringTransfer{ 596 StartEpoch: 10, 597 EndEpoch: &endEpoch, 598 }, 599 }, 600 }, 601 }, 602 }, 603 }, 604 }) 605 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.recurring.end_epoch"), commands.ErrIsNotValid) 606 } 607 608 func testNewTransferWithNoKind(t *testing.T) { 609 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 610 Terms: &types.ProposalTerms{ 611 Change: &types.ProposalTerms_NewTransfer{ 612 NewTransfer: &types.NewTransfer{ 613 Changes: &types.NewTransferConfiguration{ 614 FractionOfBalance: "0.5", 615 Amount: "1000", 616 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 617 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 618 Destination: crypto.RandomHash(), 619 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 620 Asset: "abcde", 621 }, 622 }, 623 }, 624 }, 625 }) 626 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.kind"), commands.ErrIsRequired) 627 } 628 629 func testNewTransferChangeSubmissionWithoutTransferFails(t *testing.T) { 630 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 631 Terms: &types.ProposalTerms{ 632 Change: &types.ProposalTerms_NewTransfer{}, 633 }, 634 }) 635 636 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer"), commands.ErrIsRequired) 637 } 638 639 func testNewTransferChangeSubmissionWithoutChangesFails(t *testing.T) { 640 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 641 Terms: &types.ProposalTerms{ 642 Change: &types.ProposalTerms_NewTransfer{ 643 NewTransfer: &types.NewTransfer{}, 644 }, 645 }, 646 }) 647 648 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes"), commands.ErrIsRequired) 649 } 650 651 func testNewTransferChangeSubmissionWithoutSourceTypeFails(t *testing.T) { 652 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 653 Terms: &types.ProposalTerms{ 654 Change: &types.ProposalTerms_NewTransfer{ 655 NewTransfer: &types.NewTransfer{ 656 Changes: &types.NewTransferConfiguration{}, 657 }, 658 }, 659 }, 660 }) 661 662 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.source_type"), commands.ErrIsRequired) 663 } 664 665 func testNewTransferChangeSubmissionWithoutDestinationTypeFails(t *testing.T) { 666 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 667 Terms: &types.ProposalTerms{ 668 Change: &types.ProposalTerms_NewTransfer{ 669 NewTransfer: &types.NewTransfer{ 670 Changes: &types.NewTransferConfiguration{ 671 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 672 }, 673 }, 674 }, 675 }, 676 }) 677 678 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination_type"), commands.ErrIsRequired) 679 } 680 681 func testNewTransferChangeSubmissionInvalidDestinationTypeFails(t *testing.T) { 682 allAccountTypes := make(map[int32]struct{}, len(types.AccountType_name)) 683 for k := range types.AccountType_name { 684 allAccountTypes[k] = struct{}{} 685 } 686 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_GENERAL)) 687 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD)) 688 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_INSURANCE)) 689 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY)) 690 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE)) 691 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES)) 692 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES)) 693 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES)) 694 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS)) 695 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL)) 696 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN)) 697 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY)) 698 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING)) 699 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN)) 700 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES)) 701 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_UNSPECIFIED)) 702 703 for at := range allAccountTypes { 704 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 705 Terms: &types.ProposalTerms{ 706 Change: &types.ProposalTerms_NewTransfer{ 707 NewTransfer: &types.NewTransfer{ 708 Changes: &types.NewTransferConfiguration{ 709 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 710 DestinationType: types.AccountType(at), 711 }, 712 }, 713 }, 714 }, 715 }) 716 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination_type"), commands.ErrIsNotValid) 717 } 718 validDestinationAccountTypes := []types.AccountType{types.AccountType_ACCOUNT_TYPE_GENERAL, types.AccountType_ACCOUNT_TYPE_INSURANCE} 719 for _, at := range validDestinationAccountTypes { 720 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 721 Terms: &types.ProposalTerms{ 722 Change: &types.ProposalTerms_NewTransfer{ 723 NewTransfer: &types.NewTransfer{ 724 Changes: &types.NewTransferConfiguration{ 725 SourceType: types.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD, 726 DestinationType: at, 727 }, 728 }, 729 }, 730 }, 731 }) 732 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination_type"), commands.ErrIsNotValid) 733 } 734 } 735 736 func testNewTransferChangeSubmissionInvalidSourceTypeFails(t *testing.T) { 737 allAccountTypes := make(map[int32]struct{}, len(types.AccountType_name)) 738 for k := range types.AccountType_name { 739 allAccountTypes[k] = struct{}{} 740 } 741 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY)) 742 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE)) 743 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_INSURANCE)) 744 delete(allAccountTypes, int32(types.AccountType_ACCOUNT_TYPE_UNSPECIFIED)) 745 746 for at := range allAccountTypes { 747 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 748 Terms: &types.ProposalTerms{ 749 Change: &types.ProposalTerms_NewTransfer{ 750 NewTransfer: &types.NewTransfer{ 751 Changes: &types.NewTransferConfiguration{ 752 SourceType: types.AccountType(at), 753 }, 754 }, 755 }, 756 }, 757 }) 758 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.source_type"), commands.ErrIsNotValid, types.AccountType(at).String()) 759 } 760 761 validSourceAccountTypes := []types.AccountType{types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, types.AccountType_ACCOUNT_TYPE_INSURANCE} 762 for _, at := range validSourceAccountTypes { 763 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 764 Terms: &types.ProposalTerms{ 765 Change: &types.ProposalTerms_NewTransfer{ 766 NewTransfer: &types.NewTransfer{ 767 Changes: &types.NewTransferConfiguration{ 768 SourceType: at, 769 }, 770 }, 771 }, 772 }, 773 }) 774 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.source_type"), commands.ErrIsNotValid) 775 } 776 } 777 778 func testNewTransferChangeSubmissionInvalidSourceFails(t *testing.T) { 779 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 780 Terms: &types.ProposalTerms{ 781 Change: &types.ProposalTerms_NewTransfer{ 782 NewTransfer: &types.NewTransfer{ 783 Changes: &types.NewTransferConfiguration{ 784 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 785 Source: "some source", 786 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 787 }, 788 }, 789 }, 790 }, 791 }) 792 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.source"), commands.ErrIsNotValid) 793 } 794 795 func testNewTransferChangeSubmissionInvalidDestinationFails(t *testing.T) { 796 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 797 Terms: &types.ProposalTerms{ 798 Change: &types.ProposalTerms_NewTransfer{ 799 NewTransfer: &types.NewTransfer{ 800 Changes: &types.NewTransferConfiguration{ 801 SourceType: types.AccountType_ACCOUNT_TYPE_INSURANCE, 802 Source: "some market", 803 DestinationType: types.AccountType_ACCOUNT_TYPE_INSURANCE, 804 Destination: "", 805 }, 806 }, 807 }, 808 }, 809 }) 810 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination"), commands.ErrIsNotValid, err.Error()) 811 } 812 813 func testCancelTransferChangeSubmission(t *testing.T) { 814 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 815 Terms: &types.ProposalTerms{ 816 Change: &types.ProposalTerms_CancelTransfer{}, 817 }, 818 }) 819 require.Contains(t, err.Get("proposal_submission.terms.change.cancel_transfer"), commands.ErrIsRequired) 820 821 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 822 Terms: &types.ProposalTerms{ 823 Change: &types.ProposalTerms_CancelTransfer{ 824 CancelTransfer: &types.CancelTransfer{}, 825 }, 826 }, 827 }) 828 require.Contains(t, err.Get("proposal_submission.terms.change.cancel_transfer.changes"), commands.ErrIsRequired) 829 830 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 831 Terms: &types.ProposalTerms{ 832 Change: &types.ProposalTerms_CancelTransfer{ 833 CancelTransfer: &types.CancelTransfer{ 834 Changes: &types.CancelTransferConfiguration{}, 835 }, 836 }, 837 }, 838 }) 839 require.Contains(t, err.Get("proposal_submission.terms.change.cancel_transfer.changes.transferId"), commands.ErrIsRequired) 840 } 841 842 func testNewTransferChangeSubmissionIneffectualTransferFails(t *testing.T) { 843 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 844 Terms: &types.ProposalTerms{ 845 Change: &types.ProposalTerms_NewTransfer{ 846 NewTransfer: &types.NewTransfer{ 847 Changes: &types.NewTransferConfiguration{ 848 SourceType: types.AccountType_ACCOUNT_TYPE_INSURANCE, 849 DestinationType: types.AccountType_ACCOUNT_TYPE_INSURANCE, 850 Source: "some destination", 851 Destination: "some destination", 852 }, 853 }, 854 }, 855 }, 856 }) 857 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.destination"), commands.ErrIsNotValid) 858 } 859 860 func testNewTransferChangeSubmissionInvalidTransferTypeFails(t *testing.T) { 861 expectation := map[types.GovernanceTransferType]bool{ 862 types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED: true, 863 types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING: false, 864 types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_BEST_EFFORT: false, 865 } 866 for tp, expectedError := range expectation { 867 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 868 Terms: &types.ProposalTerms{ 869 Change: &types.ProposalTerms_NewTransfer{ 870 NewTransfer: &types.NewTransfer{ 871 Changes: &types.NewTransferConfiguration{ 872 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 873 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 874 Destination: crypto.RandomHash(), 875 TransferType: tp, 876 }, 877 }, 878 }, 879 }, 880 }) 881 if expectedError { 882 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.transfer_type"), commands.ErrIsRequired) 883 } else { 884 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.transfer_type"), commands.ErrIsRequired) 885 } 886 } 887 } 888 889 func testNewTransferChangeSubmissionInvalidAmountFails(t *testing.T) { 890 transfer := &types.NewTransferConfiguration{ 891 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 892 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 893 Destination: crypto.RandomHash(), 894 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 895 } 896 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 897 Terms: &types.ProposalTerms{ 898 Change: &types.ProposalTerms_NewTransfer{ 899 NewTransfer: &types.NewTransfer{ 900 Changes: transfer, 901 }, 902 }, 903 }, 904 }) 905 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.amount"), commands.ErrIsRequired) 906 transfer.Amount = "abc" 907 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 908 Terms: &types.ProposalTerms{ 909 Change: &types.ProposalTerms_NewTransfer{ 910 NewTransfer: &types.NewTransfer{ 911 Changes: transfer, 912 }, 913 }, 914 }, 915 }) 916 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.amount"), commands.ErrIsNotValid) 917 transfer.Amount = "500.1234" 918 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 919 Terms: &types.ProposalTerms{ 920 Change: &types.ProposalTerms_NewTransfer{ 921 NewTransfer: &types.NewTransfer{ 922 Changes: transfer, 923 }, 924 }, 925 }, 926 }) 927 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.amount"), commands.ErrIsNotValid) 928 929 transfer.Amount = "-500" 930 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 931 Terms: &types.ProposalTerms{ 932 Change: &types.ProposalTerms_NewTransfer{ 933 NewTransfer: &types.NewTransfer{ 934 Changes: transfer, 935 }, 936 }, 937 }, 938 }) 939 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.amount"), commands.ErrIsNotValid) 940 941 transfer.Amount = "500" 942 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 943 Terms: &types.ProposalTerms{ 944 Change: &types.ProposalTerms_NewTransfer{ 945 NewTransfer: &types.NewTransfer{ 946 Changes: transfer, 947 }, 948 }, 949 }, 950 }) 951 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.amount"), commands.ErrIsNotValid) 952 } 953 954 func testNewTransferChangeSubmissionInvalidAseetFails(t *testing.T) { 955 transfer := &types.NewTransferConfiguration{ 956 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 957 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 958 Destination: crypto.RandomHash(), 959 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 960 Amount: "500", 961 } 962 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 963 Terms: &types.ProposalTerms{ 964 Change: &types.ProposalTerms_NewTransfer{ 965 NewTransfer: &types.NewTransfer{ 966 Changes: transfer, 967 }, 968 }, 969 }, 970 }) 971 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.asset"), commands.ErrIsRequired) 972 transfer.Asset = "abcde" 973 err = checkProposalSubmission(&commandspb.ProposalSubmission{ 974 Terms: &types.ProposalTerms{ 975 Change: &types.ProposalTerms_NewTransfer{ 976 NewTransfer: &types.NewTransfer{ 977 Changes: transfer, 978 }, 979 }, 980 }, 981 }) 982 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.asset"), commands.ErrIsRequired) 983 } 984 985 func testNewTransferChangeSubmissionInvalidFractionFails(t *testing.T) { 986 expectation := map[string]error{ 987 "": commands.ErrIsRequired, 988 "abc": commands.ErrIsNotValid, 989 "-1": commands.ErrMustBePositive, 990 "1.01": commands.ErrMustBeLTE1, 991 } 992 993 transfer := &types.NewTransferConfiguration{ 994 SourceType: types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY, 995 DestinationType: types.AccountType_ACCOUNT_TYPE_GENERAL, 996 Destination: crypto.RandomHash(), 997 TransferType: types.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING, 998 Amount: "500", 999 Asset: "abcde", 1000 } 1001 for fraction, expectedErr := range expectation { 1002 transfer.FractionOfBalance = fraction 1003 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 1004 Terms: &types.ProposalTerms{ 1005 Change: &types.ProposalTerms_NewTransfer{ 1006 NewTransfer: &types.NewTransfer{ 1007 Changes: transfer, 1008 }, 1009 }, 1010 }, 1011 }) 1012 require.Contains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.fraction_of_balance"), expectedErr) 1013 } 1014 transfer.FractionOfBalance = "0.5" 1015 err := checkProposalSubmission(&commandspb.ProposalSubmission{ 1016 Terms: &types.ProposalTerms{ 1017 Change: &types.ProposalTerms_NewTransfer{ 1018 NewTransfer: &types.NewTransfer{ 1019 Changes: transfer, 1020 }, 1021 }, 1022 }, 1023 }) 1024 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.fraction_of_balance"), commands.ErrMustBePositive) 1025 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.fraction_of_balance"), commands.ErrIsNotValid) 1026 require.NotContains(t, err.Get("proposal_submission.terms.change.new_transfer.changes.fraction_of_balance"), commands.ErrIsRequired) 1027 }