code.vegaprotocol.io/vega@v0.79.0/commands/proposal_submission_pap_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package commands_test
    17  
    18  import (
    19  	"fmt"
    20  	"testing"
    21  
    22  	"code.vegaprotocol.io/vega/commands"
    23  	types "code.vegaprotocol.io/vega/protos/vega"
    24  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    25  	datapb "code.vegaprotocol.io/vega/protos/vega/data/v1"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  )
    29  
    30  func TestSubmissionOfNewPAPWithoutDetailsFails(t *testing.T) {
    31  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
    32  		Terms: &types.ProposalTerms{
    33  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{},
    34  		},
    35  	})
    36  
    37  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase"), commands.ErrIsRequired)
    38  }
    39  
    40  func TestSubmissionOfNewPAPWithoutChangeDetailsFails(t *testing.T) {
    41  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
    42  		Terms: &types.ProposalTerms{
    43  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
    44  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{},
    45  			},
    46  		},
    47  	})
    48  
    49  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes"), commands.ErrIsRequired)
    50  }
    51  
    52  func TestSubmissionOfNewPAPWithoutFromAssetFails(t *testing.T) {
    53  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
    54  		Terms: &types.ProposalTerms{
    55  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
    56  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
    57  					Changes: &types.NewProtocolAutomatedPurchaseChanges{},
    58  				},
    59  			},
    60  		},
    61  	})
    62  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.from"), commands.ErrIsRequired)
    63  }
    64  
    65  func TestSubmissionOfNewPAPInvalidFromAccountTypeFails(t *testing.T) {
    66  	validFromAccountTypes := map[types.AccountType]struct{}{
    67  		types.AccountType_ACCOUNT_TYPE_BUY_BACK_FEES: {},
    68  	}
    69  	for tp := range types.AccountType_name {
    70  		err := checkProposalSubmission(&commandspb.ProposalSubmission{
    71  			Terms: &types.ProposalTerms{
    72  				Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
    73  					NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
    74  						Changes: &types.NewProtocolAutomatedPurchaseChanges{
    75  							FromAccountType: types.AccountType(tp),
    76  						},
    77  					},
    78  				},
    79  			},
    80  		})
    81  		_, ok := validFromAccountTypes[types.AccountType(tp)]
    82  		if !ok {
    83  			if tp == 0 {
    84  				assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.from_account_type"), commands.ErrIsRequired)
    85  			} else {
    86  				assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.from_account_type"), commands.ErrIsNotValid)
    87  			}
    88  		} else {
    89  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.from_account_type"), commands.ErrIsNotValid)
    90  		}
    91  	}
    92  }
    93  
    94  func TestSubmissionOfNewPAPInvalidToAccountTypeFails(t *testing.T) {
    95  	validAccountTypes := map[types.AccountType]struct{}{
    96  		types.AccountType_ACCOUNT_TYPE_GLOBAL_INSURANCE: {},
    97  		types.AccountType_ACCOUNT_TYPE_GLOBAL_REWARD:    {},
    98  		types.AccountType_ACCOUNT_TYPE_NETWORK_TREASURY: {},
    99  		types.AccountType_ACCOUNT_TYPE_BUY_BACK_FEES:    {},
   100  	}
   101  	for tp := range types.AccountType_name {
   102  		err := checkProposalSubmission(&commandspb.ProposalSubmission{
   103  			Terms: &types.ProposalTerms{
   104  				Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   105  					NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   106  						Changes: &types.NewProtocolAutomatedPurchaseChanges{
   107  							ToAccountType: types.AccountType(tp),
   108  						},
   109  					},
   110  				},
   111  			},
   112  		})
   113  		_, ok := validAccountTypes[types.AccountType(tp)]
   114  		if !ok {
   115  			if tp == 0 {
   116  				assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.to_account_type"), commands.ErrIsRequired)
   117  			} else {
   118  				assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.to_account_type"), commands.ErrIsNotValid)
   119  			}
   120  		} else {
   121  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.to_account_type"), commands.ErrIsNotValid)
   122  		}
   123  	}
   124  }
   125  
   126  func TestSubmissionOfNewPAPWithoutMarketIDFails(t *testing.T) {
   127  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
   128  		Terms: &types.ProposalTerms{
   129  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   130  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   131  					Changes: &types.NewProtocolAutomatedPurchaseChanges{},
   132  				},
   133  			},
   134  		},
   135  	})
   136  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.market_id"), commands.ErrIsRequired)
   137  }
   138  
   139  func TestSubmissionOfNewPAPWithInvalidPriceOffsetFails(t *testing.T) {
   140  	values := []string{"", "banana", "-1", "0", "0.9", "1.1"}
   141  	errors := []error{commands.ErrIsRequired, commands.ErrNotAValidFloat, commands.ErrMustBePositive, commands.ErrMustBePositive, nil, nil}
   142  	for i, v := range values {
   143  		err := checkProposalSubmission(&commandspb.ProposalSubmission{
   144  			Terms: &types.ProposalTerms{
   145  				Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   146  					NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   147  						Changes: &types.NewProtocolAutomatedPurchaseChanges{
   148  							OracleOffsetFactor: v,
   149  						},
   150  					},
   151  				},
   152  			},
   153  		})
   154  		if errors[i] != nil {
   155  			assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor"), errors[i])
   156  		} else {
   157  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor"), commands.ErrIsRequired)
   158  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor"), commands.ErrNotAValidFloat)
   159  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.oracle_offset_factor"), commands.ErrMustBePositive)
   160  		}
   161  	}
   162  }
   163  
   164  func TestSubmissionOfNewPAPWithInvalidDurationFails(t *testing.T) {
   165  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
   166  		Terms: &types.ProposalTerms{
   167  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   168  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   169  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   170  						AuctionDuration: "",
   171  					},
   172  				},
   173  			},
   174  		},
   175  	})
   176  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_duration"), commands.ErrIsRequired)
   177  
   178  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   179  		Terms: &types.ProposalTerms{
   180  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   181  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   182  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   183  						AuctionDuration: "dsfhjkhkj",
   184  					},
   185  				},
   186  			},
   187  		},
   188  	})
   189  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_duration"), fmt.Errorf("must be a valid duration"))
   190  
   191  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   192  		Terms: &types.ProposalTerms{
   193  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   194  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   195  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   196  						AuctionDuration: "10h5m",
   197  					},
   198  				},
   199  			},
   200  		},
   201  	})
   202  	assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_duration"), fmt.Errorf("must be a valid duration"))
   203  	assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_duration"), commands.ErrIsRequired)
   204  }
   205  
   206  func TestSubmissionOfNewPAPWithInvalidMinMaxFails(t *testing.T) {
   207  	values := []string{"", "banana", "-1", "0", "1000"}
   208  	errors := []error{commands.ErrIsRequired, commands.ErrMustBePositive, commands.ErrMustBePositive, commands.ErrMustBePositive, nil}
   209  
   210  	for i, v := range values {
   211  		err := checkProposalSubmission(&commandspb.ProposalSubmission{
   212  			Terms: &types.ProposalTerms{
   213  				Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   214  					NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   215  						Changes: &types.NewProtocolAutomatedPurchaseChanges{
   216  							MinimumAuctionSize: v,
   217  							MaximumAuctionSize: v,
   218  						},
   219  					},
   220  				},
   221  			},
   222  		})
   223  		if errors[i] != nil {
   224  			assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.minimum_auction_size"), errors[i])
   225  			assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size"), errors[i])
   226  		} else {
   227  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.minimum_auction_size"), commands.ErrIsRequired)
   228  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.minimum_auction_size"), commands.ErrMustBePositive)
   229  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size"), commands.ErrIsRequired)
   230  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size"), commands.ErrMustBePositive)
   231  		}
   232  	}
   233  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
   234  		Terms: &types.ProposalTerms{
   235  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   236  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   237  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   238  						MinimumAuctionSize: "100",
   239  						MaximumAuctionSize: "99",
   240  					},
   241  				},
   242  			},
   243  		},
   244  	})
   245  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.maximum_auction_size"), fmt.Errorf("must be greater than or equal to minimum_auction_size"))
   246  }
   247  
   248  func TestSubmissionOfNewPAPWithInvalidExpiry(t *testing.T) {
   249  	values := []int64{-1, 0, 100}
   250  	errors := []error{commands.ErrMustBePositiveOrZero, nil, nil}
   251  
   252  	for i, v := range values {
   253  		err := checkProposalSubmission(&commandspb.ProposalSubmission{
   254  			Terms: &types.ProposalTerms{
   255  				Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   256  					NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   257  						Changes: &types.NewProtocolAutomatedPurchaseChanges{
   258  							ExpiryTimestamp: v,
   259  						},
   260  					},
   261  				},
   262  			},
   263  		})
   264  		if errors[i] != nil {
   265  			assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.expiry_timestamp"), errors[i])
   266  		} else {
   267  			assert.NotContains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.expiry_timestamp"), errors[i])
   268  		}
   269  	}
   270  }
   271  
   272  func TestSubmissionInvalidAuctionScheduleFails(t *testing.T) {
   273  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
   274  		Terms: &types.ProposalTerms{
   275  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   276  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   277  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   278  						AuctionSchedule: nil,
   279  					},
   280  				},
   281  			},
   282  		},
   283  	})
   284  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_schedule"), commands.ErrIsRequired)
   285  
   286  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   287  		Terms: &types.ProposalTerms{
   288  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   289  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   290  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   291  						AuctionSchedule: &types.DataSourceDefinition{
   292  							SourceType: &types.DataSourceDefinition_External{},
   293  						},
   294  					},
   295  				},
   296  			},
   297  		},
   298  	})
   299  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_schedule"), fmt.Errorf("auction schedule must be an internal time trigger"))
   300  
   301  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   302  		Terms: &types.ProposalTerms{
   303  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   304  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   305  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   306  						AuctionSchedule: &types.DataSourceDefinition{
   307  							SourceType: &types.DataSourceDefinition_Internal{
   308  								Internal: &types.DataSourceDefinitionInternal{
   309  									SourceType: &types.DataSourceDefinitionInternal_Time{},
   310  								},
   311  							},
   312  						},
   313  					},
   314  				},
   315  			},
   316  		},
   317  	})
   318  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_schedule"), fmt.Errorf("auction schedule must be an internal time trigger"))
   319  
   320  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   321  		Terms: &types.ProposalTerms{
   322  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   323  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   324  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   325  						AuctionSchedule: &types.DataSourceDefinition{
   326  							SourceType: &types.DataSourceDefinition_Internal{
   327  								Internal: &types.DataSourceDefinitionInternal{
   328  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   329  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   330  											Triggers: []*datapb.InternalTimeTrigger{},
   331  										},
   332  									},
   333  								},
   334  							},
   335  						},
   336  					},
   337  				},
   338  			},
   339  		},
   340  	})
   341  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_schedule.internal.timetrigger"), commands.ErrOneTimeTriggerAllowedMax)
   342  
   343  	initial1 := int64(100)
   344  	initial2 := int64(200)
   345  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   346  		Terms: &types.ProposalTerms{
   347  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   348  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   349  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   350  						AuctionSchedule: &types.DataSourceDefinition{
   351  							SourceType: &types.DataSourceDefinition_Internal{
   352  								Internal: &types.DataSourceDefinitionInternal{
   353  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   354  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   355  											Triggers: []*datapb.InternalTimeTrigger{
   356  												{
   357  													Initial: &initial1,
   358  												},
   359  												{
   360  													Initial: &initial2,
   361  												},
   362  											},
   363  										},
   364  									},
   365  								},
   366  							},
   367  						},
   368  					},
   369  				},
   370  			},
   371  		},
   372  	})
   373  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_schedule.internal.timetrigger"), commands.ErrOneTimeTriggerAllowedMax)
   374  
   375  	initial1 = -100
   376  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   377  		Terms: &types.ProposalTerms{
   378  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   379  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   380  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   381  						AuctionSchedule: &types.DataSourceDefinition{
   382  							SourceType: &types.DataSourceDefinition_Internal{
   383  								Internal: &types.DataSourceDefinitionInternal{
   384  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   385  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   386  											Triggers: []*datapb.InternalTimeTrigger{
   387  												{
   388  													Initial: &initial1,
   389  												},
   390  											},
   391  										},
   392  									},
   393  								},
   394  							},
   395  						},
   396  					},
   397  				},
   398  			},
   399  		},
   400  	})
   401  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_schedule.internal.timetrigger.triggers.0.initial"), commands.ErrIsNotValid)
   402  
   403  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   404  		Terms: &types.ProposalTerms{
   405  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   406  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   407  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   408  						AuctionSchedule: &types.DataSourceDefinition{
   409  							SourceType: &types.DataSourceDefinition_Internal{
   410  								Internal: &types.DataSourceDefinitionInternal{
   411  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   412  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   413  											Triggers: []*datapb.InternalTimeTrigger{
   414  												{
   415  													Every: initial1,
   416  												},
   417  											},
   418  										},
   419  									},
   420  								},
   421  							},
   422  						},
   423  					},
   424  				},
   425  			},
   426  		},
   427  	})
   428  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_schedule.internal.timetrigger.triggers.0.every"), commands.ErrIsNotValid)
   429  }
   430  
   431  func TestSubmissionInvalidVolumeSnapshotScheduleFails(t *testing.T) {
   432  	err := checkProposalSubmission(&commandspb.ProposalSubmission{
   433  		Terms: &types.ProposalTerms{
   434  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   435  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   436  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   437  						AuctionVolumeSnapshotSchedule: nil,
   438  					},
   439  				},
   440  			},
   441  		},
   442  	})
   443  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_volume_snapshot_schedule"), commands.ErrIsRequired)
   444  
   445  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   446  		Terms: &types.ProposalTerms{
   447  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   448  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   449  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   450  						AuctionVolumeSnapshotSchedule: &types.DataSourceDefinition{
   451  							SourceType: &types.DataSourceDefinition_External{},
   452  						},
   453  					},
   454  				},
   455  			},
   456  		},
   457  	})
   458  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_volume_snapshot_schedule"), fmt.Errorf("auction volume snapshot schedule must be an internal time trigger"))
   459  
   460  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   461  		Terms: &types.ProposalTerms{
   462  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   463  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   464  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   465  						AuctionVolumeSnapshotSchedule: &types.DataSourceDefinition{
   466  							SourceType: &types.DataSourceDefinition_Internal{
   467  								Internal: &types.DataSourceDefinitionInternal{
   468  									SourceType: &types.DataSourceDefinitionInternal_Time{},
   469  								},
   470  							},
   471  						},
   472  					},
   473  				},
   474  			},
   475  		},
   476  	})
   477  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.auction_volume_snapshot_schedule"), fmt.Errorf("auction volume snapshot schedule must be an internal time trigger"))
   478  
   479  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   480  		Terms: &types.ProposalTerms{
   481  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   482  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   483  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   484  						AuctionVolumeSnapshotSchedule: &types.DataSourceDefinition{
   485  							SourceType: &types.DataSourceDefinition_Internal{
   486  								Internal: &types.DataSourceDefinitionInternal{
   487  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   488  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   489  											Triggers: []*datapb.InternalTimeTrigger{},
   490  										},
   491  									},
   492  								},
   493  							},
   494  						},
   495  					},
   496  				},
   497  			},
   498  		},
   499  	})
   500  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_volume_snapshot_schedule.internal.timetrigger"), commands.ErrOneTimeTriggerAllowedMax)
   501  
   502  	initial1 := int64(100)
   503  	initial2 := int64(200)
   504  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   505  		Terms: &types.ProposalTerms{
   506  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   507  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   508  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   509  						AuctionVolumeSnapshotSchedule: &types.DataSourceDefinition{
   510  							SourceType: &types.DataSourceDefinition_Internal{
   511  								Internal: &types.DataSourceDefinitionInternal{
   512  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   513  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   514  											Triggers: []*datapb.InternalTimeTrigger{
   515  												{
   516  													Initial: &initial1,
   517  												},
   518  												{
   519  													Initial: &initial2,
   520  												},
   521  											},
   522  										},
   523  									},
   524  								},
   525  							},
   526  						},
   527  					},
   528  				},
   529  			},
   530  		},
   531  	})
   532  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_volume_snapshot_schedule.internal.timetrigger"), commands.ErrOneTimeTriggerAllowedMax)
   533  
   534  	initial1 = -100
   535  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   536  		Terms: &types.ProposalTerms{
   537  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   538  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   539  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   540  						AuctionVolumeSnapshotSchedule: &types.DataSourceDefinition{
   541  							SourceType: &types.DataSourceDefinition_Internal{
   542  								Internal: &types.DataSourceDefinitionInternal{
   543  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   544  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   545  											Triggers: []*datapb.InternalTimeTrigger{
   546  												{
   547  													Initial: &initial1,
   548  												},
   549  											},
   550  										},
   551  									},
   552  								},
   553  							},
   554  						},
   555  					},
   556  				},
   557  			},
   558  		},
   559  	})
   560  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_volume_snapshot_schedule.internal.timetrigger.triggers.0.initial"), commands.ErrIsNotValid)
   561  
   562  	err = checkProposalSubmission(&commandspb.ProposalSubmission{
   563  		Terms: &types.ProposalTerms{
   564  			Change: &types.ProposalTerms_NewProtocolAutomatedPurchase{
   565  				NewProtocolAutomatedPurchase: &types.NewProtocolAutomatedPurchase{
   566  					Changes: &types.NewProtocolAutomatedPurchaseChanges{
   567  						AuctionVolumeSnapshotSchedule: &types.DataSourceDefinition{
   568  							SourceType: &types.DataSourceDefinition_Internal{
   569  								Internal: &types.DataSourceDefinitionInternal{
   570  									SourceType: &types.DataSourceDefinitionInternal_TimeTrigger{
   571  										TimeTrigger: &types.DataSourceSpecConfigurationTimeTrigger{
   572  											Triggers: []*datapb.InternalTimeTrigger{
   573  												{
   574  													Every: initial1,
   575  												},
   576  											},
   577  										},
   578  									},
   579  								},
   580  							},
   581  						},
   582  					},
   583  				},
   584  			},
   585  		},
   586  	})
   587  	assert.Contains(t, err.Get("proposal_submission.terms.change.protocol_automated_purchase.changes.data_spec_for_auction_volume_snapshot_schedule.internal.timetrigger.triggers.0.every"), commands.ErrIsNotValid)
   588  }