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  }