diff --git a/target_chains/ethereum/contracts/contracts/pyth/Pyth.sol b/target_chains/ethereum/contracts/contracts/pyth/Pyth.sol index dbc2be966c..f97b7bda89 100644 --- a/target_chains/ethereum/contracts/contracts/pyth/Pyth.sol +++ b/target_chains/ethereum/contracts/contracts/pyth/Pyth.sol @@ -493,8 +493,11 @@ abstract contract Pyth is function getTotalFee( uint totalNumUpdates ) private view returns (uint requiredFee) { - return - (totalNumUpdates * singleUpdateFeeInWei()) + transactionFeeInWei(); + uint updateFee = customUpdateFeeInWei(msg.sender); + if (updateFee == 0) { + updateFee = singleUpdateFeeInWei(); + } + return (totalNumUpdates * updateFee) + transactionFeeInWei(); } function findIndexOfPriceId( diff --git a/target_chains/ethereum/contracts/contracts/pyth/PythGetters.sol b/target_chains/ethereum/contracts/contracts/pyth/PythGetters.sol index e0146da190..d7458326b2 100644 --- a/target_chains/ethereum/contracts/contracts/pyth/PythGetters.sol +++ b/target_chains/ethereum/contracts/contracts/pyth/PythGetters.sol @@ -95,4 +95,8 @@ contract PythGetters is PythState { function transactionFeeInWei() public view returns (uint) { return _state.transactionFeeInWei; } + + function customUpdateFeeInWei(address addr) public view returns (uint) { + return _state.customUpdateFeeInWei[addr]; + } } diff --git a/target_chains/ethereum/contracts/contracts/pyth/PythGovernance.sol b/target_chains/ethereum/contracts/contracts/pyth/PythGovernance.sol index 5bb1bd3265..13bc39f5e2 100644 --- a/target_chains/ethereum/contracts/contracts/pyth/PythGovernance.sol +++ b/target_chains/ethereum/contracts/contracts/pyth/PythGovernance.sol @@ -39,6 +39,12 @@ abstract contract PythGovernance is address newWormholeAddress ); event TransactionFeeSet(uint oldFee, uint newFee); + event CustomFeeSet(address indexed target, uint oldFee, uint newFee); + + struct SetCustomFeePayload { + address target; + uint newFee; + } function verifyGovernanceVM( bytes memory encodedVM @@ -255,4 +261,11 @@ abstract contract PythGovernance is emit TransactionFeeSet(oldFee, transactionFeeInWei()); } + + function setCustomFee(SetCustomFeePayload memory payload) internal { + uint oldFee = customUpdateFeeInWei(payload.target); + setCustomUpdateFeeInWei(payload.target, payload.newFee); + + emit CustomFeeSet(payload.target, oldFee, payload.newFee); + } } diff --git a/target_chains/ethereum/contracts/contracts/pyth/PythSetters.sol b/target_chains/ethereum/contracts/contracts/pyth/PythSetters.sol index 849fc7659f..4fbb0ea15f 100644 --- a/target_chains/ethereum/contracts/contracts/pyth/PythSetters.sol +++ b/target_chains/ethereum/contracts/contracts/pyth/PythSetters.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.0; import "./PythState.sol"; import "@pythnetwork/pyth-sdk-solidity/IPythEvents.sol"; +import "./PythInternalStructs.sol"; contract PythSetters is PythState, IPythEvents { function setWormhole(address wh) internal { @@ -52,4 +53,8 @@ contract PythSetters is PythState, IPythEvents { function setTransactionFeeInWei(uint fee) internal { _state.transactionFeeInWei = fee; } + + function setCustomUpdateFeeInWei(address addr, uint fee) internal { + _state.customUpdateFeeInWei[addr] = fee; + } } diff --git a/target_chains/ethereum/contracts/contracts/pyth/PythState.sol b/target_chains/ethereum/contracts/contracts/pyth/PythState.sol index a860a4341b..b5a197626d 100644 --- a/target_chains/ethereum/contracts/contracts/pyth/PythState.sol +++ b/target_chains/ethereum/contracts/contracts/pyth/PythState.sol @@ -40,6 +40,8 @@ contract PythStorage { mapping(bytes32 => PythInternalStructs.PriceInfo) latestPriceInfo; // Fee charged per transaction, in addition to per-update fees uint transactionFeeInWei; + // Mapping of address to custom fee per update (0 means use default fee) + mapping(address => uint) customUpdateFeeInWei; } }