-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: code-based instance configuration support (#492)
**Motivation:** Code-based instance configurations serve as an alternative to our standard JSON-based instance configuration. JSON-based configs will work in most use cases but they are limited when a more advanced setup is required. Code-based configs use the power of llama scripts to enable features such as creating strategies or accounts with multiple logic contracts and creating permissions based on dynamic conditions (e.g. deploying a guard and then using the deployed address as the target address). User flow: - Deployer calls `just deploy-instance` using something like `advancedInstanceConfig.json` as the config file (required to have instant execution strategy as the first strategy and role 1 assigned to deployer) - Deployer creates a contract similar to `src/llama-scripts/LlamaInstanceConfigScriptTemplate.sol` and inherits from `LlamaInstanceConfigBase`. Contract is deployed and address is used in next step. - Deployer adds correct parameters to `run-configure-advanced-instance-script` in the `justfile` and calls `just configure-advanced-instance` **Modifications:** - Added a `ConfigureAdvancedLlamaInstance.s.sol` script that can be run for an instance deployed using an advanced configuration (instant execution strategy on setRolePermission with a single policyholder). - This script authorizes and executes `LlamaInstanceConfigScript.sol` which can be edited to describe the instance configuration using code. It also includes the post configuration cleanup that removes any trace of the config bot. - Added tests - Added a justfile command and documentation **Result:** Instances can be deployed using a standard JSON-based configuration or an advanced code-based configuration.
- Loading branch information
1 parent
d2be19f
commit 17a6779
Showing
11 changed files
with
552 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.19; | ||
|
||
import {Script, stdJson} from "forge-std/Script.sol"; | ||
|
||
import {Clones} from "@openzeppelin/proxy/Clones.sol"; | ||
|
||
import {ILlamaStrategy} from "src/interfaces/ILlamaStrategy.sol"; | ||
import {LlamaCore} from "src/LlamaCore.sol"; | ||
import {LlamaPolicy} from "src/LlamaPolicy.sol"; | ||
import {LlamaInstanceConfigScriptTemplate} from "src/llama-scripts/LlamaInstanceConfigScriptTemplate.sol"; | ||
import {DeployUtils} from "script/DeployUtils.sol"; | ||
import {Action, ActionInfo, PermissionData} from "src/lib/Structs.sol"; | ||
import {RoleDescription} from "src/lib/UDVTs.sol"; | ||
|
||
contract ConfigureAdvancedLlamaInstance is Script { | ||
using stdJson for string; | ||
|
||
uint8 constant CONFIG_ROLE = 1; | ||
|
||
// The bootstrap strategy must be set as an instant execution strategy for this script to run | ||
ILlamaStrategy bootstrapStrategy; | ||
|
||
function _authorizeScript(address deployer, LlamaCore core, address configurationScript) internal { | ||
// Grant the CONFIG_ROLE permission to authorize scripts with the instant execution strategy | ||
LlamaPolicy policy = core.policy(); | ||
PermissionData memory scriptAuthorizePermission = | ||
PermissionData(address(core), LlamaCore.setScriptAuthorization.selector, bootstrapStrategy); | ||
bytes memory authPermissionData = | ||
abi.encodeCall(LlamaPolicy.setRolePermission, (CONFIG_ROLE, scriptAuthorizePermission, true)); | ||
|
||
vm.broadcast(deployer); | ||
uint256 authPermissionActionId = core.createAction( | ||
CONFIG_ROLE, | ||
bootstrapStrategy, | ||
address(policy), | ||
0, | ||
authPermissionData, | ||
"# Grant permission to authorize configuration script\n\nGrant the configuration bot permission to authorize scripts." | ||
); | ||
ActionInfo memory authPermissionActionInfo = ActionInfo( | ||
authPermissionActionId, deployer, CONFIG_ROLE, bootstrapStrategy, address(policy), 0, authPermissionData | ||
); | ||
|
||
vm.broadcast(deployer); | ||
core.queueAction(authPermissionActionInfo); | ||
|
||
vm.broadcast(deployer); | ||
core.executeAction(authPermissionActionInfo); | ||
|
||
// Create an action to authorize the instance configuration script | ||
bytes memory authorizeData = abi.encodeCall(LlamaCore.setScriptAuthorization, (configurationScript, true)); | ||
|
||
vm.broadcast(deployer); | ||
uint256 authorizeActionId = core.createAction( | ||
CONFIG_ROLE, | ||
bootstrapStrategy, | ||
address(core), | ||
0, | ||
authorizeData, | ||
"# Authorize configuration script\n\nAuthorize the instance configuration script." | ||
); | ||
ActionInfo memory authorizeActionInfo = | ||
ActionInfo(authorizeActionId, deployer, CONFIG_ROLE, bootstrapStrategy, address(core), 0, authorizeData); | ||
|
||
vm.broadcast(deployer); | ||
core.queueAction(authorizeActionInfo); | ||
|
||
vm.broadcast(deployer); | ||
core.executeAction(authorizeActionInfo); | ||
} | ||
|
||
function _executeScript( | ||
address deployer, | ||
LlamaCore core, | ||
address configurationScript, | ||
string memory updatedRoleDescription | ||
) internal { | ||
//Grant the CONFIG_ROLE permission to execute the deployed script with the instant execution strategy | ||
LlamaPolicy policy = core.policy(); | ||
|
||
// This assumes that the selector matches the execute function's selector in LlamaInstanceConfigScriptTemplate | ||
PermissionData memory scriptExecutePermission = | ||
PermissionData(configurationScript, LlamaInstanceConfigScriptTemplate.execute.selector, bootstrapStrategy); | ||
bytes memory executePermissionData = | ||
abi.encodeCall(LlamaPolicy.setRolePermission, (CONFIG_ROLE, scriptExecutePermission, true)); | ||
|
||
vm.broadcast(deployer); | ||
uint256 executePermissionActionId = core.createAction( | ||
CONFIG_ROLE, | ||
bootstrapStrategy, | ||
address(policy), | ||
0, | ||
executePermissionData, | ||
"# Grant permission to execute configuration script\n\nGive the config bot permission to call the execute function on the instance configuration script." | ||
); | ||
ActionInfo memory executePermissionActionInfo = ActionInfo( | ||
executePermissionActionId, deployer, CONFIG_ROLE, bootstrapStrategy, address(policy), 0, executePermissionData | ||
); | ||
|
||
vm.broadcast(deployer); | ||
core.queueAction(executePermissionActionInfo); | ||
|
||
vm.broadcast(deployer); | ||
core.executeAction(executePermissionActionInfo); | ||
|
||
// Create an action to call execute on the instance configuration script | ||
RoleDescription updatedDescription = RoleDescription.wrap(bytes32(bytes(updatedRoleDescription))); | ||
bytes memory executeData = | ||
abi.encodeCall(LlamaInstanceConfigScriptTemplate.execute, (deployer, bootstrapStrategy, updatedDescription)); | ||
|
||
vm.broadcast(deployer); | ||
uint256 executeActionId = core.createAction( | ||
CONFIG_ROLE, | ||
bootstrapStrategy, | ||
configurationScript, | ||
0, | ||
executeData, | ||
"# Execute configuration script\n\nExecute the instance configuration script." | ||
); | ||
|
||
ActionInfo memory executeActionInfo = | ||
ActionInfo(executeActionId, deployer, CONFIG_ROLE, bootstrapStrategy, configurationScript, 0, executeData); | ||
|
||
vm.broadcast(deployer); | ||
core.queueAction(executeActionInfo); | ||
|
||
vm.broadcast(deployer); | ||
core.executeAction(executeActionInfo); | ||
} | ||
|
||
function run( | ||
address deployer, | ||
string memory configFile, | ||
LlamaCore core, | ||
address configurationScript, | ||
string memory updatedRoleDescription | ||
) public { | ||
// Get bootstrap strategy | ||
string memory jsonInput = DeployUtils.readScriptInput(configFile); | ||
address strategyLogic = address(jsonInput.readAddress(".strategyLogic")); | ||
bytes[] memory encodedStrategies = DeployUtils.readStrategies(jsonInput); | ||
bootstrapStrategy = | ||
ILlamaStrategy(Clones.predictDeterministicAddress(strategyLogic, keccak256(encodedStrategies[0]), address(core))); | ||
|
||
// Grant the config bot permission to authorize scripts and authorize the instance configuration script | ||
_authorizeScript(deployer, core, configurationScript); | ||
|
||
// Grant the config bot permission to execute the instance configuration script and execute the instance | ||
// configuration script | ||
_executeScript(deployer, core, configurationScript, updatedRoleDescription); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"comment": "This is the default configuration for code-based deployments. The strategy logic is the `LlamaRelativeQuantityQuorum` contract.", | ||
"factory": "0xFf5d4E226D9A3496EECE31083a8F493edd79AbEB", | ||
"instanceName": "Code Based Config Example", | ||
"instanceColor": "#6A45EC", | ||
"instanceLogo": "<g><path fill='#fff' d='M94.528 446.858h-6.905v2.912h2.658v15.141h-3.424v2.911h10.199v-2.911h-2.528v-18.053ZM107.476 446.858h-6.904v2.912h2.657v15.141h-3.423v2.911h10.199v-2.911h-2.529v-18.053ZM117.016 457.442c.144-1.5 1.17-2.3 3.019-2.3 1.849 0 2.774.8 2.774 2.533v.422l-5.085.626c-3.019.379-5.388 1.703-5.388 4.688 0 2.97 2.239 4.673 5.633 4.673 2.846 0 4.103-1.092 4.695-2.024h.289v1.762h3.958v-9.55c0-4.164-2.658-6.042-6.789-6.042-4.161 0-6.703 1.878-7.006 4.775v.437h3.9Zm-.506 5.78c0-1.151.867-1.704 2.124-1.879l4.175-.553v.656c0 2.46-1.618 3.697-3.843 3.697-1.56 0-2.456-.757-2.456-1.921ZM130.126 467.822h3.9v-9.812c0-1.878.982-2.694 2.355-2.694 1.228 0 1.834.714 1.834 1.922v10.584h3.901v-9.812c0-1.878.982-2.694 2.34-2.694 1.242 0 1.835.714 1.835 1.922v10.584h3.914v-11.123c0-2.766-1.733-4.411-4.377-4.411-2.369 0-3.467 1.034-4.102 2.169h-.289c-.434-.99-1.503-2.169-3.698-2.169-2.153 0-3.091.903-3.612 1.82h-.289v-1.529h-3.712v15.243ZM157.105 457.442c.145-1.5 1.17-2.3 3.019-2.3 1.849 0 2.774.8 2.774 2.533v.422l-5.085.626c-3.02.379-5.388 1.703-5.388 4.688 0 2.97 2.239 4.673 5.633 4.673 2.846 0 4.103-1.092 4.695-2.024h.289v1.762H167v-9.55c0-4.164-2.658-6.042-6.789-6.042-4.161 0-6.703 1.878-7.006 4.775v.437h3.9Zm-.506 5.78c0-1.151.867-1.704 2.124-1.879l4.175-.553v.656c0 2.46-1.618 3.697-3.843 3.697-1.56 0-2.456-.757-2.456-1.921Z'/><g fill='#6A45EC'><path d='M36.956 458.249a1.37 1.37 0 0 1 .39-.942c.245-.251.577-.397.927-.406H55.8a6.262 6.262 0 0 0 4.458-1.855 6.352 6.352 0 0 0 1.369-2.06 6.406 6.406 0 0 0 .482-2.433V428h-4.96v22.553a1.371 1.371 0 0 1-.389.942 1.351 1.351 0 0 1-.927.407H38.29a6.263 6.263 0 0 0-4.445 1.861A6.383 6.383 0 0 0 32 458.249v15.568h4.956v-15.568ZM64.304 432.298h-.22l.21.213v4.65h4.561l2.14 2.179a6.286 6.286 0 0 0-3.617 2.205 6.394 6.394 0 0 0-1.422 4.016v28.262h4.936v-28.269c.005-.356.148-.696.397-.948.25-.252.587-.395.94-.4h.76c2.912 0 3.9-1.638 4.192-2.325.293-.688.744-2.565-1.316-4.651l-4.831-4.915H69.53M51.193 471.362c1.083 0 2.154.216 3.153.638a8.153 8.153 0 0 1 2.665 1.817h6a13.224 13.224 0 0 0-4.85-5.438 13.059 13.059 0 0 0-6.968-2.017c-2.464 0-4.879.699-6.968 2.017a13.225 13.225 0 0 0-4.85 5.438h6A8.154 8.154 0 0 1 48.038 472a8.101 8.101 0 0 1 3.154-.638Z'/></g></g>", | ||
"strategyLogic": "0x81F7D26fD7d814bFcEF78239a32c0BA5282C98Dc", | ||
"strategyType": 1, | ||
"accountLogic": "0x915Af6753f03D2687Fa923b2987625e21e2991aE", | ||
"initialStrategies": [ | ||
{ | ||
"approvalPeriod": 0, | ||
"approvalRole": 1, | ||
"comment": "Instant execution", | ||
"disapprovalRole": 0, | ||
"expirationPeriod": 432000, | ||
"forceApprovalRoles": [], | ||
"forceDisapprovalRoles": [], | ||
"isFixedLengthApprovalPeriod": false, | ||
"minApprovalPct": 0, | ||
"minDisapprovalPct": 10001, | ||
"queuingPeriod": 0 | ||
} | ||
], | ||
"initialAccounts": [], | ||
"initialRoleDescriptions": ["Configuration Bot"], | ||
"initialRoleHolders": [ | ||
{ | ||
"comment": "This assigns the Configuration Bot role to the configuration bot.", | ||
"expiration": 18446744073709551615, | ||
"policyholder": "0x144316A2AAdB8E36cCD32F07cB22484E96e58AD7", | ||
"quantity": 1, | ||
"role": 1 | ||
} | ||
], | ||
"initialRolePermissions": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"comment": "This is the default configuration for code-based deployments. The strategy logic is the `LlamaRelativeQuantityQuorum` contract.", | ||
"factory": "0xDEb1E9a6Be7Baf84208BB6E10aC9F9bbE1D70809", | ||
"instanceName": "Llama", | ||
"instanceColor": "#6A45EC", | ||
"instanceLogo": "<g><path fill='#fff' d='M94.528 446.858h-6.905v2.912h2.658v15.141h-3.424v2.911h10.199v-2.911h-2.528v-18.053ZM107.476 446.858h-6.904v2.912h2.657v15.141h-3.423v2.911h10.199v-2.911h-2.529v-18.053ZM117.016 457.442c.144-1.5 1.17-2.3 3.019-2.3 1.849 0 2.774.8 2.774 2.533v.422l-5.085.626c-3.019.379-5.388 1.703-5.388 4.688 0 2.97 2.239 4.673 5.633 4.673 2.846 0 4.103-1.092 4.695-2.024h.289v1.762h3.958v-9.55c0-4.164-2.658-6.042-6.789-6.042-4.161 0-6.703 1.878-7.006 4.775v.437h3.9Zm-.506 5.78c0-1.151.867-1.704 2.124-1.879l4.175-.553v.656c0 2.46-1.618 3.697-3.843 3.697-1.56 0-2.456-.757-2.456-1.921ZM130.126 467.822h3.9v-9.812c0-1.878.982-2.694 2.355-2.694 1.228 0 1.834.714 1.834 1.922v10.584h3.901v-9.812c0-1.878.982-2.694 2.34-2.694 1.242 0 1.835.714 1.835 1.922v10.584h3.914v-11.123c0-2.766-1.733-4.411-4.377-4.411-2.369 0-3.467 1.034-4.102 2.169h-.289c-.434-.99-1.503-2.169-3.698-2.169-2.153 0-3.091.903-3.612 1.82h-.289v-1.529h-3.712v15.243ZM157.105 457.442c.145-1.5 1.17-2.3 3.019-2.3 1.849 0 2.774.8 2.774 2.533v.422l-5.085.626c-3.02.379-5.388 1.703-5.388 4.688 0 2.97 2.239 4.673 5.633 4.673 2.846 0 4.103-1.092 4.695-2.024h.289v1.762H167v-9.55c0-4.164-2.658-6.042-6.789-6.042-4.161 0-6.703 1.878-7.006 4.775v.437h3.9Zm-.506 5.78c0-1.151.867-1.704 2.124-1.879l4.175-.553v.656c0 2.46-1.618 3.697-3.843 3.697-1.56 0-2.456-.757-2.456-1.921Z'/><g fill='#6A45EC'><path d='M36.956 458.249a1.37 1.37 0 0 1 .39-.942c.245-.251.577-.397.927-.406H55.8a6.262 6.262 0 0 0 4.458-1.855 6.352 6.352 0 0 0 1.369-2.06 6.406 6.406 0 0 0 .482-2.433V428h-4.96v22.553a1.371 1.371 0 0 1-.389.942 1.351 1.351 0 0 1-.927.407H38.29a6.263 6.263 0 0 0-4.445 1.861A6.383 6.383 0 0 0 32 458.249v15.568h4.956v-15.568ZM64.304 432.298h-.22l.21.213v4.65h4.561l2.14 2.179a6.286 6.286 0 0 0-3.617 2.205 6.394 6.394 0 0 0-1.422 4.016v28.262h4.936v-28.269c.005-.356.148-.696.397-.948.25-.252.587-.395.94-.4h.76c2.912 0 3.9-1.638 4.192-2.325.293-.688.744-2.565-1.316-4.651l-4.831-4.915H69.53M51.193 471.362c1.083 0 2.154.216 3.153.638a8.153 8.153 0 0 1 2.665 1.817h6a13.224 13.224 0 0 0-4.85-5.438 13.059 13.059 0 0 0-6.968-2.017c-2.464 0-4.879.699-6.968 2.017a13.225 13.225 0 0 0-4.85 5.438h6A8.154 8.154 0 0 1 48.038 472a8.101 8.101 0 0 1 3.154-.638Z'/></g></g>", | ||
"strategyLogic": "0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496", | ||
"strategyType": 1, | ||
"accountLogic": "0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76", | ||
"initialStrategies": [ | ||
{ | ||
"approvalPeriod": 0, | ||
"approvalRole": 1, | ||
"comment": "Instant execution", | ||
"disapprovalRole": 0, | ||
"expirationPeriod": 432000, | ||
"forceApprovalRoles": [], | ||
"forceDisapprovalRoles": [], | ||
"isFixedLengthApprovalPeriod": false, | ||
"minApprovalPct": 0, | ||
"minDisapprovalPct": 10001, | ||
"queuingPeriod": 0 | ||
} | ||
], | ||
"initialAccounts": [], | ||
"initialRoleDescriptions": ["Configuration Bot"], | ||
"initialRoleHolders": [ | ||
{ | ||
"comment": "This assigns the Configuration Bot role to the instance deployer.", | ||
"expiration": 18446744073709551615, | ||
"policyholder": "0x3d9fEa8AeD0249990133132Bb4BC8d07C6a8259a", | ||
"quantity": 1, | ||
"role": 1 | ||
} | ||
], | ||
"initialRolePermissions": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.19; | ||
|
||
import {LlamaBaseScript} from "src/llama-scripts/LlamaBaseScript.sol"; | ||
import {ILlamaStrategy} from "src/interfaces/ILlamaStrategy.sol"; | ||
import {LlamaCore} from "src/LlamaCore.sol"; | ||
import {LlamaPolicy} from "src/LlamaPolicy.sol"; | ||
import {PermissionData} from "src/lib/Structs.sol"; | ||
import {RoleDescription} from "src/lib/UDVTs.sol"; | ||
|
||
abstract contract LlamaInstanceConfigBase is LlamaBaseScript { | ||
uint8 constant CONFIG_ROLE = 1; | ||
|
||
function _postConfigurationCleanup( | ||
address configPolicyHolder, | ||
LlamaCore core, | ||
ILlamaStrategy bootstrapStrategy, | ||
RoleDescription description, | ||
PermissionData memory executePermission | ||
) internal { | ||
LlamaPolicy policy = core.policy(); | ||
PermissionData memory authorizePermission = | ||
PermissionData(address(core), LlamaCore.setScriptAuthorization.selector, bootstrapStrategy); | ||
|
||
// Rename role #1 description | ||
policy.updateRoleDescription(CONFIG_ROLE, description); | ||
|
||
// Unauthorize configuration script | ||
core.setScriptAuthorization(SELF, false); | ||
|
||
// Remove configuration policyholder | ||
policy.revokePolicy(configPolicyHolder); | ||
|
||
// Unauthorize instant execution strategy | ||
core.setStrategyAuthorization(bootstrapStrategy, false); | ||
|
||
// Remove role #1 permissions to authorize and execute scripts | ||
policy.setRolePermission(CONFIG_ROLE, authorizePermission, false); | ||
policy.setRolePermission(CONFIG_ROLE, executePermission, false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.19; | ||
|
||
import {LlamaInstanceConfigBase} from "src/llama-scripts/LlamaInstanceConfigBase.sol"; | ||
import {ILlamaStrategy} from "src/interfaces/ILlamaStrategy.sol"; | ||
import {LlamaCore} from "src/LlamaCore.sol"; | ||
import {PermissionData} from "src/lib/Structs.sol"; | ||
import {RoleDescription} from "src/lib/UDVTs.sol"; | ||
|
||
contract LlamaInstanceConfigScriptTemplate is LlamaInstanceConfigBase { | ||
function execute(address configPolicyHolder, ILlamaStrategy bootstrapStrategy, RoleDescription description) | ||
external | ||
onlyDelegateCall | ||
{ | ||
LlamaCore core = LlamaCore(msg.sender); | ||
|
||
// The selector needs to be this contract's execute function | ||
PermissionData memory executePermission = | ||
PermissionData(SELF, LlamaInstanceConfigScriptTemplate.execute.selector, bootstrapStrategy); | ||
|
||
// Insert configuration code here | ||
|
||
_postConfigurationCleanup(configPolicyHolder, core, bootstrapStrategy, description, executePermission); | ||
} | ||
} |
Oops, something went wrong.