Moving Access Control Away From Smart Contracts' Code

DeFi Security Summit at Devconnect Argentina 2025 · November 2025 · 19:12

Guillermo Narvaja, co-founder and CTO of Ensuro, challenges the industry standard of hardwiring access control policy directly into smart contract code. He presents an alternative that makes deployed access control rules easy to observe and audit, so that users and reviewers can see who is allowed to do what without reading the contract's implementation.

Speakers

Topics

From DeFi Security Summit at Devconnect Argentina 2025, hosted by DeFi Security Summit.

Transcript

Hi, good afternoon. Well, today I'm going to talk to you about the design pattern that we are applying to the de development of our smart contracts in our protocol. Uh that implies like removing the access control decision from the coding time or moving from the coding time the access control decisions to the deployment or configuration time. Well, a few words about words about me. I'm an Argentinian software engineer with more than 25 years of of experience since 2021 at the CTO and founder co-founder of Insuro. Insur is a blockchain based reinsurance.

Uh we cover real world risk uh using blockchain infrastructure and well let's go to the topic first. Uh let's start with with an introduction. Um so regarding access control in solidity or in the ABM uh is typically so first all the methods are open by default. So this that creates a problem or let's say unless we specify rule every method is going to be accessible by anyone.

The way we implement that is with modifiers in each contract. Erh typically access control is used to restrict some operations to administrative access. erh like different roles and but this also use it uh for emergency post like for posting specific methods we well we also part of the access control scope is also defined in time logs um and yes and mostly is implemented through the opening library that has uh several implementation for the different patterns that I'm going to go over and later to explain our our pattern and yeah finally I want to mention that also

lot of contracts you are upgradable and use proxies and that will become relevant for for the next part so let's start with the ownable that's the simplest and oldest uh design pattern for setting access control is super simple you just decorate the method with only owner and and that's all it's easy but it doesn't have any granularity like you only have one user that can do administrative task to any methods. So then we have the access control. This is the second most used. So this is this gives more flexibility. You can define different named roles for different methods. You still need to make decisions at the coding time. Okay, I'm

going to use the same role for these two methods or I'm going to create different roles for each methods and those decisions are made at at coding time. And another problem is the AC the access contract configuration is done at the smart contract level. So if you have 10 contracts you need to define 10 rules. Another special case is the postable contract that is typically like I I I use the include this in access control. In this case, we don't re restrict the access to the contract based on the user, but instead based on a given state of the protocol of the contract that says if the contract is posted or not that is typically used for emergency

post and is also implemented with a decorator, but again it's another coding time decision that you need to decide okay which methods are going to be posable and which not. Finally, we have the access managed or access manager plus access managed pattern. So this is a contract introduced in open sle in version 5 in December 2023. So for me it's a it's not so widely used it but it's a big step forward in the direction that we we are presenting in this in this panel in this presentation because um it allows you to so first uh it works with an access

manager contract that concentrates all the access rules of a given protocol of a set of contracts and then the contracts are access managed meaning that they delegate the access control to another contract and they just so you just decorate the contracts. The only decision that you need to take at coding time is adding a restricted modifier. Then at the configuration time you can decide okay who can access if the same role can access different methods or or whatever. It still has the same problem.

So has many many other benefits. For example, the access manager includes built-in support for time logs. That is good. So you don't need to use a different contract to implement time locks. But you still have the same problem that the decision of decorating which methods are going to be restricted is a decision that needs to be taken at coding time. So to summarize like all these patterns have this this set of problems right first we have um a hardwired logic right access control logic all the logic is hardwired in the code you need to define which methods are going to be like in some cases more or less like from from

the scope from going to oable to access manage it but you still need to make the decision at coding time and it's something that you can change another impact of this is increased contract size because all these goes to the is part of the implementation of each methods. This check of okay I need to call this contract to check if this method is restricted or not or if it's enabled or not. This adds a lot of burden at the at the testing time because if you want to reach like 100 coverage, 100 branch coverage, you need to test all the special cases like for each method testing. Okay, a non user cannot call this method but authorized user can call this method and this and

so on like and you you end up doing a lot of repetitive test for for testing that kind of that kind of behavior. And also for your normal test when you want to test the logic of your contracts, you still need to do all the setup of setting up the rules and saying okay this is going to be applied by the admin. And the final effect is the bad observability, right? So you can't um it's it's very hard once a code is deployed to know what are what is the access contract configuration of a given contract. You need to read the code and from there you need to see okay which methods have the this modifier and based

on that you you will go and check the access manager contract. So it's very hard to programmatically assess or understand what is the access control configuration of a given protocol or contract. So the alternative let's move away the access control logic of of our smart contract. And how we do it, we move it to the proxy to just three lines in the in the proxy. So here we have the the basically the the minimal version of the access management proxy the the contract that we are introducing that that's just that. So first let's let's recap the the ERC

19767 proxy is the standard proxy used for upgradeable contract just receives all the calls and delegates the call to the implementation contract. What we are doing is before delegating the call we are calling the access manager contract to check if that method based on the selector is allowed or not for for the user that is calling. So only with this configuration we can remove all the access uh control logic from our implementation contracts. So the impact is is huge.

This is functionally equivalent to using the access manager of open sele 5 and decorating all your methods with the restricted uh decorator modifier. Uh it has a gas impact and this is also a problem. Typically, you don't want to add the possibility of adding access control to the views because doesn't make a lot of sense. Unfortunately, the EVM doesn't have a way to detect if I'm being called in a view or not. So, it's hard to detect that.

So, one optimization we did is we allow to construct the proxy with a set of skiped methods. So those methods are going to be a skip of the access control validation. So in that way we we reduce the so that part means that at deployment time so in some part of the configuration will be done at production time. So we have every method that is restricted then at production time with the access manager configuration you can say okay this is delegated to the public role. that means that this method can be called by anyone or this is delegated to I don't know back office role and so on that is configuration time this is for

for a bit of optimization uh the decision that you still can take at the deployment time when you deploy the proxy you can define okay this set of methods are going to be skipped and then for for gas optimization we avoid calling the access manager still is much better than defi defining that at the coding time and the and we will see like in terms of gas implication. So the the gas overhead of using this approach is is a minimal or is the is exactly the same as using like for a skip method is exactly the same as using a proxy. So the difference is only 1,00 gas 1,500 gas and for non-s skipped methods is

more or less the same as using the access manager pattern of open seline. So what are the the benefits like no more hardwired logic in your contracts. So you remove all the all that code all those modifiers the the implementation code becomes much more simpler and as I said like those decisions are postponed up to the deployment phase and you may have like a different configuration uh for example you can do a closed beta where you deploy uh your contracts initially all your methods are access are restricted to specific users

that have a given RO and then you can make those those methods public and you open your protocol to anyone like stuff like that is a it's very simple to implement with this and you have all that flexibility. In terms of contract size, we are also seeing like between 10 or 20% reduction in the contract size. And uh and this is even more if if we remove the post base because with this you don't need anymore the post base. The access manager proxy. So the access manager contract of open sling has a method that allows you to put set target closed and then any call to a given contract is going to be

stopped or posted or rejected let's say in terms of uh testing I for me this is the best part because uh when doing all your test you forget about testing about access control so you don't need to test this method is accessible or is restricted or not. You don't need to do all the setup and in your test you can focus on testing your core logic. So um we our testing library or our JavaScript library that comes with the this access management proxy allows you to deploy the proxy with all the methods open. So for testing, of course, that is

crazy doing that for production, but for testing is a is a perfect setup because you you just test the contract logic and you forget about the access control. And then a final benefit and I think this is the the most profound one uh or or the one that will have more impact if this is more used as a practice is a better observability because now with this uh all the access control logic can be quered from the blockchain. You just need to query the access manager configuration or or the proxy perhaps for the pass through method for the

skipped methods but only that just quering the blockchain you can you can know what is access configuration for a given protocol or for a given contract instead of I don't know going and reading and parsing the code and seeing which method have a given decorator um and this enables doing like as as we do in in Ensuro, we have a manifest where we declare what is our access control configuration in a readable format and we have tools that monitor the access the the onchain configuration compared to this manifest and we have tools also to apply the changes. So the onchain configuration is the same as the

manifest. So this enables a lot of benefits regarding making the access control configuration much more visual, much more transparent uh and easily to to to manage. So finally some final thought. So hopefully well first I expect that you like this approach and you start using it on your project. I'm open to questions in caseh you you have doubts about it. But if this becomes more widely used and more standardized then the benefit will be very good for the ecosystem because uh we will have an

standardized way of uh reading the access control configuration. Now we have different implementation. I don't know the other day I was reading the morpho v2 code and that is a great project. I like morpho. I don't want to say anything bad about them but they are like reimplementing or reimplementing a way of doing access control and that is a problem for standardizing monitoring or for all the people that wants to track okay this contract is upgradable with the six days of delay with the this amount or this operation is done by by this or that is delegated to a multisig for doing with this doing all that work is super transparent super easy to do it without this It's a pain.

And finally, what something I I'm dream I would like to see in solidity some support for kind of a method that says predispatch hook. So before dispatching the call to a specific method, some hook where you can put in solidity code that allows you to put this. In this case, we can implement the same behavior that I presented here without the proxy. So it's kind of a something that I think I I'm not an expert in the internals of solidity but probably something that can be implemented. So thanks uh well there you have first ensur website in case you're wondering there is the GitHub repository for the access manager proxy at least the it's a minimal code it's

not so important but in case you want to use it there is the link of the pull request where we apply that change to ensur finally in case also there is an issue that I submitted to open sepine so they can include it in in open sele library there kind of the standard library and so you can go and vote. Well, thanks. I think we have time for for questions. >> Questions if you have time for questions.

>> There's no questions. So, you can just go up. >> There is a someone racing there. Put >> those hands up high. Thanks for coming here. Uh uh great presentation. Thank you so much. Um in your hooks basically you're passing the message signature to the access manager. You're not passing the uh the call data itself for the analysis. Now um you might have seen my ERC it is 7746 where I suggested to doing the generic middleware hooks which basically is very similar to what you're doing. Um the

only difference is that I suggested to pass the message data as well to the access manager so that you can have logic based on that. So what was your design consideration around that? Thanks. Uh yes sorry I I I don't know if I get it completely but I think you mentioned about like that we we are passing I'm passing only the selector of the method not all the call data I think that's so first because I'm I'm building on top of the access manager of open sealing so I'm replicating the behavior they already have in their in their code so this is kind of just a an elaboration on top of that like instead of

replicating with the modifiers. >> I agree that in some cases you may need to do something more granular like instead of just filtering on the selector something that we are doing in in some cases we are creating fake selectors. So for example, I don't know I have I have a a given method and then I can set up the rule to access that method but then inside the method I can call and I can ask the access manager about a a given fake selector that is still four bytes and is generated with some part of the parameters and then I can create more more granular rules. So the idea is to in that case use the same access manager to to hold all the configuration

but give us like enough flexibility. Well any other question? >> All right. Thank you very much GMO. >> Thanks.