Skip to content

Comments

Diamond Proxy pattern based smart contracts#16

Open
udityadav-supraoracles wants to merge 9 commits intofeature/evm_automationfrom
feature/diamond_proxy_automation_registry
Open

Diamond Proxy pattern based smart contracts#16
udityadav-supraoracles wants to merge 9 commits intofeature/evm_automationfrom
feature/diamond_proxy_automation_registry

Conversation

@udityadav-supraoracles
Copy link

@udityadav-supraoracles udityadav-supraoracles commented Feb 17, 2026

This PR includes changes to accommodate use of Diamond Proxy pattern for EVM Automation Registry smart contracts.

-includes:
facets: ConfigFacet. RegistryFacet and CoreFacet.
DiamondInit: This contract is used to initialise the state of Diamond, its not added as facet. So, we don't have a flag to check for initialisation. Once Diamond is deployed, this contract is supposed to be called as part of diamondCut.

@udityadav-supraoracles udityadav-supraoracles marked this pull request as ready for review February 19, 2026 08:43
@udityadav-supraoracles
Copy link
Author

Currently the AppStorage have inner structs which doesn't allow the inner structs to be expanded later. Either we can have all variables in AppStorage struct or have a mapping pointing to inner struct as structs pointing by mapping are expandable.

Referring to: https://eip2535diamonds.substack.com/p/diamond-upgrades
Do not put structs directly in structs unless you don’t plan on ever adding more state variables to the inner structs. You won't be able to add new state variables to inner structs in upgrades without overwriting existing state variables.

Please let me know your opinion Dr @sjoshisupra @aregng.

Comment on lines +60 to +69
function setVmSigner(address _vmSigner) external {
LibDiamond.enforceIsContractOwner();

LibUtils.validateAddress(_vmSigner);

address oldVmSigner = s.vmSigner;
s.vmSigner = _vmSigner;

emit VmSignerUpdated(oldVmSigner, _vmSigner);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@udityadav-supraoracles, @aregng, I do not foresee any circumstances for VM_SIGNER to change since this is hard coded in rust layer. Is this method only to initialize after contract deployment or do we foresee this to be useful? If not, perhaps we should not have this API (if this is initialized with appropriate VM_SIGNER address at the time of deployment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The VM_SIGNER and ERC20Supra both are initialised at the time of deployment. We can remove their respective API's to update the addresses if we do not plan to change them later. Please let me know your opinion @aregng .


/// @notice Function to update the ERC20Supra address.
/// @param _erc20Supra New address for ERC20Supra.
function setErc20Supra(address _erc20Supra) external {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@udityadav-supraoracles, is this to update ERC 20 contract address? Or to update the address of the registry itself where it stores ERC20 tokens collected from fee? It is not clear from the comments.
If it is the former, why does registry contract need to know ERC20 contract address?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is meant to update the address of ERC20Supra contract in registry, as the registry holds ERC20Supra address. The registry needs to know ERC20Supra's address in order to call transferFrom on it while charging fees.

Regarding fee collection, fee charged in terms of ERC20Supra tokens is stored at the registry's address(ERC20 standard contract inherited by ERC20Supra maintains mapping _balances where it stores the registry's balance).

uint256 balance = IERC20(s.erc20Supra).balanceOf(address(this));

if (balance < _amount) { revert InsufficientBalance(); }
if (balance - _amount < s.registryState.cycleLockedFees + s.registryState.totalDepositedAutomationFees) { revert RequestExceedsLockedBalance(); }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@udityadav-supraoracles, something seems off. I believe we want to withdraw from s.registryState.totalDepostedAutomationFees, meaning that shouldn't the expression be
balance - _amount < s.registryState.cycleLockedFees? does totalDepositedAutomationFees refer to fees or does it refer to the caution that we take to deter DOS via cancellation?

Comment on lines +132 to +133
if (s.registryState.gasCommittedForNextCycle > _registryMaxGasCap) { revert UnacceptableRegistryMaxGasCap(); }
if (s.registryState.sysGasCommittedForNextCycle > _sysRegistryMaxGasCap) { revert UnacceptableSysRegistryMaxGasCap(); }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@udityadav-supraoracles, shouldn't these two checks also be part of LibCommon.validateConfigParameters method? This seems like validation checks only.

/// @param _taskIndexes Array of task index to be processed.
function processTasks(uint64 _cycleIndex, uint64[] memory _taskIndexes) external {
// Check caller is VM Signer
if (msg.sender != s.vmSigner) { revert CallerNotVmSigner(); }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@udityadav-supraoracles, it is better to have a common method enforceIsVmSigner similar to enforceIsContractOwner.

uint256 thresholdScaledAsFraction = thresholdPercentageScaled / 100; // DECIMAL-scaled fraction
uint256 surplusClipped = thresholdScaledAsFraction + surplusScaled > DECIMAL ? DECIMAL - thresholdScaledAsFraction : surplusScaled;

uint256 baseScaled = DECIMAL + surplusClipped; // (1 + base)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

take the exponential computation out as a separate private method. @udityadav-supraoracles

return uint128(automationFeeForInterval / DECIMAL);
}

// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: INTERNAL FUNCTIONS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are methods above this line which are also internal, right? @udityadav-supraoracles

/// @notice Helper function to sort an array.
/// @param arr Input array to sort.
/// @return Returns the sorted array.
function sortUint64(uint64[] memory arr) internal pure returns (uint64[] memory) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use quick / heap sort, perhaps there might be existing library in solidity which does this. current sorting is highly inefficient @udityadav-supraoracles

/// @notice Helper function to sort an array.
/// @param arr Input array to sort.
/// @return Returns the sorted array.
function sortUint256(uint256[] memory arr) internal pure returns (uint256[] memory) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same suggestion, find library or use quick/heap sort @udityadav-supraoracles

/// @return intermediateState Returns the intermediate state.
function dropOrChargeTasks(
uint64[] memory _taskIndexes
) private returns (LibCommon.IntermediateStateOfCycleChange memory intermediateState) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this be private? I believe this need to be called by VM_SIGNER right? In fact, multiple places I believe methods are marked as private which may not work with evm and they need to be restricted to be called by VM_SIGNER only. @udityadav-supraoracles @aregng

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is called from onCycleTransition defined as internal in the same library which furthur gets called by VM_SIGNER facing function processTasks. So, there's no issue with this function being marked as private as its not directly called by VM_SIGNER.

VM_SIGNER only calls monitorCycleEnd and processTasks which're marked as external and other helper functions are marked as internal or private.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants