Skip to content

Diamond Proxy pattern based smart contracts#16

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

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

Conversation

@udityadav-supraoracles
Copy link
Copy Markdown

@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
Copy Markdown
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 thread solidity/supra_contracts/src/facets/ConfigFacet.sol Outdated
Comment thread solidity/supra_contracts/src/facets/ConfigFacet.sol Outdated
Comment thread solidity/supra_contracts/src/facets/ConfigFacet.sol Outdated
Comment thread solidity/supra_contracts/src/facets/ConfigFacet.sol Outdated
Comment thread solidity/supra_contracts/src/facets/CoreFacet.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibAccounting.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibAccounting.sol
Comment thread solidity/supra_contracts/src/libraries/LibCommon.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibCommon.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibCore.sol
@sjoshisupra
Copy link
Copy Markdown

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.

Hi @udityadav-supraoracles , in that case we should use the guidelines and avoid nested structs.

Comment thread solidity/supra_contracts/src/libraries/LibAccounting.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibCommon.sol
Comment thread solidity/supra_contracts/src/libraries/LibCommon.sol Outdated

library LibDiamond {
// 32 bytes keccak hash of a string to use as a diamond storage location.
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shall we modify the string passed to keccak256? It looks like this came from template and to ensure the storage at random location, we should use a unique string. @udityadav-supraoracles

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, this is from the standard Diamond implementation. Existing string "diamond.standard.diamond.storage" also creates a unique storage slot for our Diamond contract.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The concept of having dedicated slot for the shared storage is a standard, but I think we can use automation registry as part of the string defining the unique position, such as diamond.registry.automation.storage.

Comment thread solidity/supra_contracts/src/libraries/LibDiamondUtils.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20SupraHandler.sol
Comment thread solidity/supra_contracts/src/libraries/LibAccounting.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibDiamondUtils.sol Outdated
Comment thread solidity/supra_contracts/src/libraries/LibDiamondUtils.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20Supra.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20Supra.sol
Comment thread solidity/supra_contracts/src/ERC20SupraHandler.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20SupraHandler.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20SupraHandler.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20SupraHandler.sol
Comment thread solidity/supra_contracts/src/ERC20SupraHandler.sol Outdated
// Check caller is VM Signer
msg.sender.enforceIsVmSigner(s.vmSigner);

LibCore.handleTaskRemoval(_taskIndex);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Do we need a method for bulk removal? Also, shouldn't Vm signer also pass some diagnosic message for removal which should be emitted as an event?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'll add a parameter for diagnostic message. @aregng please let me know your opinion if we require a method for bulk removal?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Yes bulk task removal will be preferable, in similar fashion as tasks are processed in bulk in scope of processTasks

);

/// @notice Emitted when a task is removed due to predicate validation failure.
event TaskRemovedAsPredicateFailed(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We may want to remove the task for multiple reasons, right? 1) Predicate is malformed due to invalid bytecode 2) Predicate is exceeding gas limits imposed, we should have a uniform mechanism for VM signer to convey the reason of failure from layer below @aregng @udityadav-supraoracles

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@udityadav-supraoracles , can a view funcion have a failing assert? The questions is should we remove a predicate that fails an assert. @aregng

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'll add a string parameter which can be used to convey the reason for failure.

It is possible for a view function to have an assertion. Let's say it can only be called by whitelisted addresses, in that case it'll fail.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@udityadav-supraoracles typically view functions are never access controlled, since they are just meant for viewing, so either it is view method or a private method. WHat use case do we have to have access control on view?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agree with you Dr @sjoshisupra , largely they're not access controlled. I only mentioned it to depict a scenario where view function can revert.

Comment thread solidity/supra_contracts/src/libraries/LibRegistry.sol Outdated
Comment thread solidity/supra_contracts/src/ERC20Supra.sol Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated

password=""
if [ -n ${PASSWORD} ]; then
password="--password ${PASSWORD}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

not sure what is being done here, if the variable is not set, how does "--passowrd ${PASSWORD}" help?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If PASSWORD is set then that value will be utilised as password else forge will prompt to input the password.

Copy link
Copy Markdown

@sjoshisupra sjoshisupra left a comment

Choose a reason for hiding this comment

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

Let's use 20M for user and system registry gas reserve, 1M is too low to be of any practical use.

);

/// @notice Emitted when a task is removed due to predicate validation failure.
event TaskRemovedAsPredicateFailed(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@udityadav-supraoracles typically view functions are never access controlled, since they are just meant for viewing, so either it is view method or a private method. WHat use case do we have to have access control on view?

Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/run.sh Outdated
Comment thread solidity/supra_contracts/src/SupraContractsBindings.sol
Comment thread solidity/supra_contracts/src/upgradeInitializers/DiamondInit.sol
@aregng
Copy link
Copy Markdown

aregng commented Apr 21, 2026

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.

Mapping point option is preferable and is currently implemented.

Comment on lines +11 to +13

// Address of the VM Signer: SUP0
address constant VM_SIGNER = address(0x53555000);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Here we have VM_SIGNER constant, but also we specify it as input parameter during initialization. Besides we also specify the manually vm_signer when checking condition of sender to be VM_SIGNER.
Suggestion: instead of specifying it VM_SINGER as input param, let's instead use the hardcoded constant. As mentioned by Dr. @sjoshisupra it is not going to be change at all.

Comment thread solidity/supra_contracts/src/facets/CoreFacet.sol

library LibDiamond {
// 32 bytes keccak hash of a string to use as a diamond storage location.
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The concept of having dedicated slot for the shared storage is a standard, but I think we can use automation registry as part of the string defining the unique position, such as diamond.registry.automation.storage.

// Check caller is VM Signer
msg.sender.enforceIsVmSigner(s.vmSigner);

LibCore.handleTaskRemoval(_taskIndex);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Yes bulk task removal will be preferable, in similar fashion as tasks are processed in bulk in scope of processTasks

@udityadav-supraoracles
Copy link
Copy Markdown
Author

s.cycleState shows the current state of the registry, so if it is READY and automation feature flag is enabled, then we move to STARTED state. One thing that can be done to improve user experience in case if state is not READY, to revert the call with error indicating inconsistent state.

@aregng So, you mean if cycle state is not READY then enableAutomation should revert? In that case
testProcessTasksWhenCycleStateSuspendedAutomationEnabled fails for automation enabled condition

@aregng
Copy link
Copy Markdown

aregng commented Apr 22, 2026

s.cycleState shows the current state of the registry, so if it is READY and automation feature flag is enabled, then we move to STARTED state. One thing that can be done to improve user experience in case if state is not READY, to revert the call with error indicating inconsistent state.

@aregng So, you mean if cycle state is not READY then enableAutomation should revert? In that case testProcessTasksWhenCycleStateSuspendedAutomationEnabled fails for automation enabled condition

Oh, I see, I missed the use-case when automation-feature is being disabled during transition state.
The current implementation is good then.


// Refund only for UST
if (!isGst) {
bool result = LibAccounting.safeDepositRefund(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

According to discussion related to task removal on predicate failure documented in this ticket: https://github.com/Entropy-Foundation/smr-moonshot/issues/2648
the tasks with failed/invalid predicate will the removed and the same refund logic will be applied to the tasks as if they have been stopped by user.
Which implies full deposit refund and refund of the half of automation cycle fee for the remaining cycle time.

Dr. @sjoshisupra , @udityadav-supraoracles , was the requirement incorrectly documented or it has been changed over the time ?

Copy link
Copy Markdown
Author

@udityadav-supraoracles udityadav-supraoracles Apr 23, 2026

Choose a reason for hiding this comment

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

@aregng Actually during the Meet you mentioned that user will be refunded as if they've cancelled the task which is in PENDING state. So, based on that I had implemented refund logic.

if (!s.ifTransitionStateExists) { revert InvalidRegistryState(); }

if (isTransitionFinalized()) {
if (!s.automationEnabled && s.cycleState == LibCommon.CycleState.FINISHED) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Usecase:

  • Cycle is in transition state and transition is in progress
  • Automation Feature is disabled
  • Cycle transition ends

Here we attempt to move to suspend state which will revert as transition state exists and it is in progress.

Described scenario is a valid one.
In this case transition to SUSPENED state should happen via STARTED state, which means first here we should transition to STARTED state always when cycle transition is finalized, i.e update cycle index by one and set cycle state to STARTED and only after that check if automation-feature flag is false, directly transition to suspended state.

I will update the ticket describing the transition table.
https://github.com/Entropy-Foundation/smr-moonshot/issues/2523#issuecomment-3677617421

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.

3 participants