code.vegaprotocol.io/vega@v0.79.0/commands/proposal_submission.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 17 18 import ( 19 "errors" 20 "fmt" 21 "math" 22 "math/big" 23 "strconv" 24 "strings" 25 "time" 26 27 dstypes "code.vegaprotocol.io/vega/core/datasource/common" 28 "code.vegaprotocol.io/vega/core/datasource/external/ethcall" 29 ethcallcommon "code.vegaprotocol.io/vega/core/datasource/external/ethcall/common" 30 "code.vegaprotocol.io/vega/libs/crypto" 31 "code.vegaprotocol.io/vega/libs/num" 32 vegapb "code.vegaprotocol.io/vega/protos/vega" 33 commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" 34 datapb "code.vegaprotocol.io/vega/protos/vega/data/v1" 35 ) 36 37 const ReferenceMaxLen int = 100 38 39 var validFromAccountTypesForPAP = map[vegapb.AccountType]struct{}{ 40 vegapb.AccountType_ACCOUNT_TYPE_BUY_BACK_FEES: {}, 41 } 42 43 var validToAccountTypesForPAP = map[vegapb.AccountType]struct{}{ 44 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE: {}, 45 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD: {}, 46 vegapb.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY: {}, 47 vegapb.AccountType_ACCOUNT_TYPE_BUY_BACK_FEES: {}, 48 } 49 50 var validTransfers = map[vegapb.AccountType]map[vegapb.AccountType]struct{}{ 51 vegapb.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY: { 52 vegapb.AccountType_ACCOUNT_TYPE_GENERAL: {}, 53 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE: {}, 54 vegapb.AccountType_ACCOUNT_TYPE_INSURANCE: {}, 55 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD: {}, 56 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: {}, 57 vegapb.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: {}, 58 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: {}, 59 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: {}, 60 vegapb.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL: {}, 61 vegapb.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN: {}, 62 vegapb.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: {}, 63 vegapb.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: {}, 64 vegapb.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN: {}, 65 vegapb.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES: {}, 66 }, 67 vegapb.AccountType_ACCOUNT_TYPE_INSURANCE: { 68 vegapb.AccountType_ACCOUNT_TYPE_GENERAL: {}, 69 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE: {}, 70 vegapb.AccountType_ACCOUNT_TYPE_INSURANCE: {}, 71 vegapb.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY: {}, 72 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD: {}, 73 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: {}, 74 vegapb.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: {}, 75 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: {}, 76 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: {}, 77 vegapb.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL: {}, 78 vegapb.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN: {}, 79 vegapb.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: {}, 80 vegapb.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: {}, 81 vegapb.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN: {}, 82 vegapb.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES: {}, 83 }, 84 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE: { 85 vegapb.AccountType_ACCOUNT_TYPE_GENERAL: {}, 86 vegapb.AccountType_ACCOUNT_TYPE_INSURANCE: {}, 87 vegapb.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY: {}, 88 vegapb.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD: {}, 89 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: {}, 90 vegapb.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: {}, 91 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: {}, 92 vegapb.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: {}, 93 vegapb.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL: {}, 94 vegapb.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN: {}, 95 vegapb.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: {}, 96 vegapb.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: {}, 97 vegapb.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN: {}, 98 vegapb.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES: {}, 99 }, 100 } 101 102 func CheckProposalSubmission(cmd *commandspb.ProposalSubmission) error { 103 return checkProposalSubmission(cmd).ErrorOrNil() 104 } 105 106 func checkProposalSubmission(cmd *commandspb.ProposalSubmission) Errors { 107 errs := NewErrors() 108 109 if cmd == nil { 110 return errs.FinalAddForProperty("proposal_submission", ErrIsRequired) 111 } 112 113 if len(cmd.Reference) > ReferenceMaxLen { 114 errs.AddForProperty("proposal_submission.reference", ErrReferenceTooLong) 115 } 116 117 if cmd.Rationale == nil { 118 errs.AddForProperty("proposal_submission.rationale", ErrIsRequired) 119 } else { 120 if cmd.Rationale != nil { 121 if len(strings.Trim(cmd.Rationale.Description, " \n\r\t")) == 0 { 122 errs.AddForProperty("proposal_submission.rationale.description", ErrIsRequired) 123 } else if len(cmd.Rationale.Description) > 20000 { 124 errs.AddForProperty("proposal_submission.rationale.description", ErrMustNotExceed20000Chars) 125 } 126 if len(strings.Trim(cmd.Rationale.Title, " \n\r\t")) == 0 { 127 errs.AddForProperty("proposal_submission.rationale.title", ErrIsRequired) 128 } else if len(cmd.Rationale.Title) > 100 { 129 errs.AddForProperty("proposal_submission.rationale.title", ErrMustBeLessThan100Chars) 130 } 131 } 132 } 133 134 if cmd.Terms == nil { 135 return errs.FinalAddForProperty("proposal_submission.terms", ErrIsRequired) 136 } 137 138 if cmd.Terms.ClosingTimestamp <= 0 { 139 errs.AddForProperty("proposal_submission.terms.closing_timestamp", ErrMustBePositive) 140 } 141 142 if cmd.Terms.ValidationTimestamp < 0 { 143 errs.AddForProperty("proposal_submission.terms.validation_timestamp", ErrMustBePositiveOrZero) 144 } 145 146 if cmd.Terms.ValidationTimestamp >= cmd.Terms.ClosingTimestamp { 147 errs.AddForProperty("proposal_submission.terms.validation_timestamp", 148 errors.New("cannot be after or equal to closing time"), 149 ) 150 } 151 152 // check for enactment timestamp 153 switch cmd.Terms.Change.(type) { 154 case *vegapb.ProposalTerms_NewFreeform: 155 if cmd.Terms.EnactmentTimestamp != 0 { 156 errs.AddForProperty("proposal_submission.terms.enactment_timestamp", ErrIsNotSupported) 157 } 158 default: 159 if cmd.Terms.EnactmentTimestamp <= 0 { 160 errs.AddForProperty("proposal_submission.terms.enactment_timestamp", ErrMustBePositive) 161 } 162 163 if cmd.Terms.ClosingTimestamp > cmd.Terms.EnactmentTimestamp { 164 errs.AddForProperty("proposal_submission.terms.closing_timestamp", 165 errors.New("cannot be after enactment time"), 166 ) 167 } 168 } 169 170 // check for validation timestamp 171 switch cmd.Terms.Change.(type) { 172 case *vegapb.ProposalTerms_NewAsset: 173 if cmd.Terms.ValidationTimestamp == 0 { 174 errs.AddForProperty("proposal_submission.terms.validation_timestamp", ErrMustBePositive) 175 } 176 if cmd.Terms.ValidationTimestamp > cmd.Terms.ClosingTimestamp { 177 errs.AddForProperty("proposal_submission.terms.validation_timestamp", 178 errors.New("cannot be after closing time"), 179 ) 180 } 181 default: 182 if cmd.Terms.ValidationTimestamp != 0 { 183 errs.AddForProperty("proposal_submission.terms.validation_timestamp", ErrIsNotSupported) 184 } 185 } 186 187 errs.Merge(checkProposalChanges(cmd.Terms)) 188 189 return errs 190 } 191 192 func checkProposalChanges(terms *vegapb.ProposalTerms) Errors { 193 errs := NewErrors() 194 195 if terms.Change == nil { 196 return errs.FinalAddForProperty("proposal_submission.terms.change", ErrIsRequired) 197 } 198 199 switch c := terms.Change.(type) { 200 case *vegapb.ProposalTerms_NewMarket: 201 errs.Merge(checkNewMarketChanges(c)) 202 case *vegapb.ProposalTerms_UpdateMarket: 203 errs.Merge(checkUpdateMarketChanges(c)) 204 case *vegapb.ProposalTerms_NewSpotMarket: 205 errs.Merge(checkNewSpotMarketChanges(c)) 206 case *vegapb.ProposalTerms_UpdateSpotMarket: 207 errs.Merge(checkUpdateSpotMarketChanges(c)) 208 case *vegapb.ProposalTerms_UpdateNetworkParameter: 209 errs.Merge(checkNetworkParameterUpdateChanges(c)) 210 case *vegapb.ProposalTerms_NewAsset: 211 errs.Merge(checkNewAssetChanges(c)) 212 case *vegapb.ProposalTerms_UpdateAsset: 213 errs.Merge(checkUpdateAssetChanges(c)) 214 case *vegapb.ProposalTerms_NewFreeform: 215 errs.Merge(CheckNewFreeformChanges(c)) 216 case *vegapb.ProposalTerms_NewTransfer: 217 errs.Merge(checkNewTransferChanges(c)) 218 case *vegapb.ProposalTerms_CancelTransfer: 219 errs.Merge(checkCancelTransferChanges(c)) 220 case *vegapb.ProposalTerms_UpdateMarketState: 221 errs.Merge(checkMarketUpdateState(c)) 222 case *vegapb.ProposalTerms_UpdateReferralProgram: 223 errs.Merge(checkUpdateReferralProgram(terms, c)) 224 case *vegapb.ProposalTerms_UpdateVolumeDiscountProgram: 225 errs.Merge(checkVolumeDiscountProgram(terms, c)) 226 case *vegapb.ProposalTerms_UpdateVolumeRebateProgram: 227 errs.Merge(checkVolumeRebateProgram(terms, c)) 228 case *vegapb.ProposalTerms_NewProtocolAutomatedPurchase: 229 errs.Merge(checkAutomatedPurchaseConfig(c)) 230 default: 231 return errs.FinalAddForProperty("proposal_submission.terms.change", ErrIsNotValid) 232 } 233 234 return errs 235 } 236 237 func checkNetworkParameterUpdateChanges(change *vegapb.ProposalTerms_UpdateNetworkParameter) Errors { 238 errs := NewErrors() 239 240 if change.UpdateNetworkParameter == nil { 241 return errs.FinalAddForProperty("proposal_submission.terms.change.update_network_parameter", ErrIsRequired) 242 } 243 244 if change.UpdateNetworkParameter.Changes == nil { 245 return errs.FinalAddForProperty("proposal_submission.terms.change.update_network_parameter.changes", ErrIsRequired) 246 } 247 248 return checkNetworkParameterUpdate(change.UpdateNetworkParameter.Changes).AddPrefix("proposal_submission.terms.change.") 249 } 250 251 func checkNetworkParameterUpdate(parameter *vegapb.NetworkParameter) Errors { 252 errs := NewErrors() 253 254 if len(parameter.Key) == 0 { 255 errs.AddForProperty("update_network_parameter.changes.key", ErrIsRequired) 256 } 257 258 if len(parameter.Value) == 0 { 259 errs.AddForProperty("update_network_parameter.changes.value", ErrIsRequired) 260 } 261 return errs 262 } 263 264 func checkNewAssetChanges(change *vegapb.ProposalTerms_NewAsset) Errors { 265 errs := NewErrors() 266 267 if change.NewAsset == nil { 268 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset", ErrIsRequired) 269 } 270 271 if change.NewAsset.Changes == nil { 272 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes", ErrIsRequired) 273 } 274 275 if len(change.NewAsset.Changes.Name) == 0 { 276 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.name", ErrIsRequired) 277 } 278 if len(change.NewAsset.Changes.Symbol) == 0 { 279 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.symbol", ErrIsRequired) 280 } 281 282 if len(change.NewAsset.Changes.Quantum) <= 0 { 283 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.quantum", ErrIsRequired) 284 } else if quantum, err := num.DecimalFromString(change.NewAsset.Changes.Quantum); err != nil { 285 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.quantum", ErrIsNotValidNumber) 286 } else if quantum.LessThanOrEqual(num.DecimalZero()) { 287 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.quantum", ErrMustBePositive) 288 } 289 290 if change.NewAsset.Changes.Source == nil { 291 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source", ErrIsRequired) 292 } 293 294 switch s := change.NewAsset.Changes.Source.(type) { 295 case *vegapb.AssetDetails_BuiltinAsset: 296 errs.Merge(checkBuiltinAssetSource(s)) 297 case *vegapb.AssetDetails_Erc20: 298 errs.Merge(checkERC20AssetSource(s)) 299 default: 300 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source", ErrIsNotValid) 301 } 302 303 return errs 304 } 305 306 func checkBatchNewAssetChanges(change *vegapb.BatchProposalTermsChange_NewAsset) Errors { 307 errs := NewErrors() 308 309 if change.NewAsset == nil { 310 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset", ErrIsRequired) 311 } 312 313 if change.NewAsset.Changes == nil { 314 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes", ErrIsRequired) 315 } 316 317 if len(change.NewAsset.Changes.Name) == 0 { 318 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.name", ErrIsRequired) 319 } 320 if len(change.NewAsset.Changes.Symbol) == 0 { 321 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.symbol", ErrIsRequired) 322 } 323 324 if len(change.NewAsset.Changes.Quantum) <= 0 { 325 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.quantum", ErrIsRequired) 326 } else if quantum, err := num.DecimalFromString(change.NewAsset.Changes.Quantum); err != nil { 327 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.quantum", ErrIsNotValidNumber) 328 } else if quantum.LessThanOrEqual(num.DecimalZero()) { 329 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.quantum", ErrMustBePositive) 330 } 331 332 if change.NewAsset.Changes.Source == nil { 333 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source", ErrIsRequired) 334 } 335 336 switch s := change.NewAsset.Changes.Source.(type) { 337 case *vegapb.AssetDetails_BuiltinAsset: 338 errs.Merge(checkBuiltinAssetSource(s)) 339 case *vegapb.AssetDetails_Erc20: 340 errs.Merge(checkERC20AssetSource(s)) 341 default: 342 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source", ErrIsNotValid) 343 } 344 345 return errs 346 } 347 348 func CheckNewFreeformChanges(change *vegapb.ProposalTerms_NewFreeform) Errors { 349 errs := NewErrors() 350 351 if change.NewFreeform == nil { 352 return errs.FinalAddForProperty("proposal_submission.terms.change.new_freeform", ErrIsRequired) 353 } 354 return errs 355 } 356 357 func checkCancelTransferChanges(change *vegapb.ProposalTerms_CancelTransfer) Errors { 358 errs := NewErrors() 359 if change.CancelTransfer == nil { 360 return errs.FinalAddForProperty("proposal_submission.terms.change.cancel_transfer", ErrIsRequired) 361 } 362 363 if change.CancelTransfer.Changes == nil { 364 return errs.FinalAddForProperty("proposal_submission.terms.change.cancel_transfer.changes", ErrIsRequired) 365 } 366 367 changes := change.CancelTransfer.Changes 368 if len(changes.TransferId) == 0 { 369 return errs.FinalAddForProperty("proposal_submission.terms.change.cancel_transfer.changes.transferId", ErrIsRequired) 370 } 371 return errs 372 } 373 374 func checkUpdateReferralProgram(terms *vegapb.ProposalTerms, change *vegapb.ProposalTerms_UpdateReferralProgram) Errors { 375 errs := NewErrors() 376 if change.UpdateReferralProgram == nil { 377 return errs.FinalAddForProperty("proposal_submission.terms.change.update_referral_program", ErrIsRequired) 378 } 379 if change.UpdateReferralProgram.Changes == nil { 380 return errs.FinalAddForProperty("proposal_submission.terms.change.update_referral_program.changes", ErrIsRequired) 381 } 382 383 return checkReferralProgramChanges(change.UpdateReferralProgram.Changes, terms.EnactmentTimestamp). 384 AddPrefix("proposal_submission.terms.change.") 385 } 386 387 func checkReferralProgramChanges(changes *vegapb.ReferralProgramChanges, enactmentTimestamp int64) Errors { 388 errs := NewErrors() 389 390 if changes.EndOfProgramTimestamp == 0 { 391 errs.AddForProperty("update_referral_program.changes.end_of_program_timestamp", ErrIsRequired) 392 } else if changes.EndOfProgramTimestamp < 0 { 393 errs.AddForProperty("update_referral_program.changes.end_of_program_timestamp", ErrMustBePositive) 394 } else if changes.EndOfProgramTimestamp < enactmentTimestamp { 395 errs.AddForProperty("update_referral_program.changes.end_of_program_timestamp", ErrMustBeGreaterThanEnactmentTimestamp) 396 } 397 if changes.WindowLength == 0 { 398 errs.AddForProperty("update_referral_program.changes.window_length", ErrIsRequired) 399 } else if changes.WindowLength > 200 { 400 errs.AddForProperty("update_referral_program.changes.window_length", ErrMustBeAtMost200) 401 } 402 403 tiers := map[string]struct{}{} 404 for i, tier := range changes.BenefitTiers { 405 errs.Merge(checkBenefitTier(i, tier)) 406 k := tier.MinimumEpochs + "_" + tier.MinimumRunningNotionalTakerVolume 407 if _, ok := tiers[k]; ok { 408 errs.AddForProperty(fmt.Sprintf("update_referral_program.changes.benefit_tiers.%d", i), fmt.Errorf("duplicate benefit tier")) 409 } 410 tiers[k] = struct{}{} 411 } 412 413 tiers = map[string]struct{}{} 414 for i, tier := range changes.StakingTiers { 415 errs.Merge(checkStakingTier(i, tier)) 416 k := tier.MinimumStakedTokens 417 if _, ok := tiers[k]; ok { 418 errs.AddForProperty(fmt.Sprintf("update_referral_program.changes.staking_tiers.%d", i), fmt.Errorf("duplicate staking tier")) 419 } 420 tiers[k] = struct{}{} 421 } 422 return errs 423 } 424 425 func checkAutomatedPurchaseConfig(newAutoPurchase *vegapb.ProposalTerms_NewProtocolAutomatedPurchase) Errors { 426 errs := NewErrors() 427 if newAutoPurchase.NewProtocolAutomatedPurchase == nil { 428 return errs.FinalAddForProperty("proposal_submission.terms.change.protocol_automated_purchase", ErrIsRequired) 429 } 430 if newAutoPurchase.NewProtocolAutomatedPurchase.Changes == nil { 431 return errs.FinalAddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes", ErrIsRequired) 432 } 433 434 change := newAutoPurchase.NewProtocolAutomatedPurchase.Changes 435 if len(change.From) == 0 { 436 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.from", ErrIsRequired) 437 } 438 439 if change.FromAccountType == vegapb.AccountType_ACCOUNT_TYPE_UNSPECIFIED { 440 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.from_account_type", ErrIsRequired) 441 } 442 if _, ok := validFromAccountTypesForPAP[change.FromAccountType]; !ok { 443 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.from_account_type", ErrIsNotValid) 444 } 445 if change.ToAccountType == vegapb.AccountType_ACCOUNT_TYPE_UNSPECIFIED { 446 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.to_account_type", ErrIsRequired) 447 } 448 if _, ok := validToAccountTypesForPAP[change.ToAccountType]; !ok { 449 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.to_account_type", ErrIsNotValid) 450 } 451 if len(change.MarketId) == 0 { 452 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.market_id", ErrIsRequired) 453 } 454 if change.PriceOracle == nil { 455 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.price_oracle", ErrIsRequired) 456 } else { 457 errs.Merge(checkDataSourceSpec(change.PriceOracle, "data_spec_for_price_oracle", "proposal_submission.terms.change.protocol_automated_purchase.changes", false)) 458 } 459 if len(change.OracleOffsetFactor) == 0 { 460 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor", ErrIsRequired) 461 } else { 462 d, err := num.DecimalFromString(change.OracleOffsetFactor) 463 if err != nil { 464 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor", ErrNotAValidFloat) 465 } else if !d.IsPositive() { 466 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor", ErrMustBePositive) 467 } 468 } 469 if change.AuctionSchedule == nil { 470 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_schedule", ErrIsRequired) 471 } else { 472 switch tp := change.AuctionSchedule.SourceType.(type) { 473 case *vegapb.DataSourceDefinition_External: 474 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_schedule", fmt.Errorf("auction schedule must be an internal time trigger")) 475 case *vegapb.DataSourceDefinition_Internal: 476 switch tp.Internal.SourceType.(type) { 477 case *vegapb.DataSourceDefinitionInternal_Time: 478 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_schedule", fmt.Errorf("auction schedule must be an internal time trigger")) 479 default: 480 } 481 } 482 errs.Merge(checkDataSourceSpec(change.AuctionSchedule, "data_spec_for_auction_schedule", "proposal_submission.terms.change.protocol_automated_purchase.changes", false)) 483 } 484 if len(change.AuctionDuration) == 0 { 485 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_duration", ErrIsRequired) 486 } else { 487 if _, err := time.ParseDuration(change.AuctionDuration); err != nil { 488 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_duration", fmt.Errorf("must be a valid duration")) 489 } 490 } 491 492 if change.AuctionVolumeSnapshotSchedule == nil { 493 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_volume_snapshot_schedule", ErrIsRequired) 494 } else { 495 switch tp := change.AuctionVolumeSnapshotSchedule.SourceType.(type) { 496 case *vegapb.DataSourceDefinition_External: 497 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_volume_snapshot_schedule", fmt.Errorf("auction volume snapshot schedule must be an internal time trigger")) 498 case *vegapb.DataSourceDefinition_Internal: 499 switch tp.Internal.SourceType.(type) { 500 case *vegapb.DataSourceDefinitionInternal_Time: 501 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_volume_snapshot_schedule", fmt.Errorf("auction volume snapshot schedule must be an internal time trigger")) 502 default: 503 } 504 } 505 errs.Merge(checkDataSourceSpec(change.AuctionVolumeSnapshotSchedule, "data_spec_for_auction_volume_snapshot_schedule", "proposal_submission.terms.change.protocol_automated_purchase.changes", false)) 506 } 507 508 var min, max *num.Uint 509 if len(change.MinimumAuctionSize) == 0 { 510 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.minimum_auction_size", ErrIsRequired) 511 } else { 512 minSize, overflow := num.UintFromString(change.MinimumAuctionSize, 10) 513 if overflow || minSize.IsZero() || minSize.IsNegative() { 514 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.minimum_auction_size", ErrMustBePositive) 515 } else { 516 min = minSize 517 } 518 } 519 if len(change.MaximumAuctionSize) == 0 { 520 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size", ErrIsRequired) 521 } else { 522 maxSize, overflow := num.UintFromString(change.MaximumAuctionSize, 10) 523 if overflow || maxSize.IsZero() || maxSize.IsNegative() { 524 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size", ErrMustBePositive) 525 } else { 526 max = maxSize 527 } 528 } 529 if min != nil && max != nil && min.GT(max) { 530 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size", fmt.Errorf("must be greater than or equal to minimum_auction_size")) 531 } 532 if change.ExpiryTimestamp < 0 { 533 errs.AddForProperty("proposal_submission.terms.change.protocol_automated_purchase.changes.expiry_timestamp", ErrMustBePositiveOrZero) 534 } 535 return errs 536 } 537 538 func checkVolumeRebateProgram(terms *vegapb.ProposalTerms, change *vegapb.ProposalTerms_UpdateVolumeRebateProgram) Errors { 539 errs := NewErrors() 540 if change.UpdateVolumeRebateProgram == nil { 541 return errs.FinalAddForProperty("proposal_submission.terms.change.update_volume_rebate_program", ErrIsRequired) 542 } 543 if change.UpdateVolumeRebateProgram.Changes == nil { 544 return errs.FinalAddForProperty("proposal_submission.terms.change.update_volume_rebate_program.changes", ErrIsRequired) 545 } 546 547 return checkVolumeRebateProgramChanges(change.UpdateVolumeRebateProgram.Changes, terms.EnactmentTimestamp). 548 AddPrefix("proposal_submission.terms.change.") 549 } 550 551 func checkVolumeDiscountProgram(terms *vegapb.ProposalTerms, change *vegapb.ProposalTerms_UpdateVolumeDiscountProgram) Errors { 552 errs := NewErrors() 553 if change.UpdateVolumeDiscountProgram == nil { 554 return errs.FinalAddForProperty("proposal_submission.terms.change.update_volume_discount_program", ErrIsRequired) 555 } 556 if change.UpdateVolumeDiscountProgram.Changes == nil { 557 return errs.FinalAddForProperty("proposal_submission.terms.change.update_volume_discount_program.changes", ErrIsRequired) 558 } 559 560 return checkVolumeDiscountProgramChanges(change.UpdateVolumeDiscountProgram.Changes, terms.EnactmentTimestamp). 561 AddPrefix("proposal_submission.terms.change.") 562 } 563 564 func checkVolumeRebateProgramChanges(changes *vegapb.VolumeRebateProgramChanges, enactmentTimestamp int64) Errors { 565 errs := NewErrors() 566 567 if changes.EndOfProgramTimestamp == 0 { 568 errs.AddForProperty("update_volume_rebate_program.changes.end_of_program_timestamp", ErrIsRequired) 569 } else if changes.EndOfProgramTimestamp < 0 { 570 errs.AddForProperty("update_volume_rebate_program.changes.end_of_program_timestamp", ErrMustBePositive) 571 } else if changes.EndOfProgramTimestamp < enactmentTimestamp { 572 errs.AddForProperty("update_volume_rebate_program.changes.end_of_program_timestamp", ErrMustBeGreaterThanEnactmentTimestamp) 573 } 574 if changes.WindowLength == 0 { 575 errs.AddForProperty("update_volume_rebate_program.changes.window_length", ErrIsRequired) 576 } else if changes.WindowLength > 200 { 577 errs.AddForProperty("update_volume_rebate_program.changes.window_length", ErrMustBeAtMost200) 578 } 579 for i, tier := range changes.BenefitTiers { 580 errs.Merge(checkVolumeRebateBenefitTier(i, tier)) 581 } 582 583 return errs 584 } 585 586 func checkVolumeRebateBenefitTier(index int, tier *vegapb.VolumeRebateBenefitTier) Errors { 587 errs := NewErrors() 588 propertyPath := fmt.Sprintf("update_volume_rebate_program.changes.benefit_tiers.%d", index) 589 if len(tier.MinimumPartyMakerVolumeFraction) == 0 { 590 errs.AddForProperty(propertyPath+".minimum_party_maker_volume_fraction", ErrIsRequired) 591 } else { 592 mrtv, err := num.DecimalFromString(tier.MinimumPartyMakerVolumeFraction) 593 if err != nil { 594 errs.AddForProperty(propertyPath+".minimum_party_maker_volume_fraction", ErrIsNotValidNumber) 595 } else if mrtv.IsNegative() || mrtv.IsZero() { 596 errs.AddForProperty(propertyPath+".minimum_party_maker_volume_fraction", ErrMustBePositive) 597 } 598 } 599 if len(tier.AdditionalMakerRebate) == 0 { 600 errs.AddForProperty(propertyPath+".additional_maker_rebate", ErrIsRequired) 601 } else { 602 rdf, err := num.DecimalFromString(tier.AdditionalMakerRebate) 603 if err != nil { 604 errs.AddForProperty(propertyPath+".additional_maker_rebate", ErrIsNotValidNumber) 605 } else if rdf.IsNegative() { 606 errs.AddForProperty(propertyPath+".additional_maker_rebate", ErrMustBePositiveOrZero) 607 } 608 } 609 return errs 610 } 611 612 func checkVolumeDiscountProgramChanges(changes *vegapb.VolumeDiscountProgramChanges, enactmentTimestamp int64) Errors { 613 errs := NewErrors() 614 615 if changes.EndOfProgramTimestamp == 0 { 616 errs.AddForProperty("update_volume_discount_program.changes.end_of_program_timestamp", ErrIsRequired) 617 } else if changes.EndOfProgramTimestamp < 0 { 618 errs.AddForProperty("update_volume_discount_program.changes.end_of_program_timestamp", ErrMustBePositive) 619 } else if changes.EndOfProgramTimestamp < enactmentTimestamp { 620 errs.AddForProperty("update_volume_discount_program.changes.end_of_program_timestamp", ErrMustBeGreaterThanEnactmentTimestamp) 621 } 622 if changes.WindowLength == 0 { 623 errs.AddForProperty("update_volume_discount_program.changes.window_length", ErrIsRequired) 624 } else if changes.WindowLength > 200 { 625 errs.AddForProperty("update_volume_discount_program.changes.window_length", ErrMustBeAtMost200) 626 } 627 for i, tier := range changes.BenefitTiers { 628 errs.Merge(checkVolumeBenefitTier(i, tier)) 629 } 630 631 return errs 632 } 633 634 func checkVolumeBenefitTier(index int, tier *vegapb.VolumeBenefitTier) Errors { 635 errs := NewErrors() 636 propertyPath := fmt.Sprintf("update_volume_discount_program.changes.benefit_tiers.%d", index) 637 if len(tier.MinimumRunningNotionalTakerVolume) == 0 { 638 errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrIsRequired) 639 } else { 640 mrtv, overflow := num.UintFromString(tier.MinimumRunningNotionalTakerVolume, 10) 641 if overflow { 642 errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrIsNotValidNumber) 643 } else if mrtv.IsNegative() || mrtv.IsZero() { 644 errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrMustBePositive) 645 } 646 } 647 if tier.VolumeDiscountFactors == nil { 648 errs.AddForProperty(propertyPath+".volume_discount_factors", ErrIsRequired) 649 } else { 650 rdf, err := num.DecimalFromString(tier.VolumeDiscountFactors.MakerDiscountFactor) 651 if err != nil { 652 errs.AddForProperty(propertyPath+".volume_discount_factors.maker_discount_factor", ErrIsNotValidNumber) 653 } else if rdf.IsNegative() { 654 errs.AddForProperty(propertyPath+".volume_discount_factors.maker_discount_factor", ErrMustBePositiveOrZero) 655 } 656 rdf, err = num.DecimalFromString(tier.VolumeDiscountFactors.LiquidityDiscountFactor) 657 if err != nil { 658 errs.AddForProperty(propertyPath+".volume_discount_factors.liquidity_discount_factor", ErrIsNotValidNumber) 659 } else if rdf.IsNegative() { 660 errs.AddForProperty(propertyPath+".volume_discount_factors.liquidity_discount_factor", ErrMustBePositiveOrZero) 661 } 662 rdf, err = num.DecimalFromString(tier.VolumeDiscountFactors.InfrastructureDiscountFactor) 663 if err != nil { 664 errs.AddForProperty(propertyPath+".volume_discount_factors.infrastructure_discount_factor", ErrIsNotValidNumber) 665 } else if rdf.IsNegative() { 666 errs.AddForProperty(propertyPath+".volume_discount_factors.infrastructure_discount_factor", ErrMustBePositiveOrZero) 667 } 668 } 669 return errs 670 } 671 672 func checkBenefitTier(index int, tier *vegapb.BenefitTier) Errors { 673 errs := NewErrors() 674 675 propertyPath := fmt.Sprintf("update_referral_program.changes.benefit_tiers.%d", index) 676 677 if len(tier.MinimumRunningNotionalTakerVolume) == 0 { 678 errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrIsRequired) 679 } else { 680 mrtv, overflow := num.UintFromString(tier.MinimumRunningNotionalTakerVolume, 10) 681 if overflow { 682 errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrIsNotValidNumber) 683 } else if mrtv.IsNegative() || mrtv.IsZero() { 684 errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrMustBePositive) 685 } 686 } 687 688 if len(tier.MinimumEpochs) == 0 { 689 errs.AddForProperty(propertyPath+".minimum_epochs", ErrIsRequired) 690 } else { 691 me, overflow := num.UintFromString(tier.MinimumEpochs, 10) 692 if overflow { 693 errs.AddForProperty(propertyPath+".minimum_epochs", ErrIsNotValidNumber) 694 } else if me.IsNegative() || me.IsZero() { 695 errs.AddForProperty(propertyPath+".minimum_epochs", ErrMustBePositive) 696 } 697 } 698 699 if tier.ReferralRewardFactors == nil { 700 errs.AddForProperty(propertyPath+".referral_reward_factors", ErrIsRequired) 701 } else { 702 if len(tier.ReferralRewardFactors.InfrastructureRewardFactor) == 0 { 703 errs.AddForProperty(propertyPath+".referral_reward_factors.infrastructure_reward_factor", ErrIsRequired) 704 } else { 705 rrf, err := num.DecimalFromString(tier.ReferralRewardFactors.InfrastructureRewardFactor) 706 if err != nil { 707 errs.AddForProperty(propertyPath+".referral_reward_factors.infrastructure_reward_factor", ErrIsNotValidNumber) 708 } else if rrf.IsNegative() { 709 errs.AddForProperty(propertyPath+".referral_reward_factors.infrastructure_reward_factor", ErrMustBePositiveOrZero) 710 } 711 } 712 if len(tier.ReferralRewardFactors.MakerRewardFactor) == 0 { 713 errs.AddForProperty(propertyPath+".referral_reward_factors.maker_reward_factor", ErrIsRequired) 714 } else { 715 rrf, err := num.DecimalFromString(tier.ReferralRewardFactors.MakerRewardFactor) 716 if err != nil { 717 errs.AddForProperty(propertyPath+".referral_reward_factors.maker_reward_factor", ErrIsNotValidNumber) 718 } else if rrf.IsNegative() { 719 errs.AddForProperty(propertyPath+".referral_reward_factors.maker_reward_factor", ErrMustBePositiveOrZero) 720 } 721 } 722 if len(tier.ReferralRewardFactors.LiquidityRewardFactor) == 0 { 723 errs.AddForProperty(propertyPath+".referral_reward_factors.liquidity_reward_factor", ErrIsRequired) 724 } else { 725 rrf, err := num.DecimalFromString(tier.ReferralRewardFactors.LiquidityRewardFactor) 726 if err != nil { 727 errs.AddForProperty(propertyPath+".referral_reward_factors.liquidity_reward_factor", ErrIsNotValidNumber) 728 } else if rrf.IsNegative() { 729 errs.AddForProperty(propertyPath+".referral_reward_factors.liquidity_reward_factor", ErrMustBePositiveOrZero) 730 } 731 } 732 } 733 734 if tier.ReferralDiscountFactors == nil { 735 errs.AddForProperty(propertyPath+".referral_discount_factors", ErrIsRequired) 736 } else { 737 if len(tier.ReferralDiscountFactors.InfrastructureDiscountFactor) == 0 { 738 errs.AddForProperty(propertyPath+".referral_discount_factors.infrastructure_discount_factor", ErrIsRequired) 739 } else { 740 rrf, err := num.DecimalFromString(tier.ReferralDiscountFactors.InfrastructureDiscountFactor) 741 if err != nil { 742 errs.AddForProperty(propertyPath+".referral_discount_factors.infrastructure_discount_factor", ErrIsNotValidNumber) 743 } else if rrf.IsNegative() { 744 errs.AddForProperty(propertyPath+".referral_discount_factors.infrastructure_discount_factor", ErrMustBePositiveOrZero) 745 } 746 } 747 if len(tier.ReferralDiscountFactors.MakerDiscountFactor) == 0 { 748 errs.AddForProperty(propertyPath+".referral_discount_factors.maker_discount_factor", ErrIsRequired) 749 } else { 750 rrf, err := num.DecimalFromString(tier.ReferralDiscountFactors.MakerDiscountFactor) 751 if err != nil { 752 errs.AddForProperty(propertyPath+".referral_discount_factors.maker_discount_factor", ErrIsNotValidNumber) 753 } else if rrf.IsNegative() { 754 errs.AddForProperty(propertyPath+".referral_discount_factors.maker_discount_factor", ErrMustBePositiveOrZero) 755 } 756 } 757 if len(tier.ReferralDiscountFactors.LiquidityDiscountFactor) == 0 { 758 errs.AddForProperty(propertyPath+".referral_discount_factors.liquidity_discount_factor", ErrIsRequired) 759 } else { 760 rrf, err := num.DecimalFromString(tier.ReferralDiscountFactors.LiquidityDiscountFactor) 761 if err != nil { 762 errs.AddForProperty(propertyPath+".referral_discount_factors.liquidity_discount_factor", ErrIsNotValidNumber) 763 } else if rrf.IsNegative() { 764 errs.AddForProperty(propertyPath+".referral_discount_factors.liquidity_discount_factor", ErrMustBePositiveOrZero) 765 } 766 } 767 } 768 769 return errs 770 } 771 772 func checkStakingTier(index int, tier *vegapb.StakingTier) Errors { 773 errs := NewErrors() 774 775 propertyPath := fmt.Sprintf("update_referral_program.changes.staking_tiers.%d", index) 776 777 if len(tier.MinimumStakedTokens) == 0 { 778 errs.AddForProperty(propertyPath+".minimum_staked_tokens", ErrIsRequired) 779 } else { 780 stakedTokens, overflow := num.UintFromString(tier.MinimumStakedTokens, 10) 781 if overflow { 782 errs.AddForProperty(propertyPath+".minimum_staked_tokens", ErrIsNotValidNumber) 783 } else if stakedTokens.IsNegative() || stakedTokens.IsZero() { 784 errs.AddForProperty(propertyPath+".minimum_staked_tokens", ErrMustBePositive) 785 } 786 } 787 788 if len(tier.ReferralRewardMultiplier) == 0 { 789 errs.AddForProperty(propertyPath+".referral_reward_multiplier", ErrIsRequired) 790 } else { 791 rrm, err := num.DecimalFromString(tier.ReferralRewardMultiplier) 792 if err != nil { 793 errs.AddForProperty(propertyPath+".referral_reward_multiplier", ErrIsNotValidNumber) 794 } else if !rrm.GreaterThanOrEqual(num.DecimalOne()) { 795 errs.AddForProperty(propertyPath+".referral_reward_multiplier", ErrMustBeGTE1) 796 } 797 } 798 799 return errs 800 } 801 802 func checkMarketUpdateState(change *vegapb.ProposalTerms_UpdateMarketState) Errors { 803 errs := NewErrors() 804 if change.UpdateMarketState == nil { 805 return errs.FinalAddForProperty("proposal_submission.terms.change.update_market_state", ErrIsRequired) 806 } 807 if change.UpdateMarketState.Changes == nil { 808 return errs.FinalAddForProperty("proposal_submission.terms.change.update_market_state.changes", ErrIsRequired) 809 } 810 return checkMarketUpdateConfiguration(change.UpdateMarketState.Changes).AddPrefix("proposal_submission.terms.change.") 811 } 812 813 func checkMarketUpdateConfiguration(changes *vegapb.UpdateMarketStateConfiguration) Errors { 814 errs := NewErrors() 815 816 if len(changes.MarketId) == 0 { 817 return errs.FinalAddForProperty("update_market_state.changes.marketId", ErrIsRequired) 818 } 819 if changes.UpdateType == 0 { 820 return errs.FinalAddForProperty("update_market_state.changes.updateType", ErrIsRequired) 821 } 822 // if the update type is not terminate, price must be empty 823 if changes.UpdateType != vegapb.MarketStateUpdateType_MARKET_STATE_UPDATE_TYPE_TERMINATE && changes.Price != nil { 824 return errs.FinalAddForProperty("update_market_state.changes.price", ErrMustBeEmpty) 825 } 826 827 // if termination and price is provided it must be a valid uint 828 if changes.UpdateType == vegapb.MarketStateUpdateType_MARKET_STATE_UPDATE_TYPE_TERMINATE && changes.Price != nil && len(*changes.Price) > 0 { 829 n, overflow := num.UintFromString(*changes.Price, 10) 830 if overflow || n.IsNegative() { 831 return errs.FinalAddForProperty("update_market_state.changes.price", ErrIsNotValid) 832 } 833 } 834 return errs 835 } 836 837 func checkNewTransferChanges(change *vegapb.ProposalTerms_NewTransfer) Errors { 838 errs := NewErrors() 839 if change.NewTransfer == nil { 840 return errs.FinalAddForProperty("proposal_submission.terms.change.new_transfer", ErrIsRequired) 841 } 842 843 if change.NewTransfer.Changes == nil { 844 return errs.FinalAddForProperty("proposal_submission.terms.change.new_transfer.changes", ErrIsRequired) 845 } 846 847 return checkNewTransferConfiguration(change.NewTransfer.Changes).AddPrefix("proposal_submission.terms.change.") 848 } 849 850 func checkNewTransferConfiguration(changes *vegapb.NewTransferConfiguration) Errors { 851 errs := NewErrors() 852 853 if changes.SourceType == vegapb.AccountType_ACCOUNT_TYPE_UNSPECIFIED { 854 return errs.FinalAddForProperty("new_transfer.changes.source_type", ErrIsRequired) 855 } 856 validDest, ok := validTransfers[changes.SourceType] 857 // source account type may be one of the following: 858 if !ok { 859 return errs.FinalAddForProperty("new_transfer.changes.source_type", ErrIsNotValid) 860 } 861 if changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_UNSPECIFIED { 862 return errs.FinalAddForProperty("new_transfer.changes.destination_type", ErrIsRequired) 863 } 864 865 if _, ok := validDest[changes.DestinationType]; !ok { 866 return errs.FinalAddForProperty("new_transfer.changes.destination_type", ErrIsNotValid) 867 } 868 dest := changes.DestinationType 869 870 // party accounts: check pubkey 871 if dest == vegapb.AccountType_ACCOUNT_TYPE_GENERAL && !IsVegaPublicKey(changes.Destination) { 872 errs.AddForProperty("new_transfer.changes.destination", ErrShouldBeAValidVegaPublicKey) 873 } 874 875 // insurance account type requires a source, other sources are global 876 if changes.SourceType == vegapb.AccountType_ACCOUNT_TYPE_INSURANCE { 877 if len(changes.Source) == 0 { 878 return errs.FinalAddForProperty("new_transfer.changes.source", ErrIsNotValid) 879 } 880 // destination == source 881 if dest == changes.SourceType && changes.Source == changes.Destination { 882 return errs.FinalAddForProperty("new_transfer.changes.destination", ErrIsNotValid) 883 } 884 } else if len(changes.Source) > 0 { 885 return errs.FinalAddForProperty("new_transfer.changes.source", ErrIsNotValid) 886 } 887 888 // global destination accounts == no source 889 if (dest == vegapb.AccountType_ACCOUNT_TYPE_GENERAL || 890 dest == vegapb.AccountType_ACCOUNT_TYPE_INSURANCE) && 891 len(changes.Destination) == 0 { 892 return errs.FinalAddForProperty("new_transfer.changes.destination", ErrIsNotValid) 893 } 894 895 if changes.TransferType == vegapb.GovernanceTransferType_GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED { 896 return errs.FinalAddForProperty("new_transfer.changes.transfer_type", ErrIsRequired) 897 } 898 899 if len(changes.Amount) == 0 { 900 return errs.FinalAddForProperty("new_transfer.changes.amount", ErrIsRequired) 901 } 902 903 n, overflow := num.UintFromString(changes.Amount, 10) 904 if overflow || n.IsNegative() { 905 return errs.FinalAddForProperty("new_transfer.changes.amount", ErrIsNotValid) 906 } 907 908 if len(changes.Asset) == 0 { 909 return errs.FinalAddForProperty("new_transfer.changes.asset", ErrIsRequired) 910 } 911 912 if len(changes.FractionOfBalance) == 0 { 913 return errs.FinalAddForProperty("new_transfer.changes.fraction_of_balance", ErrIsRequired) 914 } 915 916 fraction, err := num.DecimalFromString(changes.FractionOfBalance) 917 if err != nil { 918 return errs.FinalAddForProperty("new_transfer.changes.fraction_of_balance", ErrIsNotValid) 919 } 920 if !fraction.IsPositive() { 921 return errs.FinalAddForProperty("new_transfer.changes.fraction_of_balance", ErrMustBePositive) 922 } 923 924 if fraction.GreaterThan(num.DecimalOne()) { 925 return errs.FinalAddForProperty("new_transfer.changes.fraction_of_balance", ErrMustBeLTE1) 926 } 927 928 if oneoff := changes.GetOneOff(); oneoff != nil { 929 if changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES || 930 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES || 931 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES || 932 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS || 933 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_AVERAGE_NOTIONAL || 934 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_RELATIVE_RETURN || 935 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY || 936 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING || 937 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_REALISED_RETURN || 938 changes.DestinationType == vegapb.AccountType_ACCOUNT_TYPE_REWARD_ELIGIBLE_ENTITIES { 939 errs.AddForProperty("new_transfer.changes.destination_type", ErrIsNotValid) 940 } 941 if oneoff.DeliverOn < 0 { 942 return errs.FinalAddForProperty("new_transfer.changes.oneoff.deliveron", ErrMustBePositiveOrZero) 943 } 944 } 945 946 if recurring := changes.GetRecurring(); recurring != nil { 947 if recurring.EndEpoch != nil && *recurring.EndEpoch < recurring.StartEpoch { 948 return errs.FinalAddForProperty("new_transfer.changes.recurring.end_epoch", ErrIsNotValid) 949 } 950 951 if f, ok := big.NewFloat(0).SetString(recurring.Factor); !ok { 952 errs.AddForProperty("new_transfer.changes.recurring.factor", ErrNotAValidFloat) 953 } else { 954 if f.Cmp(big.NewFloat(0)) <= 0 { 955 errs.AddForProperty("new_transfer.changes.recurring.factor", ErrMustBePositive) 956 } 957 } 958 959 if recurring.DispatchStrategy != nil { 960 if len(changes.Destination) > 0 { 961 errs.AddForProperty("new_transfer.changes.destination", ErrIsNotValid) 962 } 963 964 validateDispatchStrategy(changes.DestinationType, recurring.DispatchStrategy, errs, "new_transfer.changes.recurring.dispatch_strategy", "new_transfer.changes.destination_type") 965 } 966 } 967 968 if changes.GetRecurring() == nil && changes.GetOneOff() == nil { 969 return errs.FinalAddForProperty("new_transfer.changes.kind", ErrIsRequired) 970 } 971 972 return errs 973 } 974 975 func checkBuiltinAssetSource(s *vegapb.AssetDetails_BuiltinAsset) Errors { 976 errs := NewErrors() 977 978 if s.BuiltinAsset == nil { 979 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source.builtin_asset", ErrIsRequired) 980 } 981 982 asset := s.BuiltinAsset 983 984 if len(asset.MaxFaucetAmountMint) == 0 { 985 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.builtin_asset.max_faucet_amount_mint", ErrIsRequired) 986 } else { 987 if maxFaucetAmount, ok := big.NewInt(0).SetString(asset.MaxFaucetAmountMint, 10); !ok { 988 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source.builtin_asset.max_faucet_amount_mint", ErrIsNotValidNumber) 989 } else if maxFaucetAmount.Cmp(big.NewInt(0)) <= 0 { 990 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.builtin_asset.max_faucet_amount_mint", ErrMustBePositive) 991 } 992 } 993 994 return errs 995 } 996 997 func checkERC20AssetSource(s *vegapb.AssetDetails_Erc20) Errors { 998 errs := NewErrors() 999 1000 if s.Erc20 == nil { 1001 return errs.FinalAddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20", ErrIsRequired) 1002 } 1003 1004 asset := s.Erc20 1005 1006 if len(asset.ChainId) == 0 { 1007 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.chain_id", ErrIsRequired) 1008 } 1009 1010 if len(asset.ContractAddress) == 0 { 1011 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.contract_address", ErrIsRequired) 1012 } 1013 if len(asset.LifetimeLimit) == 0 { 1014 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.lifetime_limit", ErrIsRequired) 1015 } else { 1016 if lifetimeLimit, ok := big.NewInt(0).SetString(asset.LifetimeLimit, 10); !ok { 1017 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.lifetime_limit", ErrIsNotValidNumber) 1018 } else { 1019 if lifetimeLimit.Cmp(big.NewInt(0)) <= 0 { 1020 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.lifetime_limit", ErrMustBePositive) 1021 } 1022 } 1023 } 1024 if len(asset.WithdrawThreshold) == 0 { 1025 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.withdraw_threshold", ErrIsRequired) 1026 } else { 1027 if withdrawThreshold, ok := big.NewInt(0).SetString(asset.WithdrawThreshold, 10); !ok { 1028 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.withdraw_threshold", ErrIsNotValidNumber) 1029 } else { 1030 if withdrawThreshold.Cmp(big.NewInt(0)) <= 0 { 1031 errs.AddForProperty("proposal_submission.terms.change.new_asset.changes.source.erc20.withdraw_threshold", ErrMustBePositive) 1032 } 1033 } 1034 } 1035 1036 return errs 1037 } 1038 1039 func checkUpdateAssetChanges(change *vegapb.ProposalTerms_UpdateAsset) Errors { 1040 errs := NewErrors() 1041 1042 if change.UpdateAsset == nil { 1043 return errs.FinalAddForProperty("proposal_submission.terms.change.update_asset", ErrIsRequired) 1044 } 1045 1046 return checkUpdateAsset(change.UpdateAsset).AddPrefix("proposal_submission.terms.change.") 1047 } 1048 1049 func checkUpdateAsset(updateAsset *vegapb.UpdateAsset) Errors { 1050 errs := NewErrors() 1051 1052 if len(updateAsset.AssetId) == 0 { 1053 errs.AddForProperty("update_asset.asset_id", ErrIsRequired) 1054 } else if !IsVegaID(updateAsset.AssetId) { 1055 errs.AddForProperty("update_asset.asset_id", ErrShouldBeAValidVegaID) 1056 } 1057 1058 if updateAsset.Changes == nil { 1059 return errs.FinalAddForProperty("update_asset.changes", ErrIsRequired) 1060 } 1061 1062 if len(updateAsset.Changes.Quantum) <= 0 { 1063 errs.AddForProperty("update_asset.changes.quantum", ErrIsRequired) 1064 } else if quantum, err := num.DecimalFromString(updateAsset.Changes.Quantum); err != nil { 1065 errs.AddForProperty("update_asset.changes.quantum", ErrIsNotValidNumber) 1066 } else if quantum.LessThanOrEqual(num.DecimalZero()) { 1067 errs.AddForProperty("update_asset.changes.quantum", ErrMustBePositive) 1068 } 1069 1070 if updateAsset.Changes.Source == nil { 1071 return errs.FinalAddForProperty("update_asset.changes.source", ErrIsRequired) 1072 } 1073 1074 switch s := updateAsset.Changes.Source.(type) { 1075 case *vegapb.AssetDetailsUpdate_Erc20: 1076 errs.Merge(checkERC20UpdateAssetSource(s)) 1077 default: 1078 return errs.FinalAddForProperty("update_asset.changes.source", ErrIsNotValid) 1079 } 1080 1081 return errs 1082 } 1083 1084 func checkERC20UpdateAssetSource(s *vegapb.AssetDetailsUpdate_Erc20) Errors { 1085 errs := NewErrors() 1086 1087 if s.Erc20 == nil { 1088 return errs.FinalAddForProperty("update_asset.changes.source.erc20", ErrIsRequired) 1089 } 1090 1091 asset := s.Erc20 1092 1093 if len(asset.LifetimeLimit) == 0 { 1094 errs.AddForProperty("update_asset.changes.source.erc20.lifetime_limit", ErrIsRequired) 1095 } else { 1096 if lifetimeLimit, ok := big.NewInt(0).SetString(asset.LifetimeLimit, 10); !ok { 1097 errs.AddForProperty("update_asset.changes.source.erc20.lifetime_limit", ErrIsNotValidNumber) 1098 } else { 1099 if lifetimeLimit.Cmp(big.NewInt(0)) <= 0 { 1100 errs.AddForProperty("update_asset.changes.source.erc20.lifetime_limit", ErrMustBePositive) 1101 } 1102 } 1103 } 1104 1105 if len(asset.WithdrawThreshold) == 0 { 1106 errs.AddForProperty("update_asset.changes.source.erc20.withdraw_threshold", ErrIsRequired) 1107 } else { 1108 if withdrawThreshold, ok := big.NewInt(0).SetString(asset.WithdrawThreshold, 10); !ok { 1109 errs.AddForProperty("update_asset.changes.source.erc20.withdraw_threshold", ErrIsNotValidNumber) 1110 } else { 1111 if withdrawThreshold.Cmp(big.NewInt(0)) <= 0 { 1112 errs.AddForProperty("update_asset.changes.source.erc20.withdraw_threshold", ErrMustBePositive) 1113 } 1114 } 1115 } 1116 1117 return errs 1118 } 1119 1120 func checkNewSpotMarketChanges(change *vegapb.ProposalTerms_NewSpotMarket) Errors { 1121 errs := NewErrors() 1122 1123 if change.NewSpotMarket == nil { 1124 return errs.FinalAddForProperty("proposal_submission.terms.change.new_spot_market", ErrIsRequired) 1125 } 1126 1127 if change.NewSpotMarket.Changes == nil { 1128 return errs.FinalAddForProperty("proposal_submission.terms.change.new_spot_market.changes", ErrIsRequired) 1129 } 1130 1131 errs.Merge(checkNewSpotMarketConfiguration(change.NewSpotMarket.Changes).AddPrefix("proposal_submission.terms.change.")) 1132 return errs 1133 } 1134 1135 func checkNewSpotMarketConfiguration(changes *vegapb.NewSpotMarketConfiguration) Errors { 1136 errs := NewErrors() 1137 1138 isCorrectProduct := false 1139 1140 errs.Merge(checkMetadata(changes, "new_market.changes")) 1141 1142 if changes.Instrument == nil { 1143 return errs.FinalAddForProperty("new_spot_market.changes.instrument", ErrIsRequired) 1144 } 1145 1146 if changes.Instrument.Product == nil { 1147 return errs.FinalAddForProperty("new_spot_market.changes.instrument.product", ErrIsRequired) 1148 } 1149 1150 switch changes.Instrument.Product.(type) { 1151 case *vegapb.InstrumentConfiguration_Spot: 1152 isCorrectProduct = true 1153 default: 1154 isCorrectProduct = false 1155 } 1156 1157 if !isCorrectProduct { 1158 return errs.FinalAddForProperty("new_spot_market.changes.instrument.product", ErrIsMismatching) 1159 } 1160 if changes.PriceDecimalPlaces >= 150 { 1161 errs.AddForProperty("new_spot_market.changes.decimal_places", ErrMustBeLessThan150) 1162 } 1163 1164 if changes.SizeDecimalPlaces >= 7 || changes.SizeDecimalPlaces <= -7 { 1165 errs.AddForProperty("new_spot_market.changes.position_decimal_places", ErrMustBeWithinRange7) 1166 } 1167 errs.Merge(checkPriceMonitoring(changes.PriceMonitoringParameters, "new_spot_market.changes")) 1168 errs.Merge(checkTargetStakeParams(changes.TargetStakeParameters, "new_spot_market.changes")) 1169 errs.Merge(checkNewInstrument(changes.Instrument, "new_spot_market.changes.instrument", changes.TickSize)) 1170 errs.Merge(checkNewSpotRiskParameters(changes)) 1171 errs.Merge(checkSLAParams(changes.SlaParams, "new_spot_market.changes.sla_params")) 1172 errs.Merge(checkTickSize(changes.TickSize, "new_spot_market.changes")) 1173 errs.Merge(checkLiquidityFeeSettings(changes.LiquidityFeeSettings, "new_spot_market.changes.liquidity_fee_settings")) 1174 1175 return errs 1176 } 1177 1178 func checkNewMarketChanges(change *vegapb.ProposalTerms_NewMarket) Errors { 1179 errs := NewErrors() 1180 1181 if change.NewMarket == nil { 1182 return errs.FinalAddForProperty("proposal_submission.terms.change.new_market", ErrIsRequired) 1183 } 1184 1185 if change.NewMarket.Changes == nil { 1186 return errs.FinalAddForProperty("proposal_submission.terms.change.new_market.changes", ErrIsRequired) 1187 } 1188 1189 return checkNewMarketChangesConfiguration(change.NewMarket.Changes).AddPrefix("proposal_submission.terms.change.") 1190 } 1191 1192 func checkMetadata( 1193 m interface{ GetMetadata() []string }, 1194 pre string, 1195 ) Errors { 1196 errs := NewErrors() 1197 1198 meta := m.GetMetadata() 1199 1200 if len(meta) > 100 { 1201 errs.AddForProperty(fmt.Sprintf("%s.metadata", pre), ErrMustBeAtMost100) 1202 } 1203 1204 for i, v := range meta { 1205 if len(v) > 2048 { 1206 errs.AddForProperty(fmt.Sprintf("%s.metadata.%d", pre, i), ErrMustBeAtMost2048) 1207 } 1208 } 1209 1210 return errs 1211 } 1212 1213 func checkNewMarketChangesConfiguration(changes *vegapb.NewMarketConfiguration) Errors { 1214 errs := NewErrors() 1215 1216 errs.Merge(checkMetadata(changes, "new_market.changes")) 1217 1218 if changes.DecimalPlaces >= 150 { 1219 errs.AddForProperty("new_market.changes.decimal_places", ErrMustBeLessThan150) 1220 } 1221 1222 if changes.PositionDecimalPlaces >= 7 || changes.PositionDecimalPlaces <= -7 { 1223 errs.AddForProperty("new_market.changes.position_decimal_places", ErrMustBeWithinRange7) 1224 } 1225 1226 if len(changes.LinearSlippageFactor) > 0 { 1227 linearSlippage, err := num.DecimalFromString(changes.LinearSlippageFactor) 1228 if err != nil { 1229 errs.AddForProperty("new_market.changes.linear_slippage_factor", ErrIsNotValidNumber) 1230 } else if linearSlippage.IsNegative() { 1231 errs.AddForProperty("new_market.changes.linear_slippage_factor", ErrMustBePositiveOrZero) 1232 } else if linearSlippage.GreaterThan(num.DecimalFromInt64(1000000)) { 1233 errs.AddForProperty("new_market.changes.linear_slippage_factor", ErrMustBeAtMost1M) 1234 } 1235 } 1236 1237 if successor := changes.Successor; successor != nil { 1238 if len(successor.InsurancePoolFraction) == 0 { 1239 errs.AddForProperty("new_market.changes.successor.insurance_pool_fraction", ErrIsRequired) 1240 } else { 1241 if ipf, err := num.DecimalFromString(successor.InsurancePoolFraction); err != nil { 1242 errs.AddForProperty("new_market.changes.successor.insurance_pool_fraction", ErrIsNotValidNumber) 1243 } else if ipf.IsNegative() || ipf.GreaterThan(num.DecimalFromInt64(1)) { 1244 errs.AddForProperty("new_market.changes.successor.insurance_pool_fraction", ErrMustBeWithinRange01) 1245 } 1246 } 1247 } 1248 1249 errs.Merge(checkLiquidationStrategy(changes.LiquidationStrategy, "new_market.changes")) 1250 errs.Merge(checkPriceMonitoring(changes.PriceMonitoringParameters, "new_market.changes")) 1251 errs.Merge(checkLiquidityMonitoring(changes.LiquidityMonitoringParameters, "new_market.changes")) 1252 errs.Merge(checkNewInstrument(changes.Instrument, "new_market.changes.instrument", changes.TickSize)) 1253 errs.Merge(checkNewRiskParameters(changes)) 1254 errs.Merge(checkSLAParams(changes.LiquiditySlaParameters, "new_market.changes.sla_params")) 1255 errs.Merge(checkLiquidityFeeSettings(changes.LiquidityFeeSettings, "new_market.changes.liquidity_fee_settings")) 1256 errs.Merge(checkCompositePriceConfiguration(changes.MarkPriceConfiguration, "new_market.changes.mark_price_configuration")) 1257 errs.Merge(checkTickSize(changes.TickSize, "new_market.changes")) 1258 1259 return errs 1260 } 1261 1262 func checkTickSize(tickSize string, parent string) Errors { 1263 errs := NewErrors() 1264 1265 if len(tickSize) == 0 { 1266 errs.AddForProperty(fmt.Sprintf("%s.tick_size", parent), ErrIsRequired) 1267 return errs 1268 } 1269 1270 tickSizeU, overflow := num.UintFromString(tickSize, 10) 1271 if overflow { 1272 errs.AddForProperty(fmt.Sprintf("%s.tick_size", parent), ErrNotAValidInteger) 1273 } else if tickSizeU.IsZero() || tickSizeU.IsNegative() { 1274 errs.AddForProperty(fmt.Sprintf("%s.tick_size", parent), ErrMustBePositive) 1275 } 1276 1277 return errs 1278 } 1279 1280 func checkUpdateMarketChanges(change *vegapb.ProposalTerms_UpdateMarket) Errors { 1281 errs := NewErrors() 1282 1283 if change.UpdateMarket == nil { 1284 return errs.FinalAddForProperty("proposal_submission.terms.change.update_market", ErrIsRequired) 1285 } 1286 1287 return checkUpdateMarket(change.UpdateMarket).AddPrefix("proposal_submission.terms.change.") 1288 } 1289 1290 func checkUpdateMarket(updateMarket *vegapb.UpdateMarket) Errors { 1291 errs := NewErrors() 1292 1293 if len(updateMarket.MarketId) == 0 { 1294 errs.AddForProperty("update_market.market_id", ErrIsRequired) 1295 } else if !IsVegaID(updateMarket.MarketId) { 1296 errs.AddForProperty("update_market.market_id", ErrShouldBeAValidVegaID) 1297 } 1298 1299 if updateMarket.Changes == nil { 1300 return errs.FinalAddForProperty("update_market.changes", ErrIsRequired) 1301 } 1302 1303 changes := updateMarket.Changes 1304 1305 if len(changes.LinearSlippageFactor) > 0 { 1306 linearSlippage, err := num.DecimalFromString(changes.LinearSlippageFactor) 1307 if err != nil { 1308 errs.AddForProperty("update_market.changes.linear_slippage_factor", ErrIsNotValidNumber) 1309 } else if linearSlippage.IsNegative() { 1310 errs.AddForProperty("update_market.changes.linear_slippage_factor", ErrMustBePositiveOrZero) 1311 } else if linearSlippage.GreaterThan(num.DecimalFromInt64(1000000)) { 1312 errs.AddForProperty("update_market.changes.linear_slippage_factor", ErrMustBeAtMost1M) 1313 } 1314 } 1315 1316 errs.Merge(checkLiquidationStrategy(changes.LiquidationStrategy, "update_market.changes")) 1317 errs.Merge(checkPriceMonitoring(changes.PriceMonitoringParameters, "update_market.changes")) 1318 errs.Merge(checkLiquidityMonitoring(changes.LiquidityMonitoringParameters, "update_market.changes")) 1319 errs.Merge(checkUpdateInstrument(changes.Instrument)) 1320 errs.Merge(checkUpdateRiskParameters(changes)) 1321 errs.Merge(checkSLAParams(changes.LiquiditySlaParameters, "update_market.changes.sla_params")) 1322 errs.Merge(checkLiquidityFeeSettings(changes.LiquidityFeeSettings, "update_market.changes.liquidity_fee_settings")) 1323 errs.Merge(checkCompositePriceConfiguration(changes.MarkPriceConfiguration, "update_market.changes.mark_price_configuration")) 1324 errs.Merge(checkTickSize(changes.TickSize, "update_market.changes")) 1325 return errs 1326 } 1327 1328 func checkUpdateSpotMarketChanges(change *vegapb.ProposalTerms_UpdateSpotMarket) Errors { 1329 errs := NewErrors() 1330 1331 if change.UpdateSpotMarket == nil { 1332 return errs.FinalAddForProperty("proposal_submission.terms.change.update_spot_market", ErrIsRequired) 1333 } 1334 return checkUpdateSpotMarket(change.UpdateSpotMarket).AddPrefix("proposal_submission.terms.change.") 1335 } 1336 1337 func checkUpdateSpotMarket(updateSpotMarket *vegapb.UpdateSpotMarket) Errors { 1338 errs := NewErrors() 1339 1340 if len(updateSpotMarket.MarketId) == 0 { 1341 errs.AddForProperty("update_spot_market.market_id", ErrIsRequired) 1342 } else if !IsVegaID(updateSpotMarket.MarketId) { 1343 errs.AddForProperty("update_spot_market.market_id", ErrShouldBeAValidVegaID) 1344 } 1345 1346 if updateSpotMarket.Changes == nil { 1347 return errs.FinalAddForProperty("update_spot_market.changes", ErrIsRequired) 1348 } 1349 1350 changes := updateSpotMarket.Changes 1351 errs.Merge(checkUpdateSpotInstrument(changes.Instrument).AddPrefix("proposal_submission.terms.change.")) 1352 errs.Merge(checkPriceMonitoring(changes.PriceMonitoringParameters, "update_spot_market.changes")) 1353 errs.Merge(checkTargetStakeParams(changes.TargetStakeParameters, "update_spot_market.changes")) 1354 errs.Merge(checkUpdateSpotRiskParameters(changes)) 1355 errs.Merge(checkSLAParams(changes.SlaParams, "update_spot_market.changes.sla_params")) 1356 errs.Merge(checkTickSize(changes.TickSize, "update_spot_market.changes")) 1357 errs.Merge(checkLiquidityFeeSettings(changes.LiquidityFeeSettings, "update_spot_market.changes.liquidity_fee_settings")) 1358 return errs 1359 } 1360 1361 func checkPriceMonitoring(parameters *vegapb.PriceMonitoringParameters, parentProperty string) Errors { 1362 errs := NewErrors() 1363 1364 if parameters == nil || len(parameters.Triggers) == 0 { 1365 return errs 1366 } 1367 1368 if len(parameters.Triggers) > 100 { 1369 errs.AddForProperty(fmt.Sprintf("%s.price_monitoring_parameters.triggers", parentProperty), errors.New("maximum 100 triggers allowed")) 1370 } 1371 1372 for i, trigger := range parameters.Triggers { 1373 if trigger.Horizon <= 0 { 1374 errs.AddForProperty(fmt.Sprintf("%s.price_monitoring_parameters.triggers.%d.horizon", parentProperty, i), ErrMustBePositive) 1375 } 1376 if trigger.AuctionExtension <= 0 { 1377 errs.AddForProperty(fmt.Sprintf("%s.price_monitoring_parameters.triggers.%d.auction_extension", parentProperty, i), ErrMustBePositive) 1378 } 1379 1380 probability, err := strconv.ParseFloat(trigger.Probability, 64) 1381 if err != nil { 1382 errs.AddForProperty(fmt.Sprintf("%s.price_monitoring_parameters.triggers.%d.probability", parentProperty, i), 1383 errors.New("must be numeric and be between 0 (exclusive) and 1 (exclusive)"), 1384 ) 1385 } 1386 1387 if probability <= 0.9 || probability >= 1 { 1388 errs.AddForProperty(fmt.Sprintf("%s.price_monitoring_parameters.triggers.%d.probability", parentProperty, i), 1389 errors.New("should be between 0.9 (exclusive) and 1 (exclusive)"), 1390 ) 1391 } 1392 } 1393 1394 return errs 1395 } 1396 1397 func checkLiquidationStrategy(params *vegapb.LiquidationStrategy, parent string) Errors { 1398 errs := NewErrors() 1399 if params == nil { 1400 // @TODO these will be required, in that case the check for nil should be removed 1401 // or return an error. 1402 return errs 1403 } 1404 dispFrac, err := num.DecimalFromString(params.DisposalFraction) 1405 if err != nil || dispFrac.IsNegative() || dispFrac.IsZero() || dispFrac.GreaterThan(num.DecimalOne()) { 1406 errs.AddForProperty(fmt.Sprintf("%s.liquidation_strategy.disposal_fraction", parent), ErrMustBeBetween01) 1407 } 1408 maxFrac, err := num.DecimalFromString(params.MaxFractionConsumed) 1409 if err != nil || maxFrac.IsNegative() || maxFrac.IsZero() || maxFrac.GreaterThan(num.DecimalOne()) { 1410 errs.AddForProperty(fmt.Sprintf("%s.liquidation_strategy.max_fraction_consumed", parent), ErrMustBeBetween01) 1411 } 1412 if params.DisposalTimeStep < 1 { 1413 errs.AddForProperty(fmt.Sprintf("%s.liquidation_strategy.disposal_time_step", parent), ErrMustBePositive) 1414 } else if params.DisposalTimeStep > 3600 { 1415 errs.AddForProperty(fmt.Sprintf("%s.liquidation_strategy.disposal_time_step", parent), ErrMustBeAtMost3600) 1416 } 1417 slippage, err := num.DecimalFromString(params.DisposalSlippageRange) 1418 if err != nil || slippage.IsNegative() || slippage.IsZero() { 1419 errs.AddForProperty(fmt.Sprintf("%s.liquidation_strategy.disposal_slippage_range", parent), ErrMustBePositive) 1420 } 1421 return errs 1422 } 1423 1424 func checkLiquidityMonitoring(parameters *vegapb.LiquidityMonitoringParameters, parentProperty string) Errors { 1425 errs := NewErrors() 1426 1427 if parameters == nil { 1428 return errs.FinalAddForProperty(fmt.Sprintf("%s.liquidity_monitoring_parameters", parentProperty), ErrIsRequired) 1429 } 1430 1431 if parameters.TargetStakeParameters == nil { 1432 return errs.FinalAddForProperty(fmt.Sprintf("%s.liquidity_monitoring_parameters.target_stake_parameters", parentProperty), ErrIsRequired) 1433 } 1434 1435 if parameters.TargetStakeParameters.TimeWindow <= 0 { 1436 errs.AddForProperty(fmt.Sprintf("%s.liquidity_monitoring_parameters.target_stake_parameters.time_window", parentProperty), ErrMustBePositive) 1437 } 1438 if parameters.TargetStakeParameters.ScalingFactor <= 0 { 1439 errs.AddForProperty(fmt.Sprintf("%s.liquidity_monitoring_parameters.target_stake_parameters.scaling_factor", parentProperty), ErrMustBePositive) 1440 } 1441 return errs 1442 } 1443 1444 func checkTargetStakeParams(targetStakeParameters *vegapb.TargetStakeParameters, parentProperty string) Errors { 1445 errs := NewErrors() 1446 if targetStakeParameters == nil { 1447 return errs.FinalAddForProperty(fmt.Sprintf("%s.target_stake_parameters", parentProperty), ErrIsRequired) 1448 } 1449 1450 if targetStakeParameters.TimeWindow <= 0 { 1451 errs.AddForProperty(fmt.Sprintf("%s.target_stake_parameters.time_window", parentProperty), ErrMustBePositive) 1452 } 1453 if targetStakeParameters.ScalingFactor <= 0 { 1454 errs.AddForProperty(fmt.Sprintf("%s.target_stake_parameters.scaling_factor", parentProperty), ErrMustBePositive) 1455 } 1456 return errs 1457 } 1458 1459 func checkNewInstrument(instrument *vegapb.InstrumentConfiguration, parent, tickSize string) Errors { 1460 errs := NewErrors() 1461 1462 if instrument == nil { 1463 return errs.FinalAddForProperty(parent, ErrIsRequired) 1464 } 1465 1466 if len(instrument.Name) == 0 { 1467 errs.AddForProperty(fmt.Sprintf("%s.name", parent), ErrIsRequired) 1468 } 1469 if len(instrument.Code) == 0 { 1470 errs.AddForProperty(fmt.Sprintf("%s.code", parent), ErrIsRequired) 1471 } 1472 1473 if instrument.Product == nil { 1474 return errs.FinalAddForProperty(fmt.Sprintf("%s.product", parent), ErrIsRequired) 1475 } 1476 1477 switch product := instrument.Product.(type) { 1478 case *vegapb.InstrumentConfiguration_Future: 1479 errs.Merge(checkNewFuture(product.Future, tickSize)) 1480 case *vegapb.InstrumentConfiguration_Perpetual: 1481 errs.Merge(checkNewPerps(product.Perpetual, fmt.Sprintf("%s.product", parent))) 1482 case *vegapb.InstrumentConfiguration_Spot: 1483 errs.Merge(checkNewSpot(product.Spot)) 1484 default: 1485 return errs.FinalAddForProperty(fmt.Sprintf("%s.product", parent), ErrIsNotValid) 1486 } 1487 1488 return errs 1489 } 1490 1491 func checkUpdateSpotInstrument(instrument *vegapb.UpdateSpotInstrumentConfiguration) Errors { 1492 errs := NewErrors() 1493 if instrument == nil { 1494 return errs.FinalAddForProperty("update_spot_market.changes.instrument", ErrIsRequired) 1495 } 1496 if len(instrument.Code) == 0 { 1497 errs.AddForProperty("update_spot_market.changes.instrument.code", ErrIsRequired) 1498 } 1499 1500 if len(instrument.Name) == 0 { 1501 errs.AddForProperty("update_spot_market.changes.instrument.name", ErrIsRequired) 1502 } 1503 return errs 1504 } 1505 1506 func checkUpdateInstrument(instrument *vegapb.UpdateInstrumentConfiguration) Errors { 1507 errs := NewErrors() 1508 1509 if instrument == nil { 1510 return errs.FinalAddForProperty("update_market.changes.instrument", ErrIsRequired) 1511 } 1512 1513 if len(instrument.Code) == 0 { 1514 errs.AddForProperty("update_market.changes.instrument.code", ErrIsRequired) 1515 } 1516 1517 if len(instrument.Name) == 0 { 1518 errs.AddForProperty("update_market.changes.instrument.name", ErrIsRequired) 1519 } 1520 1521 if instrument.Product == nil { 1522 return errs.FinalAddForProperty("update_market.changes.instrument.product", ErrIsRequired) 1523 } 1524 1525 switch product := instrument.Product.(type) { 1526 case *vegapb.UpdateInstrumentConfiguration_Future: 1527 errs.Merge(checkUpdateFuture(product.Future)) 1528 case *vegapb.UpdateInstrumentConfiguration_Perpetual: 1529 errs.Merge(checkUpdatePerps(product.Perpetual, "update_market.changes.instrument.product")) 1530 default: 1531 return errs.FinalAddForProperty("update_market.changes.instrument.product", ErrIsNotValid) 1532 } 1533 1534 return errs 1535 } 1536 1537 func checkNewFuture(future *vegapb.FutureProduct, tickSize string) Errors { 1538 errs := NewErrors() 1539 1540 if future == nil { 1541 return errs.FinalAddForProperty("new_market.changes.instrument.product.future", ErrIsRequired) 1542 } 1543 1544 if len(future.SettlementAsset) == 0 { 1545 errs.AddForProperty("new_market.changes.instrument.product.future.settlement_asset", ErrIsRequired) 1546 } 1547 if len(future.QuoteName) == 0 { 1548 errs.AddForProperty("new_market.changes.instrument.product.future.quote_name", ErrIsRequired) 1549 } 1550 1551 if future.Cap != nil { 1552 // convert to uint to ensure input is valid 1553 if len(future.Cap.MaxPrice) == 0 { 1554 errs.AddForProperty("new_market.changes.instrument.product.future.cap.max_price", ErrIsRequired) 1555 } else { 1556 // tick size is validated later on, ignore errors here 1557 tick, _ := num.UintFromString(tickSize, 10) 1558 if tick.IsZero() { 1559 tick = num.UintOne() 1560 } 1561 mp, err := num.UintFromString(future.Cap.MaxPrice, 10) 1562 if err || mp.IsZero() { 1563 errs.AddForProperty("new_market.changes.instrument.product.future.cap.max_price", ErrMustBePositive) 1564 } else if !mp.Mod(mp, tick).IsZero() { 1565 errs.AddForProperty("new_market.changes.instrument.product.future.cap.max_price", ErrMaxPriceMustRespectTickSize) 1566 } 1567 } 1568 } 1569 1570 errs.Merge(checkDataSourceSpec(future.DataSourceSpecForSettlementData, "data_source_spec_for_settlement_data", "new_market.changes.instrument.product.future", true)) 1571 errs.Merge(checkDataSourceSpec(future.DataSourceSpecForTradingTermination, "data_source_spec_for_trading_termination", "new_market.changes.instrument.product.future", false)) 1572 errs.Merge(checkNewOracleBinding(future)) 1573 1574 return errs 1575 } 1576 1577 func checkNewPerps(perps *vegapb.PerpetualProduct, parentProperty string) Errors { 1578 errs := NewErrors() 1579 1580 if perps == nil { 1581 return errs.FinalAddForProperty(fmt.Sprintf("%s.perps", parentProperty), ErrIsRequired) 1582 } 1583 1584 if len(perps.SettlementAsset) == 0 { 1585 errs.AddForProperty(fmt.Sprintf("%s.perps.settlement_asset", parentProperty), ErrIsRequired) 1586 } 1587 if len(perps.QuoteName) == 0 { 1588 errs.AddForProperty(fmt.Sprintf("%s.perps.quote_name", parentProperty), ErrIsRequired) 1589 } 1590 1591 if len(perps.MarginFundingFactor) <= 0 { 1592 errs.AddForProperty(fmt.Sprintf("%s.perps.margin_funding_factor", parentProperty), ErrIsRequired) 1593 } else { 1594 mff, err := num.DecimalFromString(perps.MarginFundingFactor) 1595 if err != nil { 1596 errs.AddForProperty(fmt.Sprintf("%s.perps.margin_funding_factor", parentProperty), ErrIsNotValidNumber) 1597 } else if mff.IsNegative() || mff.GreaterThan(num.DecimalOne()) { 1598 errs.AddForProperty(fmt.Sprintf("%s.perps.margin_funding_factor", parentProperty), ErrMustBeWithinRange01) 1599 } 1600 } 1601 1602 if len(perps.InterestRate) <= 0 { 1603 errs.AddForProperty(fmt.Sprintf("%s.perps.interest_rate", parentProperty), ErrIsRequired) 1604 } else { 1605 mff, err := num.DecimalFromString(perps.InterestRate) 1606 if err != nil { 1607 errs.AddForProperty(fmt.Sprintf("%s.perps.interest_rate", parentProperty), ErrIsNotValidNumber) 1608 } else if mff.LessThan(num.MustDecimalFromString("-1")) || mff.GreaterThan(num.DecimalOne()) { 1609 errs.AddForProperty(fmt.Sprintf("%s.perps.interest_rate", parentProperty), ErrMustBeWithinRange11) 1610 } 1611 } 1612 1613 var ( 1614 okClampLowerBound, okClampUpperBound bool 1615 clampLowerBound, clampUpperBound num.Decimal 1616 err error 1617 ) 1618 1619 if len(perps.ClampLowerBound) <= 0 { 1620 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_lower_bound", parentProperty), ErrIsRequired) 1621 } else { 1622 clampLowerBound, err = num.DecimalFromString(perps.ClampLowerBound) 1623 if err != nil { 1624 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_lower_bound", parentProperty), ErrIsNotValidNumber) 1625 } else if clampLowerBound.LessThan(num.MustDecimalFromString("-1")) || clampLowerBound.GreaterThan(num.DecimalOne()) { 1626 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_lower_bound", parentProperty), ErrMustBeWithinRange11) 1627 } else { 1628 okClampLowerBound = true 1629 } 1630 } 1631 1632 if len(perps.ClampUpperBound) <= 0 { 1633 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrIsRequired) 1634 } else { 1635 clampUpperBound, err = num.DecimalFromString(perps.ClampUpperBound) 1636 if err != nil { 1637 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrIsNotValidNumber) 1638 } else if clampUpperBound.LessThan(num.MustDecimalFromString("-1")) || clampUpperBound.GreaterThan(num.DecimalOne()) { 1639 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrMustBeWithinRange11) 1640 } else { 1641 okClampUpperBound = true 1642 } 1643 } 1644 1645 if okClampLowerBound && okClampUpperBound && clampUpperBound.LessThan(clampLowerBound) { 1646 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrMustBeGTEClampLowerBound) 1647 } 1648 1649 if perps.FundingRateScalingFactor != nil { 1650 sf, err := num.DecimalFromString(*perps.FundingRateScalingFactor) 1651 if err != nil { 1652 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_scaling_factor", parentProperty), ErrIsNotValidNumber) 1653 } 1654 if sf.IsNegative() { 1655 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_scaling_factor", parentProperty), ErrMustBePositiveOrZero) 1656 } 1657 } 1658 1659 var lowerBound, upperBound num.Decimal 1660 if perps.FundingRateLowerBound != nil { 1661 if lowerBound, err = num.DecimalFromString(*perps.FundingRateLowerBound); err != nil { 1662 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_lower_bound", parentProperty), ErrIsNotValidNumber) 1663 } 1664 } 1665 1666 if perps.FundingRateUpperBound != nil { 1667 if upperBound, err = num.DecimalFromString(*perps.FundingRateUpperBound); err != nil { 1668 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_upper_bound", parentProperty), ErrIsNotValidNumber) 1669 } 1670 } 1671 1672 if perps.FundingRateLowerBound != nil && perps.FundingRateUpperBound != nil { 1673 if lowerBound.GreaterThan(upperBound) { 1674 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_lower_bound", parentProperty), ErrIsNotValid) 1675 } 1676 } 1677 1678 errs.Merge(checkDataSourceSpec(perps.DataSourceSpecForSettlementData, "data_source_spec_for_settlement_data", fmt.Sprintf("%s.perps", parentProperty), true)) 1679 errs.Merge(checkDataSourceSpec(perps.DataSourceSpecForSettlementSchedule, "data_source_spec_for_settlement_schedule", fmt.Sprintf("%s.perps", parentProperty), true)) 1680 errs.Merge(checkNewPerpsOracleBinding(perps)) 1681 1682 if perps.InternalCompositePriceConfiguration != nil { 1683 errs.Merge(checkCompositePriceConfiguration(perps.InternalCompositePriceConfiguration, fmt.Sprintf("%s.perps.internal_composite_price_configuration", parentProperty))) 1684 } 1685 1686 return errs 1687 } 1688 1689 func checkNewSpot(spot *vegapb.SpotProduct) Errors { 1690 errs := NewErrors() 1691 1692 if spot == nil { 1693 return errs.FinalAddForProperty("new_spot_market.changes.instrument.product.spot", ErrIsRequired) 1694 } 1695 1696 if len(spot.BaseAsset) == 0 { 1697 errs.AddForProperty("new_spot_market.changes.instrument.product.spot.base_asset", ErrIsRequired) 1698 } 1699 if len(spot.QuoteAsset) == 0 { 1700 errs.AddForProperty("new_spot_market.changes.instrument.product.spot.quote_asset", ErrIsRequired) 1701 } 1702 if spot.BaseAsset == spot.QuoteAsset { 1703 errs.AddForProperty("new_spot_market.changes.instrument.product.spot.quote_asset", ErrIsNotValid) 1704 } 1705 1706 return errs 1707 } 1708 1709 func checkUpdateFuture(future *vegapb.UpdateFutureProduct) Errors { 1710 errs := NewErrors() 1711 1712 if future == nil { 1713 return errs.FinalAddForProperty("update_market.changes.instrument.product.future", ErrIsRequired) 1714 } 1715 1716 if len(future.QuoteName) == 0 { 1717 errs.AddForProperty("update_market.changes.instrument.product.future.quote_name", ErrIsRequired) 1718 } 1719 1720 errs.Merge(checkDataSourceSpec(future.DataSourceSpecForSettlementData, "data_source_spec_for_settlement_data", "update_market.changes.instrument.product.future", true)) 1721 errs.Merge(checkDataSourceSpec(future.DataSourceSpecForTradingTermination, "data_source_spec_for_trading_termination", "update_market.changes.instrument.product.future", false)) 1722 errs.Merge(checkUpdateOracleBinding(future)) 1723 1724 return errs 1725 } 1726 1727 func checkUpdatePerps(perps *vegapb.UpdatePerpetualProduct, parentProperty string) Errors { 1728 errs := NewErrors() 1729 1730 if perps == nil { 1731 return errs.FinalAddForProperty(fmt.Sprintf("%s.perps", parentProperty), ErrIsRequired) 1732 } 1733 1734 if len(perps.QuoteName) == 0 { 1735 errs.AddForProperty(fmt.Sprintf("%s.perps.quote_name", parentProperty), ErrIsRequired) 1736 } 1737 1738 if len(perps.MarginFundingFactor) <= 0 { 1739 errs.AddForProperty(fmt.Sprintf("%s.perps.margin_funding_factor", parentProperty), ErrIsRequired) 1740 } else { 1741 mff, err := num.DecimalFromString(perps.MarginFundingFactor) 1742 if err != nil { 1743 errs.AddForProperty(fmt.Sprintf("%s.perps.margin_funding_factor", parentProperty), ErrIsNotValidNumber) 1744 } else if mff.IsNegative() || mff.GreaterThan(num.DecimalOne()) { 1745 errs.AddForProperty(fmt.Sprintf("%s.perps.margin_funding_factor", parentProperty), ErrMustBeWithinRange01) 1746 } 1747 } 1748 1749 if len(perps.InterestRate) <= 0 { 1750 errs.AddForProperty(fmt.Sprintf("%s.perps.interest_rate", parentProperty), ErrIsRequired) 1751 } else { 1752 mff, err := num.DecimalFromString(perps.InterestRate) 1753 if err != nil { 1754 errs.AddForProperty(fmt.Sprintf("%s.perps.interest_rate", parentProperty), ErrIsNotValidNumber) 1755 } else if mff.LessThan(num.MustDecimalFromString("-1")) || mff.GreaterThan(num.DecimalOne()) { 1756 errs.AddForProperty(fmt.Sprintf("%s.perps.interest_rate", parentProperty), ErrMustBeWithinRange11) 1757 } 1758 } 1759 1760 var ( 1761 okClampLowerBound, okClampUpperBound bool 1762 clampLowerBound, clampUpperBound num.Decimal 1763 err error 1764 ) 1765 1766 if len(perps.ClampLowerBound) <= 0 { 1767 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_lower_bound", parentProperty), ErrIsRequired) 1768 } else { 1769 clampLowerBound, err = num.DecimalFromString(perps.ClampLowerBound) 1770 if err != nil { 1771 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_lower_bound", parentProperty), ErrIsNotValidNumber) 1772 } else if clampLowerBound.LessThan(num.MustDecimalFromString("-1")) || clampLowerBound.GreaterThan(num.DecimalOne()) { 1773 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_lower_bound", parentProperty), ErrMustBeWithinRange11) 1774 } else { 1775 okClampLowerBound = true 1776 } 1777 } 1778 1779 if len(perps.ClampUpperBound) <= 0 { 1780 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrIsRequired) 1781 } else { 1782 clampUpperBound, err = num.DecimalFromString(perps.ClampUpperBound) 1783 if err != nil { 1784 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrIsNotValidNumber) 1785 } else if clampUpperBound.LessThan(num.MustDecimalFromString("-1")) || clampUpperBound.GreaterThan(num.DecimalOne()) { 1786 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrMustBeWithinRange11) 1787 } else { 1788 okClampUpperBound = true 1789 } 1790 } 1791 1792 if okClampLowerBound && okClampUpperBound && clampUpperBound.LessThan(clampLowerBound) { 1793 errs.AddForProperty(fmt.Sprintf("%s.perps.clamp_upper_bound", parentProperty), ErrMustBeGTEClampLowerBound) 1794 } 1795 1796 if perps.FundingRateScalingFactor != nil { 1797 sf, err := num.DecimalFromString(*perps.FundingRateScalingFactor) 1798 if err != nil { 1799 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_scaling_factor", parentProperty), ErrIsNotValidNumber) 1800 } 1801 if sf.IsNegative() { 1802 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_scaling_factor", parentProperty), ErrMustBePositiveOrZero) 1803 } 1804 } 1805 1806 var lowerBound, upperBound num.Decimal 1807 if perps.FundingRateLowerBound != nil { 1808 if lowerBound, err = num.DecimalFromString(*perps.FundingRateLowerBound); err != nil { 1809 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_lower_bound", parentProperty), ErrIsNotValidNumber) 1810 } 1811 } 1812 1813 if perps.FundingRateUpperBound != nil { 1814 if upperBound, err = num.DecimalFromString(*perps.FundingRateUpperBound); err != nil { 1815 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_upper_bound", parentProperty), ErrIsNotValidNumber) 1816 } 1817 } 1818 1819 if perps.FundingRateLowerBound != nil && perps.FundingRateUpperBound != nil { 1820 if lowerBound.GreaterThan(upperBound) { 1821 errs.AddForProperty(fmt.Sprintf("%s.perps.funding_rate_lower_bound", parentProperty), ErrIsNotValid) 1822 } 1823 } 1824 1825 errs.Merge(checkDataSourceSpec(perps.DataSourceSpecForSettlementData, "data_source_spec_for_settlement_data", "proposal_submission.terms.change.update_market.changes.instrument.product.future", true)) 1826 errs.Merge(checkDataSourceSpec(perps.DataSourceSpecForSettlementSchedule, "data_source_spec_for_settlement_schedule", "proposal_submission.terms.change.new_market.changes.instrument.product.perps", true)) 1827 errs.Merge(checkUpdatePerpsOracleBinding(perps)) 1828 1829 if perps.InternalCompositePriceConfiguration != nil { 1830 errs.Merge(checkCompositePriceConfiguration(perps.InternalCompositePriceConfiguration, fmt.Sprintf("%s.perps.internal_composite_price_configuration", parentProperty))) 1831 } 1832 1833 return errs 1834 } 1835 1836 func checkDataSourceSpec(spec *vegapb.DataSourceDefinition, name string, parentProperty string, tryToSettle bool, 1837 ) Errors { 1838 errs := NewErrors() 1839 if spec == nil { 1840 return errs.FinalAddForProperty(fmt.Sprintf("%s.%s", parentProperty, name), ErrIsRequired) 1841 } 1842 1843 if spec.SourceType == nil { 1844 return errs.FinalAddForProperty(fmt.Sprintf("%s.%s", parentProperty, name+".source_type"), ErrIsRequired) 1845 } 1846 1847 switch tp := spec.SourceType.(type) { 1848 case *vegapb.DataSourceDefinition_Internal: 1849 switch tp.Internal.SourceType.(type) { 1850 case *vegapb.DataSourceDefinitionInternal_Time: 1851 if tryToSettle { 1852 return errs.FinalAddForProperty(fmt.Sprintf("%s.%s", parentProperty, name), ErrIsNotValid) 1853 } 1854 1855 t := tp.Internal.GetTime() 1856 if t != nil { 1857 if len(t.Conditions) == 0 { 1858 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.time.conditions", parentProperty, name), ErrIsRequired) 1859 } 1860 1861 if len(t.Conditions) != 0 { 1862 for j, condition := range t.Conditions { 1863 if len(condition.Value) == 0 { 1864 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.time.conditions.%d.value", parentProperty, name, j), ErrIsRequired) 1865 } 1866 if condition.Operator == datapb.Condition_OPERATOR_UNSPECIFIED { 1867 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.time.conditions.%d.operator", parentProperty, name, j), ErrIsRequired) 1868 } 1869 1870 if _, ok := datapb.Condition_Operator_name[int32(condition.Operator)]; !ok { 1871 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.time.conditions.%d.operator", parentProperty, name, j), ErrIsNotValid) 1872 } 1873 } 1874 } 1875 } else { 1876 return errs.FinalAddForProperty(fmt.Sprintf("%s.%s.internal.time", parentProperty, name), ErrIsRequired) 1877 } 1878 1879 case *vegapb.DataSourceDefinitionInternal_TimeTrigger: 1880 spl := strings.Split(parentProperty, ".") 1881 if spl[len(spl)-1] == "future" { 1882 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.timetrigger", parentProperty, name), ErrIsNotValid) 1883 } 1884 1885 t := tp.Internal.GetTimeTrigger() 1886 if len(t.Triggers) != 1 { 1887 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.timetrigger", parentProperty, name), ErrOneTimeTriggerAllowedMax) 1888 } else { 1889 for i, v := range t.Triggers { 1890 if v.Initial != nil && *v.Initial <= 0 { 1891 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.timetrigger.triggers.%d.initial", parentProperty, name, i), ErrIsNotValid) 1892 } 1893 if v.Every <= 0 { 1894 errs.AddForProperty(fmt.Sprintf("%s.%s.internal.timetrigger.triggers.%d.every", parentProperty, name, i), ErrIsNotValid) 1895 } 1896 } 1897 } 1898 } 1899 case *vegapb.DataSourceDefinition_External: 1900 if tp.External == nil { 1901 errs.AddForProperty(fmt.Sprintf("%s.%s.external", parentProperty, name), ErrIsRequired) 1902 return errs 1903 } 1904 switch tp.External.SourceType.(type) { 1905 case *vegapb.DataSourceDefinitionExternal_Oracle: 1906 // If data source type is external - check if the signers are present first. 1907 o := tp.External.GetOracle() 1908 if o != nil { 1909 signers := o.Signers 1910 if len(signers) == 0 { 1911 errs.AddForProperty(fmt.Sprintf("%s.%s.external.oracle.signers", parentProperty, name), ErrIsRequired) 1912 } 1913 1914 for i, key := range signers { 1915 signer := dstypes.SignerFromProto(key) 1916 if signer.IsEmpty() { 1917 errs.AddForProperty(fmt.Sprintf("%s.%s.external.oracle.signers.%d", parentProperty, name, i), ErrIsNotValid) 1918 } else if pubkey := signer.GetSignerPubKey(); pubkey != nil && !crypto.IsValidVegaPubKey(pubkey.Key) { 1919 errs.AddForProperty(fmt.Sprintf("%s.%s.external.oracle.signers.%d", parentProperty, name, i), ErrIsNotValidVegaPubkey) 1920 } else if address := signer.GetSignerETHAddress(); address != nil && !crypto.EthereumIsValidAddress(address.Address) { 1921 errs.AddForProperty(fmt.Sprintf("%s.%s.external.oracle.signers.%d", parentProperty, name, i), ErrIsNotValidEthereumAddress) 1922 } 1923 } 1924 1925 filters := o.Filters 1926 errs.Merge(checkDataSourceSpecFilters(filters, fmt.Sprintf("%s.external.oracle", name), parentProperty)) 1927 } else { 1928 errs.AddForProperty(fmt.Sprintf("%s.%s.external.oracle", parentProperty, name), ErrIsRequired) 1929 } 1930 case *vegapb.DataSourceDefinitionExternal_EthOracle: 1931 ethOracle := tp.External.GetEthOracle() 1932 1933 if ethOracle != nil { 1934 if !crypto.EthereumIsValidAddress(ethOracle.Address) { 1935 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.address", parentProperty, name), ErrIsNotValidEthereumAddress) 1936 } 1937 1938 spec, err := ethcallcommon.SpecFromProto(ethOracle) 1939 if err != nil { 1940 switch { 1941 case errors.Is(err, ethcallcommon.ErrCallSpecIsNil): 1942 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle", parentProperty, name), ErrEmptyEthereumCallSpec) 1943 case errors.Is(err, ethcallcommon.ErrInvalidCallTrigger): 1944 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.trigger", parentProperty, name), ErrInvalidEthereumCallTrigger) 1945 case errors.Is(err, ethcallcommon.ErrInvalidCallArgs): 1946 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.args", parentProperty, name), ErrInvalidEthereumCallArgs) 1947 default: 1948 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle", parentProperty, name), ErrInvalidEthereumCallSpec) 1949 } 1950 } 1951 1952 if _, err := ethcall.NewCall(spec); err != nil { 1953 switch { 1954 case errors.Is(err, ethcallcommon.ErrInvalidEthereumAbi): 1955 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.abi", parentProperty, name), ErrInvalidEthereumAbi) 1956 case errors.Is(err, ethcallcommon.ErrInvalidCallArgs): 1957 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.callargs", parentProperty, name), ErrInvalidEthereumCallArgs) 1958 case errors.Is(err, ethcallcommon.ErrInvalidFilters): 1959 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.filters", parentProperty, name), ErrInvalidEthereumFilters) 1960 default: 1961 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle", parentProperty, name), ErrInvalidEthereumCallSpec) 1962 } 1963 } 1964 1965 filters := ethOracle.Filters 1966 errs.Merge(checkDataSourceSpecFilters(filters, fmt.Sprintf("%s.external.ethoracle", name), parentProperty)) 1967 1968 if len(ethOracle.Abi) == 0 { 1969 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.abi", parentProperty, name), ErrIsRequired) 1970 } 1971 1972 if len(strings.TrimSpace(ethOracle.Method)) == 0 { 1973 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.method", parentProperty, name), ErrIsRequired) 1974 } 1975 1976 if len(ethOracle.Normalisers) == 0 { 1977 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.normalisers", parentProperty, name), ErrIsRequired) 1978 } 1979 1980 if ethOracle.Trigger == nil { 1981 errs.AddForProperty(fmt.Sprintf("%s.%s.external.ethoracle.trigger", parentProperty, name), ErrIsRequired) 1982 } 1983 } else { 1984 errs.AddForProperty(fmt.Sprintf("%s.%s.external.oracle", parentProperty, name), ErrIsRequired) 1985 } 1986 } 1987 } 1988 return errs 1989 } 1990 1991 func checkDataSourceSpecFilters(filters []*datapb.Filter, name string, parentProperty string) Errors { 1992 errs := NewErrors() 1993 1994 if len(filters) == 0 { 1995 return errs.FinalAddForProperty(fmt.Sprintf("%s.%s.filters", parentProperty, name), ErrIsRequired) 1996 } 1997 1998 for i, filter := range filters { 1999 if filter.Key == nil { 2000 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.key", parentProperty, name, i), ErrIsNotValid) 2001 } else { 2002 if len(filter.Key.Name) == 0 { 2003 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.key.name", parentProperty, name, i), ErrIsRequired) 2004 } 2005 if filter.Key.Type == datapb.PropertyKey_TYPE_UNSPECIFIED { 2006 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.key.type", parentProperty, name, i), ErrIsRequired) 2007 } 2008 if _, ok := datapb.PropertyKey_Type_name[int32(filter.Key.Type)]; !ok { 2009 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.key.type", parentProperty, name, i), ErrIsNotValid) 2010 } 2011 } 2012 2013 if len(filter.Conditions) != 0 { 2014 for j, condition := range filter.Conditions { 2015 if len(condition.Value) == 0 { 2016 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.conditions.%d.value", parentProperty, name, i, j), ErrIsRequired) 2017 } 2018 if condition.Operator == datapb.Condition_OPERATOR_UNSPECIFIED { 2019 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.conditions.%d.operator", parentProperty, name, i, j), ErrIsRequired) 2020 } 2021 if _, ok := datapb.Condition_Operator_name[int32(condition.Operator)]; !ok { 2022 errs.AddForProperty(fmt.Sprintf("%s.%s.filters.%d.conditions.%d.operator", parentProperty, name, i, j), ErrIsNotValid) 2023 } 2024 } 2025 } 2026 } 2027 2028 return errs 2029 } 2030 2031 func isBindingMatchingSpec(spec *vegapb.DataSourceDefinition, bindingProperty string) bool { 2032 if spec == nil { 2033 return false 2034 } 2035 2036 switch specType := spec.SourceType.(type) { 2037 case *vegapb.DataSourceDefinition_External: 2038 switch specType.External.SourceType.(type) { 2039 case *vegapb.DataSourceDefinitionExternal_Oracle: 2040 return isBindingMatchingSpecFilters(spec, bindingProperty) 2041 case *vegapb.DataSourceDefinitionExternal_EthOracle: 2042 ethOracle := specType.External.GetEthOracle() 2043 2044 isNormaliser := false 2045 2046 for _, v := range ethOracle.Normalisers { 2047 if v.Name == bindingProperty { 2048 isNormaliser = true 2049 break 2050 } 2051 } 2052 2053 return isNormaliser || isBindingMatchingSpecFilters(spec, bindingProperty) 2054 } 2055 2056 case *vegapb.DataSourceDefinition_Internal: 2057 return isBindingMatchingSpecFilters(spec, bindingProperty) 2058 } 2059 2060 return isBindingMatchingSpecFilters(spec, bindingProperty) 2061 } 2062 2063 // This is the legacy oracles way of checking that the spec has a property matching the binding property by iterating 2064 // over the filters, but is it not possible to not have filters, or a filter that does not match the oracle property so 2065 // this would break? 2066 func isBindingMatchingSpecFilters(spec *vegapb.DataSourceDefinition, bindingProperty string) bool { 2067 bindingPropertyFound := false 2068 filters := []*datapb.Filter{} 2069 if spec != nil { 2070 filters = spec.GetFilters() 2071 } 2072 if spec != nil && filters != nil { 2073 for _, filter := range filters { 2074 if filter.Key != nil && filter.Key.Name == bindingProperty { 2075 bindingPropertyFound = true 2076 } 2077 } 2078 } 2079 return bindingPropertyFound 2080 } 2081 2082 func checkCompositePriceBinding(binding *vegapb.SpecBindingForCompositePrice, definition *vegapb.DataSourceDefinition, property string) Errors { 2083 errs := NewErrors() 2084 2085 if binding == nil { 2086 errs.AddForProperty(property, ErrIsRequired) 2087 return errs 2088 } 2089 2090 if len(binding.PriceSourceProperty) == 0 { 2091 errs.AddForProperty(property, ErrIsRequired) 2092 } else if !isBindingMatchingSpec(definition, binding.PriceSourceProperty) { 2093 errs.AddForProperty(fmt.Sprintf("%s.price_source_property", property), ErrIsMismatching) 2094 } 2095 return errs 2096 } 2097 2098 func checkNewOracleBinding(future *vegapb.FutureProduct) Errors { 2099 errs := NewErrors() 2100 if future.DataSourceSpecBinding != nil { 2101 if len(future.DataSourceSpecBinding.SettlementDataProperty) == 0 { 2102 errs.AddForProperty("new_market.changes.instrument.product.future.data_source_spec_binding.settlement_data_property", ErrIsRequired) 2103 } else { 2104 if !isBindingMatchingSpec(future.DataSourceSpecForSettlementData, future.DataSourceSpecBinding.SettlementDataProperty) { 2105 errs.AddForProperty("new_market.changes.instrument.product.future.data_source_spec_binding.settlement_data_property", ErrIsMismatching) 2106 } 2107 } 2108 2109 if len(future.DataSourceSpecBinding.TradingTerminationProperty) == 0 { 2110 errs.AddForProperty("new_market.changes.instrument.product.future.data_source_spec_binding.trading_termination_property", ErrIsRequired) 2111 } else { 2112 if future.DataSourceSpecForTradingTermination == nil || future.DataSourceSpecForTradingTermination.GetExternal() != nil && !isBindingMatchingSpec(future.DataSourceSpecForTradingTermination, future.DataSourceSpecBinding.TradingTerminationProperty) { 2113 errs.AddForProperty("new_market.changes.instrument.product.future.data_source_spec_binding.trading_termination_property", ErrIsMismatching) 2114 } 2115 } 2116 } else { 2117 errs.AddForProperty("new_market.changes.instrument.product.future.data_source_spec_binding", ErrIsRequired) 2118 } 2119 2120 return errs 2121 } 2122 2123 func checkNewPerpsOracleBinding(perps *vegapb.PerpetualProduct) Errors { 2124 errs := NewErrors() 2125 2126 if perps.DataSourceSpecBinding != nil { 2127 if len(perps.DataSourceSpecBinding.SettlementDataProperty) == 0 { 2128 errs.AddForProperty("new_market.changes.instrument.product.perps.data_source_spec_binding.settlement_data_property", ErrIsRequired) 2129 } else { 2130 if !isBindingMatchingSpec(perps.DataSourceSpecForSettlementData, perps.DataSourceSpecBinding.SettlementDataProperty) { 2131 errs.AddForProperty("new_market.changes.instrument.product.perps.data_source_spec_binding.settlement_data_property", ErrIsMismatching) 2132 } 2133 } 2134 } else { 2135 errs.AddForProperty("new_market.changes.instrument.product.perps.data_source_spec_binding", ErrIsRequired) 2136 } 2137 2138 return errs 2139 } 2140 2141 func checkUpdateOracleBinding(future *vegapb.UpdateFutureProduct) Errors { 2142 errs := NewErrors() 2143 if future.DataSourceSpecBinding != nil { 2144 if len(future.DataSourceSpecBinding.SettlementDataProperty) == 0 { 2145 errs.AddForProperty("update_market.changes.instrument.product.future.data_source_spec_binding.settlement_data_property", ErrIsRequired) 2146 } else { 2147 if !isBindingMatchingSpec(future.DataSourceSpecForSettlementData, future.DataSourceSpecBinding.SettlementDataProperty) { 2148 errs.AddForProperty("update_market.changes.instrument.product.future.data_source_spec_binding.settlement_data_property", ErrIsMismatching) 2149 } 2150 } 2151 2152 if len(future.DataSourceSpecBinding.TradingTerminationProperty) == 0 { 2153 errs.AddForProperty("update_market.changes.instrument.product.future.data_source_spec_binding.trading_termination_property", ErrIsRequired) 2154 } else { 2155 if !isBindingMatchingSpec(future.DataSourceSpecForTradingTermination, future.DataSourceSpecBinding.TradingTerminationProperty) { 2156 errs.AddForProperty("update_market.changes.instrument.product.future.data_source_spec_binding.trading_termination_property", ErrIsMismatching) 2157 } 2158 } 2159 } else { 2160 errs.AddForProperty("update_market.changes.instrument.product.future.data_source_spec_binding", ErrIsRequired) 2161 } 2162 2163 return errs 2164 } 2165 2166 func checkUpdatePerpsOracleBinding(perps *vegapb.UpdatePerpetualProduct) Errors { 2167 errs := NewErrors() 2168 if perps.DataSourceSpecBinding != nil { 2169 if len(perps.DataSourceSpecBinding.SettlementDataProperty) == 0 { 2170 errs.AddForProperty("update_market.changes.instrument.product.perps.data_source_spec_binding.settlement_data_property", ErrIsRequired) 2171 } else { 2172 if !isBindingMatchingSpec(perps.DataSourceSpecForSettlementData, perps.DataSourceSpecBinding.SettlementDataProperty) { 2173 errs.AddForProperty("update_market.changes.instrument.product.perps.data_source_spec_binding.settlement_data_property", ErrIsMismatching) 2174 } 2175 } 2176 } else { 2177 errs.AddForProperty("update_market.changes.instrument.product.perps.data_source_spec_binding", ErrIsRequired) 2178 } 2179 2180 return errs 2181 } 2182 2183 func checkNewRiskParameters(config *vegapb.NewMarketConfiguration) Errors { 2184 errs := NewErrors() 2185 2186 if config.RiskParameters == nil { 2187 return errs.FinalAddForProperty("new_market.changes.risk_parameters", ErrIsRequired) 2188 } 2189 2190 switch parameters := config.RiskParameters.(type) { 2191 case *vegapb.NewMarketConfiguration_Simple: 2192 errs.Merge(checkNewSimpleParameters(parameters)) 2193 case *vegapb.NewMarketConfiguration_LogNormal: 2194 errs.Merge(checkNewLogNormalRiskParameters(parameters)) 2195 default: 2196 errs.AddForProperty("new_market.changes.risk_parameters", ErrIsNotValid) 2197 } 2198 2199 return errs 2200 } 2201 2202 func checkSLAParams(config *vegapb.LiquiditySLAParameters, parent string) Errors { 2203 errs := NewErrors() 2204 if config == nil { 2205 return errs.FinalAddForProperty(fmt.Sprintf("%s.sla_params", parent), ErrIsRequired) 2206 } 2207 2208 lppr, err := num.DecimalFromString(config.PriceRange) 2209 if err != nil { 2210 errs.AddForProperty(fmt.Sprintf("%s.price_range", parent), ErrIsNotValidNumber) 2211 } else if lppr.IsZero() || lppr.LessThan(num.DecimalZero()) || lppr.GreaterThan(num.DecimalFromFloat(20)) { 2212 errs.AddForProperty(fmt.Sprintf("%s.price_range", parent), ErrMustBeWithinRangeGT0LT20) 2213 } 2214 2215 commitmentMinTimeFraction, err := num.DecimalFromString(config.CommitmentMinTimeFraction) 2216 if err != nil { 2217 errs.AddForProperty(fmt.Sprintf("%s.commitment_min_time_fraction", parent), ErrIsNotValidNumber) 2218 } else if commitmentMinTimeFraction.LessThan(num.DecimalZero()) || commitmentMinTimeFraction.GreaterThan(num.DecimalOne()) { 2219 errs.AddForProperty(fmt.Sprintf("%s.commitment_min_time_fraction", parent), ErrMustBeWithinRange01) 2220 } 2221 2222 slaCompetitionFactor, err := num.DecimalFromString(config.SlaCompetitionFactor) 2223 if err != nil { 2224 errs.AddForProperty(fmt.Sprintf("%s.sla_competition_factor", parent), ErrIsNotValidNumber) 2225 } else if slaCompetitionFactor.LessThan(num.DecimalZero()) || slaCompetitionFactor.GreaterThan(num.DecimalOne()) { 2226 errs.AddForProperty(fmt.Sprintf("%s.sla_competition_factor", parent), ErrMustBeWithinRange01) 2227 } 2228 2229 if config.PerformanceHysteresisEpochs > 366 { 2230 errs.AddForProperty(fmt.Sprintf("%s.performance_hysteresis_epochs", parent), ErrMustBeLessThen366) 2231 } 2232 2233 return errs 2234 } 2235 2236 func checkLiquidityFeeSettings(config *vegapb.LiquidityFeeSettings, parent string) Errors { 2237 errs := NewErrors() 2238 if config == nil { 2239 return nil // no error, we'll default to margin-cost method 2240 } 2241 2242 // check for valid enum range 2243 if config.Method == vegapb.LiquidityFeeSettings_METHOD_UNSPECIFIED { 2244 errs.AddForProperty(fmt.Sprintf("%s.method", parent), ErrIsRequired) 2245 } 2246 if _, ok := vegapb.LiquidityFeeSettings_Method_name[int32(config.Method)]; !ok { 2247 errs.AddForProperty(fmt.Sprintf("%s.method", parent), ErrIsNotValid) 2248 } 2249 2250 if config.FeeConstant == nil && config.Method == vegapb.LiquidityFeeSettings_METHOD_CONSTANT { 2251 errs.AddForProperty(fmt.Sprintf("%s.fee_constant", parent), ErrIsRequired) 2252 } 2253 2254 if config.FeeConstant != nil { 2255 if config.Method != vegapb.LiquidityFeeSettings_METHOD_CONSTANT { 2256 errs.AddForProperty(fmt.Sprintf("%s.method", parent), ErrIsNotValid) 2257 } 2258 2259 fee, err := num.DecimalFromString(*config.FeeConstant) 2260 switch { 2261 case err != nil: 2262 errs.AddForProperty(fmt.Sprintf("%s.fee_constant", parent), ErrIsNotValidNumber) 2263 case fee.IsNegative(): 2264 errs.AddForProperty(fmt.Sprintf("%s.fee_constant", parent), ErrMustBePositiveOrZero) 2265 case fee.GreaterThan(num.DecimalOne()): 2266 errs.AddForProperty(fmt.Sprintf("%s.fee_constant", parent), ErrMustBeWithinRange01) 2267 } 2268 } 2269 2270 return errs 2271 } 2272 2273 func checkCompositePriceConfiguration(config *vegapb.CompositePriceConfiguration, parent string) Errors { 2274 errs := NewErrors() 2275 if config == nil { 2276 errs.AddForProperty(parent, ErrIsRequired) 2277 return errs 2278 } 2279 if config.CompositePriceType == vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_UNSPECIFIED { 2280 errs.AddForProperty(fmt.Sprintf("%s.composite_price_type", parent), ErrIsRequired) 2281 } 2282 2283 if _, ok := vegapb.CompositePriceType_name[int32(config.CompositePriceType)]; !ok { 2284 errs.AddForProperty(fmt.Sprintf("%s.composite_price_type", parent), ErrIsNotValid) 2285 } 2286 2287 if config.CompositePriceType != vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_LAST_TRADE { 2288 if config.DecayPower > 3 || config.DecayPower < 1 { 2289 errs.AddForProperty(fmt.Sprintf("%s.decay_power", parent), fmt.Errorf("must be in {1, 2, 3}")) 2290 } 2291 if len(config.DecayWeight) == 0 { 2292 errs.AddForProperty(fmt.Sprintf("%s.decay_weight", parent), ErrIsRequired) 2293 } else { 2294 dw, err := num.DecimalFromString(config.DecayWeight) 2295 if err != nil { 2296 errs.AddForProperty(fmt.Sprintf("%s.decay_weight", parent), ErrIsNotValidNumber) 2297 } else if dw.LessThan(num.DecimalZero()) || dw.GreaterThan(num.DecimalOne()) { 2298 errs.AddForProperty(fmt.Sprintf("%s.decay_weight", parent), ErrMustBeWithinRange01) 2299 } 2300 } 2301 if len(config.CashAmount) == 0 { 2302 errs.AddForProperty(fmt.Sprintf("%s.cash_amount", parent), ErrIsRequired) 2303 } else if n, overflow := num.UintFromString(config.CashAmount, 10); overflow || n.IsNegative() { 2304 errs.AddForProperty(fmt.Sprintf("%s.cash_amount", parent), ErrIsNotValidNumber) 2305 } 2306 } else { 2307 if config.DecayPower != 0 { 2308 errs.AddForProperty(fmt.Sprintf("%s.decay_power", parent), fmt.Errorf("must not be defined for price type last trade")) 2309 } 2310 if len(config.DecayWeight) > 0 { 2311 errs.AddForProperty(fmt.Sprintf("%s.decay_weight", parent), fmt.Errorf("must not be defined for price type last trade")) 2312 } 2313 if len(config.CashAmount) > 0 { 2314 errs.AddForProperty(fmt.Sprintf("%s.cash_amount", parent), fmt.Errorf("must not be defined for price type last trade")) 2315 } 2316 if len(config.SourceStalenessTolerance) > 0 { 2317 errs.AddForProperty(fmt.Sprintf("%s.source_staleness_tolerance", parent), fmt.Errorf("must not be defined for price type last trade")) 2318 } 2319 if len(config.SourceWeights) > 0 { 2320 errs.AddForProperty(fmt.Sprintf("%s.source_weights", parent), fmt.Errorf("must not be defined for price type last trade")) 2321 } 2322 if len(config.DataSourcesSpec) > 0 { 2323 errs.AddForProperty(fmt.Sprintf("%s.data_sources_spec", parent), fmt.Errorf("must not be defined for price type last trade")) 2324 } 2325 if len(config.DataSourcesSpec) > 0 { 2326 errs.AddForProperty(fmt.Sprintf("%s.data_sources_spec_binding", parent), fmt.Errorf("must not be defined for price type last trade")) 2327 } 2328 } 2329 2330 if config.CompositePriceType != vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_WEIGHTED && len(config.SourceWeights) > 0 { 2331 errs.AddForProperty(fmt.Sprintf("%s.source_weights", parent), fmt.Errorf("must be empty if composite price type is not weighted")) 2332 } 2333 2334 if config.CompositePriceType == vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_WEIGHTED && len(config.SourceWeights) != 3+len(config.DataSourcesSpec) { 2335 errs.AddForProperty(fmt.Sprintf("%s.source_weights", parent), fmt.Errorf("must be defined for all price sources")) 2336 } 2337 2338 if config.CompositePriceType == vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_WEIGHTED && len(config.SourceWeights) != len(config.SourceStalenessTolerance) { 2339 errs.AddForProperty(fmt.Sprintf("%s.source_staleness_tolerance", parent), fmt.Errorf("must have the same length as source_weights")) 2340 } 2341 2342 weightSum := num.DecimalZero() 2343 for i, v := range config.SourceWeights { 2344 if d, err := num.DecimalFromString(v); err != nil { 2345 errs.AddForProperty(fmt.Sprintf("%s.source_weights.%d", parent, i), ErrIsNotValidNumber) 2346 } else if d.LessThan(num.DecimalZero()) { 2347 errs.AddForProperty(fmt.Sprintf("%s.source_weights.%d", parent, i), ErrMustBePositiveOrZero) 2348 } else { 2349 weightSum = weightSum.Add(d) 2350 } 2351 } 2352 if config.CompositePriceType == vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_WEIGHTED && weightSum.IsZero() { 2353 errs.AddForProperty(fmt.Sprintf("%s.source_weights", parent), fmt.Errorf("must have at least one none zero weight")) 2354 } 2355 2356 for i, v := range config.SourceStalenessTolerance { 2357 if _, err := time.ParseDuration(v); err != nil { 2358 errs.AddForProperty(fmt.Sprintf("%s.source_staleness_tolerance.%d", parent, i), fmt.Errorf("must be a valid duration")) 2359 } 2360 } 2361 if len(config.DataSourcesSpec) > 0 && len(config.DataSourcesSpec) != len(config.DataSourcesSpecBinding) { 2362 errs.AddForProperty(fmt.Sprintf("%s.data_sources_spec", parent), fmt.Errorf("must be have the same number of elements as the corresponding bindings")) 2363 } 2364 if len(config.DataSourcesSpec) > 5 { 2365 errs.AddForProperty(fmt.Sprintf("%s.data_sources_spec", parent), fmt.Errorf("too many data source specs - must be less than or equal to 5")) 2366 } 2367 if config.CompositePriceType != vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_LAST_TRADE && len(config.SourceStalenessTolerance) != 3+len(config.DataSourcesSpec) { 2368 errs.AddForProperty(fmt.Sprintf("%s.source_staleness_tolerance", parent), fmt.Errorf("must included staleness information for all price sources")) 2369 } 2370 2371 if config.CompositePriceType == vegapb.CompositePriceType_COMPOSITE_PRICE_TYPE_LAST_TRADE && len(config.DataSourcesSpec) > 0 { 2372 errs.AddForProperty(fmt.Sprintf("%s.data_sources_spec", parent), fmt.Errorf("are not supported for last trade composite price type")) 2373 } 2374 if len(config.DataSourcesSpec) != len(config.DataSourcesSpecBinding) { 2375 errs.AddForProperty(fmt.Sprintf("%s.data_sources_spec_binding", parent), fmt.Errorf("must be defined for all oracles")) 2376 } else if len(config.DataSourcesSpec) > 0 { 2377 for i, dsd := range config.DataSourcesSpec { 2378 errs.Merge(checkDataSourceSpec(dsd, fmt.Sprintf("data_sources_spec.%d", i), parent, true)) 2379 errs.Merge(checkCompositePriceBinding(config.DataSourcesSpecBinding[i], dsd, fmt.Sprintf("%s.data_sources_spec_binding.%d", parent, i))) 2380 } 2381 } 2382 2383 return errs 2384 } 2385 2386 func checkNewSpotRiskParameters(config *vegapb.NewSpotMarketConfiguration) Errors { 2387 errs := NewErrors() 2388 2389 if config.RiskParameters == nil { 2390 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters", ErrIsRequired) 2391 } 2392 2393 switch parameters := config.RiskParameters.(type) { 2394 case *vegapb.NewSpotMarketConfiguration_Simple: 2395 errs.Merge(checkNewSpotSimpleParameters(parameters)) 2396 case *vegapb.NewSpotMarketConfiguration_LogNormal: 2397 errs.Merge(checkNewSpotLogNormalRiskParameters(parameters)) 2398 default: 2399 errs.AddForProperty("new_spot_market.changes.risk_parameters", ErrIsNotValid) 2400 } 2401 2402 return errs 2403 } 2404 2405 func checkUpdateRiskParameters(config *vegapb.UpdateMarketConfiguration) Errors { 2406 errs := NewErrors() 2407 2408 if config.RiskParameters == nil { 2409 return errs.FinalAddForProperty("update_market.changes.risk_parameters", ErrIsRequired) 2410 } 2411 2412 switch parameters := config.RiskParameters.(type) { 2413 case *vegapb.UpdateMarketConfiguration_Simple: 2414 errs.Merge(checkUpdateSimpleParameters(parameters)) 2415 case *vegapb.UpdateMarketConfiguration_LogNormal: 2416 errs.Merge(checkUpdateLogNormalRiskParameters(parameters)) 2417 default: 2418 errs.AddForProperty("update_market.changes.risk_parameters", ErrIsNotValid) 2419 } 2420 2421 return errs 2422 } 2423 2424 func checkUpdateSpotRiskParameters(config *vegapb.UpdateSpotMarketConfiguration) Errors { 2425 errs := NewErrors() 2426 2427 if config.RiskParameters == nil { 2428 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters", ErrIsRequired) 2429 } 2430 2431 switch parameters := config.RiskParameters.(type) { 2432 case *vegapb.UpdateSpotMarketConfiguration_Simple: 2433 errs.Merge(checkUpdateSpotSimpleParameters(parameters)) 2434 case *vegapb.UpdateSpotMarketConfiguration_LogNormal: 2435 errs.Merge(checkUpdateSpotLogNormalRiskParameters(parameters)) 2436 default: 2437 errs.AddForProperty("update_spot_market.changes.risk_parameters", ErrIsNotValid) 2438 } 2439 2440 return errs 2441 } 2442 2443 func checkNewSimpleParameters(params *vegapb.NewMarketConfiguration_Simple) Errors { 2444 errs := NewErrors() 2445 2446 if params.Simple == nil { 2447 return errs.FinalAddForProperty("new_market.changes.risk_parameters.simple", ErrIsRequired) 2448 } 2449 2450 if params.Simple.MinMoveDown > 0 { 2451 errs.AddForProperty("new_market.changes.risk_parameters.simple.min_move_down", ErrMustBeNegativeOrZero) 2452 } 2453 2454 if params.Simple.MaxMoveUp < 0 { 2455 errs.AddForProperty("new_market.changes.risk_parameters.simple.max_move_up", ErrMustBePositiveOrZero) 2456 } 2457 2458 if params.Simple.ProbabilityOfTrading < 0 || params.Simple.ProbabilityOfTrading > 1 { 2459 errs.AddForProperty("new_market.changes.risk_parameters.simple.probability_of_trading", 2460 fmt.Errorf("should be between 0 (inclusive) and 1 (inclusive)"), 2461 ) 2462 } 2463 2464 return errs 2465 } 2466 2467 func checkNewSpotSimpleParameters(params *vegapb.NewSpotMarketConfiguration_Simple) Errors { 2468 errs := NewErrors() 2469 2470 if params.Simple == nil { 2471 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.simple", ErrIsRequired) 2472 } 2473 2474 if params.Simple.MinMoveDown > 0 { 2475 errs.AddForProperty("new_spot_market.changes.risk_parameters.simple.min_move_down", ErrMustBeNegativeOrZero) 2476 } 2477 2478 if params.Simple.MaxMoveUp < 0 { 2479 errs.AddForProperty("new_spot_market.changes.risk_parameters.simple.max_move_up", ErrMustBePositiveOrZero) 2480 } 2481 2482 if params.Simple.ProbabilityOfTrading < 0 || params.Simple.ProbabilityOfTrading > 1 { 2483 errs.AddForProperty("new_spot_market.changes.risk_parameters.simple.probability_of_trading", 2484 fmt.Errorf("should be between 0 (inclusive) and 1 (inclusive)"), 2485 ) 2486 } 2487 2488 return errs 2489 } 2490 2491 func checkUpdateSimpleParameters(params *vegapb.UpdateMarketConfiguration_Simple) Errors { 2492 errs := NewErrors() 2493 2494 if params.Simple == nil { 2495 return errs.FinalAddForProperty("update_market.changes.risk_parameters.simple", ErrIsRequired) 2496 } 2497 2498 if params.Simple.MinMoveDown > 0 { 2499 errs.AddForProperty("update_market.changes.risk_parameters.simple.min_move_down", ErrMustBeNegativeOrZero) 2500 } 2501 2502 if params.Simple.MaxMoveUp < 0 { 2503 errs.AddForProperty("update_market.changes.risk_parameters.simple.max_move_up", ErrMustBePositiveOrZero) 2504 } 2505 2506 if params.Simple.ProbabilityOfTrading < 0 || params.Simple.ProbabilityOfTrading > 1 { 2507 errs.AddForProperty("update_market.changes.risk_parameters.simple.probability_of_trading", 2508 fmt.Errorf("should be between 0 (inclusive) and 1 (inclusive)"), 2509 ) 2510 } 2511 2512 return errs 2513 } 2514 2515 func checkUpdateSpotSimpleParameters(params *vegapb.UpdateSpotMarketConfiguration_Simple) Errors { 2516 errs := NewErrors() 2517 2518 if params.Simple == nil { 2519 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.simple", ErrIsRequired) 2520 } 2521 2522 if params.Simple.MinMoveDown > 0 { 2523 errs.AddForProperty("update_spot_market.changes.risk_parameters.simple.min_move_down", ErrMustBeNegativeOrZero) 2524 } 2525 2526 if params.Simple.MaxMoveUp < 0 { 2527 errs.AddForProperty("update_spot_market.changes.risk_parameters.simple.max_move_up", ErrMustBePositiveOrZero) 2528 } 2529 2530 if params.Simple.ProbabilityOfTrading < 0 || params.Simple.ProbabilityOfTrading > 1 { 2531 errs.AddForProperty("update_spot_market.changes.risk_parameters.simple.probability_of_trading", 2532 fmt.Errorf("should be between 0 (inclusive) and 1 (inclusive)"), 2533 ) 2534 } 2535 2536 return errs 2537 } 2538 2539 func checkNewLogNormalRiskParameters(params *vegapb.NewMarketConfiguration_LogNormal) Errors { 2540 errs := NewErrors() 2541 2542 if params.LogNormal == nil { 2543 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal", ErrIsRequired) 2544 } 2545 2546 if params.LogNormal.Params == nil { 2547 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params", ErrIsRequired) 2548 } 2549 2550 if params.LogNormal.RiskAversionParameter < 1e-8 || params.LogNormal.RiskAversionParameter > 0.1 { 2551 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.risk_aversion_parameter", errors.New("must be between [1e-8, 0.1]")) 2552 } 2553 2554 if params.LogNormal.Tau < 1e-8 || params.LogNormal.Tau > 1 { 2555 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.tau", errors.New("must be between [1e-8, 1]")) 2556 } 2557 2558 if math.IsNaN(params.LogNormal.Params.Mu) { 2559 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params.mu", ErrIsNotValidNumber) 2560 } 2561 2562 if params.LogNormal.Params.Mu < -1e-6 || params.LogNormal.Params.Mu > 1e-6 { 2563 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params.mu", errors.New("must be between [-1e-6,1e-6]")) 2564 } 2565 2566 if math.IsNaN(params.LogNormal.Params.Sigma) { 2567 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params.sigma", ErrIsNotValidNumber) 2568 } 2569 2570 if params.LogNormal.Params.Sigma < 1e-3 || params.LogNormal.Params.Sigma > 50 { 2571 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params.sigma", errors.New("must be between [1e-3,50]")) 2572 } 2573 2574 if math.IsNaN(params.LogNormal.Params.R) { 2575 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params.r", ErrIsNotValidNumber) 2576 } 2577 2578 if params.LogNormal.Params.R < -1 || params.LogNormal.Params.R > 1 { 2579 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.params.r", errors.New("must be between [-1,1]")) 2580 } 2581 2582 // if not nil, both short and long must be specified and correct 2583 if params.LogNormal.RiskFactorOverride != nil { 2584 short := params.LogNormal.RiskFactorOverride.Short 2585 long := params.LogNormal.RiskFactorOverride.Long 2586 if len(short) <= 0 { 2587 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.risk_factor_override.short", ErrIsRequired) 2588 } 2589 2590 d, err := num.DecimalFromString(short) 2591 if err != nil { 2592 errs.AddForProperty("new_market.changes.risk_parameters.log_normal.risk_factor_override.short", ErrIsNotValidNumber) 2593 } else if d.LessThanOrEqual(num.DecimalZero()) { 2594 errs.AddForProperty("new_market.changes.risk_parameters.log_normal.risk_factor_override.short", ErrMustBePositive) 2595 } 2596 2597 if len(long) <= 0 { 2598 return errs.FinalAddForProperty("new_market.changes.risk_parameters.log_normal.risk_factor_override.long", ErrIsRequired) 2599 } 2600 2601 d, err = num.DecimalFromString(long) 2602 if err != nil { 2603 errs.AddForProperty("new_market.changes.risk_parameters.log_normal.risk_factor_override.long", ErrIsNotValidNumber) 2604 } else if d.LessThanOrEqual(num.DecimalZero()) { 2605 errs.AddForProperty("new_market.changes.risk_parameters.log_normal.risk_factor_override.long", ErrMustBePositive) 2606 } 2607 } 2608 2609 return errs 2610 } 2611 2612 func checkUpdateLogNormalRiskParameters(params *vegapb.UpdateMarketConfiguration_LogNormal) Errors { 2613 errs := NewErrors() 2614 2615 if params.LogNormal == nil { 2616 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal", ErrIsRequired) 2617 } 2618 2619 if params.LogNormal.Params == nil { 2620 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.params", ErrIsRequired) 2621 } 2622 2623 if params.LogNormal.RiskAversionParameter <= 0 { 2624 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.risk_aversion_parameter", ErrMustBePositive) 2625 } 2626 2627 if params.LogNormal.Tau <= 0 { 2628 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.tau", ErrMustBePositive) 2629 } 2630 2631 if math.IsNaN(params.LogNormal.Params.Mu) { 2632 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.params.mu", ErrIsNotValidNumber) 2633 } 2634 2635 if math.IsNaN(params.LogNormal.Params.Sigma) { 2636 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.params.sigma", ErrIsNotValidNumber) 2637 } 2638 2639 if params.LogNormal.Params.Sigma <= 0 { 2640 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.params.sigma", ErrMustBePositive) 2641 } 2642 2643 if math.IsNaN(params.LogNormal.Params.R) { 2644 return errs.FinalAddForProperty("update_market.changes.risk_parameters.log_normal.params.r", ErrIsNotValidNumber) 2645 } 2646 2647 // if not nil, both short and long must be specified and correct 2648 if params.LogNormal.RiskFactorOverride != nil { 2649 short := params.LogNormal.RiskFactorOverride.Short 2650 long := params.LogNormal.RiskFactorOverride.Long 2651 if len(short) <= 0 { 2652 errs.AddForProperty("update_market.changes.risk_parameters.log_normal.risk_factor_override.short", ErrIsRequired) 2653 } 2654 2655 d, err := num.DecimalFromString(short) 2656 if err != nil { 2657 errs.AddForProperty("update_market.changes.risk_parameters.log_normal.risk_factor_override.short", ErrIsNotValidNumber) 2658 } else if d.LessThanOrEqual(num.DecimalZero()) { 2659 errs.AddForProperty("update_market.changes.risk_parameters.log_normal.risk_factor_override.short", ErrMustBePositive) 2660 } 2661 2662 if len(long) <= 0 { 2663 errs.AddForProperty("update_market.changes.risk_parameters.log_normal.risk_factor_override.long", ErrIsRequired) 2664 } 2665 2666 d, err = num.DecimalFromString(long) 2667 if err != nil { 2668 errs.AddForProperty("update_market.changes.risk_parameters.log_normal.risk_factor_override.long", ErrIsNotValidNumber) 2669 } else if d.LessThanOrEqual(num.DecimalZero()) { 2670 errs.AddForProperty("update_market.changes.risk_parameters.log_normal.risk_factor_override.long", ErrMustBePositive) 2671 } 2672 } 2673 2674 return errs 2675 } 2676 2677 func checkNewSpotLogNormalRiskParameters(params *vegapb.NewSpotMarketConfiguration_LogNormal) Errors { 2678 errs := NewErrors() 2679 2680 if params.LogNormal == nil { 2681 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal", ErrIsRequired) 2682 } 2683 2684 if params.LogNormal.Params == nil { 2685 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params", ErrIsRequired) 2686 } 2687 2688 if params.LogNormal.RiskAversionParameter < 1e-8 || params.LogNormal.RiskAversionParameter > 0.1 { 2689 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.risk_aversion_parameter", errors.New("must be between [1e-8, 0.1]")) 2690 } 2691 2692 if params.LogNormal.Tau < 1e-8 || params.LogNormal.Tau > 1 { 2693 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.tau", errors.New("must be between [1e-8, 1]")) 2694 } 2695 2696 if math.IsNaN(params.LogNormal.Params.Mu) { 2697 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params.mu", ErrIsNotValidNumber) 2698 } 2699 2700 if params.LogNormal.Params.Mu < -1e-6 || params.LogNormal.Params.Mu > 1e-6 { 2701 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params.mu", errors.New("must be between [-1e-6,1e-6]")) 2702 } 2703 2704 if math.IsNaN(params.LogNormal.Params.Sigma) { 2705 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params.sigma", ErrIsNotValidNumber) 2706 } 2707 2708 if params.LogNormal.Params.Sigma < 1e-3 || params.LogNormal.Params.Sigma > 50 { 2709 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params.sigma", errors.New("must be between [1e-3,50]")) 2710 } 2711 2712 if math.IsNaN(params.LogNormal.Params.R) { 2713 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params.r", ErrIsNotValidNumber) 2714 } 2715 2716 if params.LogNormal.Params.R < -1 || params.LogNormal.Params.R > 1 { 2717 return errs.FinalAddForProperty("new_spot_market.changes.risk_parameters.log_normal.params.r", errors.New("must be between [-1,1]")) 2718 } 2719 2720 return errs 2721 } 2722 2723 func checkUpdateSpotLogNormalRiskParameters(params *vegapb.UpdateSpotMarketConfiguration_LogNormal) Errors { 2724 errs := NewErrors() 2725 2726 if params.LogNormal == nil { 2727 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal", ErrIsRequired) 2728 } 2729 2730 if params.LogNormal.Params == nil { 2731 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.params", ErrIsRequired) 2732 } 2733 2734 if params.LogNormal.RiskAversionParameter <= 0 { 2735 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.risk_aversion_parameter", ErrMustBePositive) 2736 } 2737 2738 if params.LogNormal.Tau <= 0 { 2739 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.tau", ErrMustBePositive) 2740 } 2741 2742 if math.IsNaN(params.LogNormal.Params.Mu) { 2743 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.params.mu", ErrIsNotValidNumber) 2744 } 2745 2746 if math.IsNaN(params.LogNormal.Params.Sigma) { 2747 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.params.sigma", ErrIsNotValidNumber) 2748 } 2749 2750 if params.LogNormal.Params.Sigma <= 0 { 2751 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.params.sigma", ErrMustBePositive) 2752 } 2753 2754 if math.IsNaN(params.LogNormal.Params.R) { 2755 return errs.FinalAddForProperty("update_spot_market.changes.risk_parameters.log_normal.params.r", ErrIsNotValidNumber) 2756 } 2757 2758 return errs 2759 }