feat(world): add callFrom entry point#1364
Conversation
🦋 Changeset detectedLatest commit: 042893f The changes in this PR will be included in the next version bump. This PR includes changesets to release 27 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| error FunctionSelectorExists(bytes4 functionSelector); | ||
| error FunctionSelectorNotFound(bytes4 functionSelector); | ||
| error ModuleAlreadyInstalled(string module); | ||
| error NoDelegationFound(address grantor, address grantee); |
There was a problem hiding this comment.
| error NoDelegationFound(address grantor, address grantee); | |
| error DelegationNotFound(address grantor, address grantee); |
(for consistency with our other errors)
|
Did some refactors around |
31a033a to
3c13457
Compare
|
Current dependencies on/for this PR:
This comment was auto-generated by Graphite. |
3c13457 to
79125bc
Compare
79125bc to
70e8c7d
Compare
| */ | ||
| function registerDelegation( | ||
| address delegatee, | ||
| bytes32 delegationControl, |
There was a problem hiding this comment.
took me a bit to realize we switched from address to resource selector/ID, and wondering if we should clarify the naming here to delegationControlId or something?
| resourceSelector: resourceSelector, | ||
| funcSelectorAndArgsHash: funcSelectorAndArgsHash, | ||
| availableCalls: availableCalls - 1 | ||
| }); |
There was a problem hiding this comment.
should we delete once we get to zero?
There was a problem hiding this comment.
this can be unchecked, since you do availableCalls > 0 already
| import { DelegationControl } from "../../DelegationControl.sol"; | ||
| import { DisposableDelegations } from "./tables/DisposableDelegations.sol"; | ||
|
|
||
| contract DisposableDelegationControl is DelegationControl { |
There was a problem hiding this comment.
I like this better than "decaying" 👍
Another potential name idea is "callbound" (to go with "timebound")
|
|
||
| // Set the timestamp to maxTimestamp+1 and expect the delegation to be expired | ||
| vm.warp(maxTimestamp + 1); | ||
| vm.expectRevert(abi.encodeWithSelector(IWorldErrors.DelegationNotFound.selector, delegator, delegatee)); |
There was a problem hiding this comment.
tiny thing but I tend to put the expectRevert immediately before the thing we expect to revert, to not confuse this with "I expect vm.prank to revert"
| @@ -0,0 +1,55 @@ | |||
| // SPDX-License-Identifier: MIT | |||
There was a problem hiding this comment.
thoughts on just delegations instead of std-delegations for the dir name?
oh nevermind, this seems to reflect the module name and these files are tied to the module
| resourceSelector: resourceSelector, | ||
| funcSelectorAndArgsHash: funcSelectorAndArgsHash, | ||
| availableCalls: availableCalls - 1 | ||
| }); |
There was a problem hiding this comment.
this can be unchecked, since you do availableCalls > 0 already
| bytes16 constant MODULE_NAME = bytes16("stddelegations.m"); | ||
|
|
||
| // Disposable delegation | ||
| bytes32 constant DISPOSABLE_DELEGATION = bytes32(abi.encodePacked(ROOT_NAMESPACE, bytes16("disposable.d"))); | ||
|
|
||
| // Timebound delegation | ||
| bytes32 constant TIMEBOUND_DELEGATION = bytes32(abi.encodePacked(ROOT_NAMESPACE, bytes16("timebound.d"))); |
There was a problem hiding this comment.
should it perhaps have a MODULE_NAMESPACE?
There was a problem hiding this comment.
My thinking was that this module should ideally be installed as a root module (so it can install the systems as root systems), because it reduces the gas cost of all systems that read or change state (around 8k for the calls to DisposableDelegationSystem)
There was a problem hiding this comment.
I don't think I have my head wrapped around the end-to-end, but are these delegation/callfrom checks always routed through the world? Ultimately wondering if it would be useful to inherit the namespace or allow the namespace to be configured, or if that only has negative consequences (only used by world, only more gas)
There was a problem hiding this comment.
Yes, they are always routed through the World. The main challenge is that the delegation check system needs to know which table to access. We could make this dynamic and store the namespace in which the module is registered in storage and then load it from storage in the system, but that would cost more gas. A cheaper alternative would be to just use two different modules for root and non-root installations (it only needs to be installed once per world, so the namespace for non-root could also be fixed). For now, I'd just go with providing the root version, because I'd expect this standard module to be installed by default - if we find there's a need for a non-root version (to be installed on worlds that don't have the root version installed by default), we can just add another version of the module later
There was a problem hiding this comment.
root only for now as the default/expected/most common path is totally fine by me
|
|
||
| if (availableCalls > 0) { | ||
| // Decrement the number of available calls | ||
| unchecked { |
There was a problem hiding this comment.
I don't know the consequences of unchecked but is it safe for us to wrap this whole statement vs just the decrement? Would unchecked apply to the .set() or _msgSender() calls?
There was a problem hiding this comment.
moved it outside of the block, gas didn't change so seems like unchecked doesn't impact the nested calls, but fells still cleaner to have it explicit

fixes #1358
see changeset for details on this change