@@ -40,15 +40,33 @@ abstract contract PythGovernance is
4040    );
4141    event TransactionFeeSet  (uint  oldFee , uint  newFee );
4242    event FeeWithdrawn  (address  targetAddress , uint  fee );
43+     event VerifierAddressSet  (
44+         address  oldVerifierAddress ,
45+         address  newVerifierAddress 
46+     );
4347
44-     function verifyGovernanceVM  (
48+     // Check whether the encodedVM is signed by either the Wormhole or the Verifier. 
49+     function validateVm  (
4550        bytes  memory  encodedVM 
46-     ) internal  returns  (IWormhole.VM memory  parsedVM ) {
51+     ) internal  view   returns  (IWormhole.VM memory  parsedVM ) {
4752        (IWormhole.VM memory  vm , bool  valid , ) =  wormhole ().parseAndVerifyVM (
4853            encodedVM
4954        );
55+         if  (valid) return  vm;
5056
51-         if  (! valid) revert  PythErrors.InvalidWormholeVaa ();
57+         if  (address (verifier ()) !=  address (0 )) {
58+             (IWormhole.VM memory  vmv , bool  validv , ) =  verifier ()
59+                 .parseAndVerifyVM (encodedVM);
60+             if  (validv) return  vmv;
61+         }
62+ 
63+         revert  PythErrors.InvalidWormholeVaa ();
64+     }
65+ 
66+     function verifyGovernanceVM  (
67+         bytes  memory  encodedVM 
68+     ) internal  returns  (IWormhole.VM memory  parsedVM ) {
69+         IWormhole.VM memory  vm =  validateVm (encodedVM);
5270
5371        if  (! isValidGovernanceDataSource (vm.emitterChainId, vm.emitterAddress))
5472            revert  PythErrors.InvalidGovernanceDataSource ();
@@ -105,6 +123,13 @@ abstract contract PythGovernance is
105123            setTransactionFee (parseSetTransactionFeePayload (gi.payload));
106124        } else  if  (gi.action ==  GovernanceAction.WithdrawFee) {
107125            withdrawFee (parseWithdrawFeePayload (gi.payload));
126+         } else  if  (gi.action ==  GovernanceAction.SetVerifierAddress) {
127+             if  (gi.targetChainId ==  0 )
128+                 revert  PythErrors.InvalidGovernanceTarget ();
129+             setVerifierAddress (
130+                 parseSetVerifierAddressPayload (gi.payload),
131+                 encodedVM
132+             );
108133        } else  {
109134            revert  PythErrors.InvalidGovernanceMessage ();
110135        }
@@ -131,11 +156,8 @@ abstract contract PythGovernance is
131156        // Make sure the claimVaa is a valid VAA with RequestGovernanceDataSourceTransfer governance message 
132157        // If it's valid then its emitter can take over the governance from the current emitter. 
133158        // The VAA is checked here to ensure that the new governance data source is valid and can send message 
134-         // through wormhole. 
135-         (IWormhole.VM memory  vm , bool  valid , ) =  wormhole ().parseAndVerifyVM (
136-             payload.claimVaa
137-         );
138-         if  (! valid) revert  PythErrors.InvalidWormholeVaa ();
159+         // through wormhole or verifier. 
160+         IWormhole.VM memory  vm =  validateVm (payload.claimVaa);
139161
140162        GovernanceInstruction memory  gi =  parseGovernanceInstruction (
141163            vm.payload
@@ -210,6 +232,8 @@ abstract contract PythGovernance is
210232        emit  ValidPeriodSet (oldValidPeriod, validTimePeriodSeconds ());
211233    }
212234
235+     // If the VAA was created by Verifier, this will revert, 
236+     // because it assumes that the new Wormhole is able to parse and verify the governance VAA. 
213237    function setWormholeAddress  (
214238        SetWormholeAddressPayload memory  payload ,
215239        bytes  memory  encodedVM 
@@ -270,4 +294,48 @@ abstract contract PythGovernance is
270294
271295        emit  FeeWithdrawn (payload.targetAddress, payload.fee);
272296    }
297+ 
298+     // If the VAA was created by Wormhole, this will revert, 
299+     // because it assumes that the new Verifier is able to parse and verify the governance VAA. 
300+     function setVerifierAddress  (
301+         SetVerifierAddressPayload memory  payload ,
302+         bytes  memory  encodedVM 
303+     ) internal  {
304+         address  oldVerifierAddress =  address (verifier ());
305+         setVerifier (payload.newVerifierAddress);
306+ 
307+         // We want to verify that the new verifier address is valid, so we make sure that it can 
308+         // parse and verify the same governance VAA that is used to set it. 
309+         (IWormhole.VM memory  vm , bool  valid , ) =  verifier ().parseAndVerifyVM (
310+             encodedVM
311+         );
312+ 
313+         if  (! valid) revert  PythErrors.InvalidGovernanceMessage ();
314+ 
315+         if  (! isValidGovernanceDataSource (vm.emitterChainId, vm.emitterAddress))
316+             revert  PythErrors.InvalidGovernanceMessage ();
317+ 
318+         if  (vm.sequence !=  lastExecutedGovernanceSequence ())
319+             revert  PythErrors.InvalidVerifierAddressToSet ();
320+ 
321+         GovernanceInstruction memory  gi =  parseGovernanceInstruction (
322+             vm.payload
323+         );
324+ 
325+         if  (gi.action !=  GovernanceAction.SetVerifierAddress)
326+             revert  PythErrors.InvalidVerifierAddressToSet ();
327+ 
328+         // Purposefully, we don't check whether the chainId is the same as the current chainId because 
329+         // we might want to change the chain id of the verifier contract. 
330+ 
331+         // The following check is not necessary for security, but is a sanity check that the new verifier 
332+         // contract parses the payload correctly. 
333+         SetVerifierAddressPayload
334+             memory  newPayload =  parseSetVerifierAddressPayload (gi.payload);
335+ 
336+         if  (newPayload.newVerifierAddress !=  payload.newVerifierAddress)
337+             revert  PythErrors.InvalidVerifierAddressToSet ();
338+ 
339+         emit  VerifierAddressSet (oldVerifierAddress, address (verifier ()));
340+     }
273341}
0 commit comments