From c91af3275aab64865fb00e51a45ddf6dd30ecb21 Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Wed, 31 Jan 2024 16:39:24 +0700 Subject: [PATCH 1/7] Some workarounds for GovV3 templating --- src/GovV3Playground.sol | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/GovV3Playground.sol diff --git a/src/GovV3Playground.sol b/src/GovV3Playground.sol new file mode 100644 index 000000000..c4661207c --- /dev/null +++ b/src/GovV3Playground.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {WithChainIdValidation, EthereumScript} from './ScriptUtils.sol'; +import {GovV3Helpers, IPayloadsControllerCore} from './GovV3Helpers.sol'; + +contract LetMeJustHaveSome { + string public name = 'some'; +} + +abstract contract WithChainIdValidationAndPayloads is WithChainIdValidation { + function getPayloads() public virtual returns (bytes[] memory); +} + +abstract contract WithChainIdValidationAndPayloadSimple is WithChainIdValidationAndPayloads { + function getPayload() public virtual returns (bytes memory); + + function getPayloads() public override returns (bytes[] memory) { + bytes[] memory payloadsCode = new bytes[](1); + payloadsCode[0] = getPayload(); + return payloadsCode; + } +} + +abstract contract DeployPayloads is WithChainIdValidationAndPayloads { + function run() external broadcast { + bytes[] memory payloadsCode = getPayloads(); + + // deploy payloads + address[] memory payloadsAddresses = new address[](payloadsCode.length); + for (uint256 i = 0; i < payloadsCode.length; i++) { + payloadsAddresses[i] = GovV3Helpers.deployDeterministic(payloadsCode[i]); + } + + // compose action + IPayloadsControllerCore.ExecutionAction[] + memory actions = new IPayloadsControllerCore.ExecutionAction[](payloadsCode.length); + for (uint256 i = 0; i < payloadsCode.length; i++) { + actions[i] = GovV3Helpers.buildAction(payloadsAddresses[i]); + } + + // register action at payloadsController + GovV3Helpers.createPayload(actions); + } +} + +contract DeploySomeSimple is WithChainIdValidationAndPayloadSimple, EthereumScript { + function getPayload() public override returns (bytes memory) { + return type(LetMeJustHaveSome).creationCode; + } +} From 04accb1cff25a9d6cccde02310ba20ef54502b8e Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Wed, 31 Jan 2024 16:49:22 +0700 Subject: [PATCH 2/7] small improvement of WithChainIdValidationAndPayloadSimple --- src/GovV3Playground.sol | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/GovV3Playground.sol b/src/GovV3Playground.sol index c4661207c..89448337e 100644 --- a/src/GovV3Playground.sol +++ b/src/GovV3Playground.sol @@ -9,15 +9,19 @@ contract LetMeJustHaveSome { } abstract contract WithChainIdValidationAndPayloads is WithChainIdValidation { - function getPayloads() public virtual returns (bytes[] memory); + function getPayloads() public view virtual returns (bytes[] memory); } abstract contract WithChainIdValidationAndPayloadSimple is WithChainIdValidationAndPayloads { - function getPayload() public virtual returns (bytes memory); + bytes public payloadCode; - function getPayloads() public override returns (bytes[] memory) { + constructor(bytes memory code) { + payloadCode = code; + } + + function getPayloads() public view override returns (bytes[] memory) { bytes[] memory payloadsCode = new bytes[](1); - payloadsCode[0] = getPayload(); + payloadsCode[0] = payloadCode; return payloadsCode; } } @@ -44,8 +48,7 @@ abstract contract DeployPayloads is WithChainIdValidationAndPayloads { } } -contract DeploySomeSimple is WithChainIdValidationAndPayloadSimple, EthereumScript { - function getPayload() public override returns (bytes memory) { - return type(LetMeJustHaveSome).creationCode; - } -} +contract DeploySomeSimple is + WithChainIdValidationAndPayloadSimple(type(LetMeJustHaveSome).creationCode), + EthereumScript +{} From f459f6fe67a3b2c3f7132398e408549c9513d465 Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Wed, 31 Jan 2024 16:53:12 +0700 Subject: [PATCH 3/7] more examples --- src/GovV3Playground.sol | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/GovV3Playground.sol b/src/GovV3Playground.sol index 89448337e..898a59212 100644 --- a/src/GovV3Playground.sol +++ b/src/GovV3Playground.sol @@ -12,20 +12,6 @@ abstract contract WithChainIdValidationAndPayloads is WithChainIdValidation { function getPayloads() public view virtual returns (bytes[] memory); } -abstract contract WithChainIdValidationAndPayloadSimple is WithChainIdValidationAndPayloads { - bytes public payloadCode; - - constructor(bytes memory code) { - payloadCode = code; - } - - function getPayloads() public view override returns (bytes[] memory) { - bytes[] memory payloadsCode = new bytes[](1); - payloadsCode[0] = payloadCode; - return payloadsCode; - } -} - abstract contract DeployPayloads is WithChainIdValidationAndPayloads { function run() external broadcast { bytes[] memory payloadsCode = getPayloads(); @@ -48,7 +34,30 @@ abstract contract DeployPayloads is WithChainIdValidationAndPayloads { } } +abstract contract DeployPayloadSimple is DeployPayloads { + bytes public payloadCode; + + constructor(bytes memory code) { + payloadCode = code; + } + + function getPayloads() public view override returns (bytes[] memory) { + bytes[] memory payloadsCode = new bytes[](1); + payloadsCode[0] = payloadCode; + return payloadsCode; + } +} + contract DeploySomeSimple is - WithChainIdValidationAndPayloadSimple(type(LetMeJustHaveSome).creationCode), + DeployPayloadSimple(type(LetMeJustHaveSome).creationCode), EthereumScript {} + +contract DeploySomeMany is DeployPayloads, EthereumScript { + function getPayloads() public view override returns (bytes[] memory) { + bytes[] memory payloadsCode = new bytes[](2); + payloadsCode[0] = type(LetMeJustHaveSome).creationCode; + payloadsCode[1] = type(LetMeJustHaveSome).creationCode; + return payloadsCode; + } +} From 1b6225eab7d219cdc6ae01fc8ce1a15681ff99d9 Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Wed, 31 Jan 2024 19:07:27 +0700 Subject: [PATCH 4/7] my take on advanced flow --- src/GovV3PlaygroundAdvanced.sol | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/GovV3PlaygroundAdvanced.sol diff --git a/src/GovV3PlaygroundAdvanced.sol b/src/GovV3PlaygroundAdvanced.sol new file mode 100644 index 000000000..ca2ff4688 --- /dev/null +++ b/src/GovV3PlaygroundAdvanced.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from 'forge-std/Script.sol'; +import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from './GovV3Helpers.sol'; + +contract LetMeJustHaveSome { + string public name = 'some'; +} + +contract LetMeJustHaveAnother { + string public name = 'another'; +} + +abstract contract WithPayloads { + struct ActionsPerChain { + string chainName; + bytes[] actionCode; + } + + function getActions() public view virtual returns (ActionsPerChain[] memory); +} + +abstract contract WithPayloadsSimple is WithPayloads { + function getActionsOneChain() public view virtual returns (ActionsPerChain memory); + + function getActions() public view override returns (ActionsPerChain[] memory) { + ActionsPerChain[] memory actions = new ActionsPerChain[](1); + actions[0] = getActionsOneChain(); + return actions; + } +} + +abstract contract DeployPayloads is WithPayloads, Script { + function run() external { + ActionsPerChain[] memory actionsPerChain = getActions(); + + for (uint256 i = 0; i < actionsPerChain.length; i++) { + ActionsPerChain memory rawActions = actionsPerChain[i]; + require(rawActions.actionCode.length != 0, 'should be at least one payload action per chain'); + + vm.rpcUrl(rawActions.chainName); + vm.startBroadcast(); + + // compose actions + IPayloadsControllerCore.ExecutionAction[] + memory composedActions = new IPayloadsControllerCore.ExecutionAction[]( + rawActions.actionCode.length + ); + // deploy payloads + for (uint256 j = 0; j < rawActions.actionCode.length; j++) { + composedActions[j] = GovV3Helpers.buildAction( + GovV3Helpers.deployDeterministic(rawActions.actionCode[j]) + ); + } + + // register actions at payloadsController + GovV3Helpers.createPayload(composedActions); + vm.stopBroadcast(); + } + } +} + +abstract contract CreateProposal is WithPayloads, Script { + string internal _ipfsFilePath; + + constructor(string memory ipfsFilePath) { + _ipfsFilePath = ipfsFilePath; + } + + function run() external { + ActionsPerChain[] memory actionsPerChain = getActions(); + + // create payloads + PayloadsControllerUtils.Payload[] memory payloadsPinned = new PayloadsControllerUtils.Payload[]( + actionsPerChain.length + ); + + for (uint256 i = 0; i < actionsPerChain.length; i++) { + ActionsPerChain memory rawActions = actionsPerChain[i]; + vm.rpcUrl(rawActions.chainName); + + IPayloadsControllerCore.ExecutionAction[] + memory actions = new IPayloadsControllerCore.ExecutionAction[]( + rawActions.actionCode.length + ); + + for (uint256 j = 0; j < rawActions.actionCode.length; j++) { + actions[j] = GovV3Helpers.buildAction(rawActions.actionCode[j]); + } + payloadsPinned[i] = GovV3Helpers._buildPayload(vm, block.chainid, actions); + } + + // create proposal + vm.rpcUrl('ethereum'); + vm.startBroadcast(); + GovV3Helpers.createProposal(vm, payloadsPinned, GovV3Helpers.ipfsHashFile(vm, _ipfsFilePath)); + vm.stopBroadcast(); + } +} + +abstract contract MySimplePayloads is WithPayloadsSimple { + function getActionsOneChain() public pure override returns (ActionsPerChain memory) { + ActionsPerChain memory payload; + + payload.chainName = 'ethereum'; + payload.actionCode = new bytes[](2); + payload.actionCode[0] = type(LetMeJustHaveSome).creationCode; + payload.actionCode[1] = type(LetMeJustHaveAnother).creationCode; + + return payload; + } +} + +contract DeploymentSimple is MySimplePayloads, DeployPayloads {} + +contract ProposalCreationSimple is + MySimplePayloads, + CreateProposal( + 'src/20240121_Multi_UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum/UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum.md' + ) +{} From c7d686ce1b28fb3023b603bf6e2561f4fe08c995 Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Wed, 31 Jan 2024 19:21:06 +0700 Subject: [PATCH 5/7] my take on advanced flow -2 --- src/GovV3PlaygroundAdvanced.sol | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/GovV3PlaygroundAdvanced.sol b/src/GovV3PlaygroundAdvanced.sol index ca2ff4688..be9318bfa 100644 --- a/src/GovV3PlaygroundAdvanced.sol +++ b/src/GovV3PlaygroundAdvanced.sol @@ -120,3 +120,28 @@ contract ProposalCreationSimple is 'src/20240121_Multi_UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum/UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum.md' ) {} + +abstract contract MyComplexPayloads is WithPayloads { + function getActions() public view override returns (ActionsPerChain[] memory) { + ActionsPerChain[] memory payloads = new ActionsPerChain[](2); + + payloads[0].chainName = 'ethereum'; + payloads[0].actionCode = new bytes[](1); + payloads[0].actionCode[0] = type(LetMeJustHaveSome).creationCode; + + payloads[1].chainName = 'polygon'; + payloads[1].actionCode = new bytes[](1); + payloads[1].actionCode[0] = type(LetMeJustHaveAnother).creationCode; + + return payloads; + } +} + +contract DeploymentComplex is MyComplexPayloads, DeployPayloads {} + +contract ProposalCreationComplex is + MyComplexPayloads, + CreateProposal( + 'src/20240121_Multi_UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum/UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum.md' + ) +{} From 5c9fcfc901c6ac28112548749059b59520f2ca91 Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Thu, 1 Feb 2024 14:06:20 +0700 Subject: [PATCH 6/7] more thinking about single chain deployments --- src/GovV3PlaygroundAdvanced.sol | 102 +++++++++--------------- src/GovV3PlaygroundAdvancedExamples.sol | 51 ++++++++++++ 2 files changed, 88 insertions(+), 65 deletions(-) create mode 100644 src/GovV3PlaygroundAdvancedExamples.sol diff --git a/src/GovV3PlaygroundAdvanced.sol b/src/GovV3PlaygroundAdvanced.sol index be9318bfa..76e74bd35 100644 --- a/src/GovV3PlaygroundAdvanced.sol +++ b/src/GovV3PlaygroundAdvanced.sol @@ -4,14 +4,6 @@ pragma solidity ^0.8.0; import {Script} from 'forge-std/Script.sol'; import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from './GovV3Helpers.sol'; -contract LetMeJustHaveSome { - string public name = 'some'; -} - -contract LetMeJustHaveAnother { - string public name = 'another'; -} - abstract contract WithPayloads { struct ActionsPerChain { string chainName; @@ -21,22 +13,17 @@ abstract contract WithPayloads { function getActions() public view virtual returns (ActionsPerChain[] memory); } -abstract contract WithPayloadsSimple is WithPayloads { - function getActionsOneChain() public view virtual returns (ActionsPerChain memory); - - function getActions() public view override returns (ActionsPerChain[] memory) { - ActionsPerChain[] memory actions = new ActionsPerChain[](1); - actions[0] = getActionsOneChain(); - return actions; - } -} - abstract contract DeployPayloads is WithPayloads, Script { + function isChainSupported(string memory chain) public view virtual returns (bool); + function run() external { ActionsPerChain[] memory actionsPerChain = getActions(); for (uint256 i = 0; i < actionsPerChain.length; i++) { ActionsPerChain memory rawActions = actionsPerChain[i]; + + // if actions belongs to the network we should not deploy, skip + if (!isChainSupported(rawActions.chainName)) continue; require(rawActions.actionCode.length != 0, 'should be at least one payload action per chain'); vm.rpcUrl(rawActions.chainName); @@ -61,9 +48,41 @@ abstract contract DeployPayloads is WithPayloads, Script { } } +// not so applicable atm, because requires solid multiChan support, but for the good future +abstract contract DeployPayloadsMultiChain is DeployPayloads { + mapping(bytes32 => bool) internal _supportedChain; + + constructor(string[] memory supportedChains) { + for (uint256 i = 0; i < supportedChains.length; i++) { + _supportedChain[keccak256(bytes(supportedChains[i]))] = true; + } + } + + function isChainSupported(string memory chain) public view override returns (bool) { + return _supportedChain[keccak256(bytes(chain))]; + } +} + +abstract contract DeployPayloadsSingleChain is DeployPayloads { + string public supportedChain; + + constructor(string memory chainName) { + supportedChain = chainName; + } + + function isChainSupported(string memory chain) public view override returns (bool) { + return keccak256(bytes(chain)) == keccak256(bytes(supportedChain)); + } +} + +abstract contract DeployPayloadsEthereum is DeployPayloadsSingleChain('ethereum') {} + +abstract contract DeployPayloadsPolygon is DeployPayloadsSingleChain('polygon') {} + abstract contract CreateProposal is WithPayloads, Script { string internal _ipfsFilePath; + // TODO: I would make it more human readable with params: date, name, isMulti(?) and generation of the actual string constructor(string memory ipfsFilePath) { _ipfsFilePath = ipfsFilePath; } @@ -98,50 +117,3 @@ abstract contract CreateProposal is WithPayloads, Script { vm.stopBroadcast(); } } - -abstract contract MySimplePayloads is WithPayloadsSimple { - function getActionsOneChain() public pure override returns (ActionsPerChain memory) { - ActionsPerChain memory payload; - - payload.chainName = 'ethereum'; - payload.actionCode = new bytes[](2); - payload.actionCode[0] = type(LetMeJustHaveSome).creationCode; - payload.actionCode[1] = type(LetMeJustHaveAnother).creationCode; - - return payload; - } -} - -contract DeploymentSimple is MySimplePayloads, DeployPayloads {} - -contract ProposalCreationSimple is - MySimplePayloads, - CreateProposal( - 'src/20240121_Multi_UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum/UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum.md' - ) -{} - -abstract contract MyComplexPayloads is WithPayloads { - function getActions() public view override returns (ActionsPerChain[] memory) { - ActionsPerChain[] memory payloads = new ActionsPerChain[](2); - - payloads[0].chainName = 'ethereum'; - payloads[0].actionCode = new bytes[](1); - payloads[0].actionCode[0] = type(LetMeJustHaveSome).creationCode; - - payloads[1].chainName = 'polygon'; - payloads[1].actionCode = new bytes[](1); - payloads[1].actionCode[0] = type(LetMeJustHaveAnother).creationCode; - - return payloads; - } -} - -contract DeploymentComplex is MyComplexPayloads, DeployPayloads {} - -contract ProposalCreationComplex is - MyComplexPayloads, - CreateProposal( - 'src/20240121_Multi_UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum/UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum.md' - ) -{} diff --git a/src/GovV3PlaygroundAdvancedExamples.sol b/src/GovV3PlaygroundAdvancedExamples.sol new file mode 100644 index 000000000..5b11bc799 --- /dev/null +++ b/src/GovV3PlaygroundAdvancedExamples.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import './GovV3PlaygroundAdvanced.sol'; + +contract LetMeJustHaveSome { + string public name = 'some'; +} + +contract LetMeJustHaveAnother { + string public name = 'another'; +} + +abstract contract MyPayloads is WithPayloads { + function getActions() public pure override returns (ActionsPerChain[] memory) { + ActionsPerChain[] memory payloads = new ActionsPerChain[](2); + + payloads[0].chainName = 'ethereum'; + payloads[0].actionCode = new bytes[](1); + payloads[0].actionCode[0] = type(LetMeJustHaveSome).creationCode; + + payloads[1].chainName = 'polygon'; + payloads[1].actionCode = new bytes[](1); + payloads[1].actionCode[0] = type(LetMeJustHaveAnother).creationCode; + + return payloads; + } +} + +contract DeploymentComplexEthereum is MyPayloads, DeployPayloadsEthereum {} + +contract DeploymentComplexPolygon is MyPayloads, DeployPayloadsPolygon {} + +// depends on what will be better for generator +contract DeploymentComplexPoly is MyPayloads, DeployPayloadsSingleChain('polygon') { + +} + +// I think it will look way better +// contract ProposalCreationComplex is +// MyPayloads, +// CreateProposal('20240121', 'UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum') +// {} +contract ProposalCreationComplex is + MyPayloads, + CreateProposal( + 'src/20240121_Multi_UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum/UpdateStETHAndWETHRiskParamsOnAaveV3EthereumOptimismAndArbitrum.md' + ) +{ + +} From 8f4cecb09205d689095b8e20deb578910b204753 Mon Sep 17 00:00:00 2001 From: Andrei Kozlov Date: Thu, 1 Feb 2024 14:10:07 +0700 Subject: [PATCH 7/7] added todo comment --- src/GovV3PlaygroundAdvanced.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GovV3PlaygroundAdvanced.sol b/src/GovV3PlaygroundAdvanced.sol index 76e74bd35..817215f0d 100644 --- a/src/GovV3PlaygroundAdvanced.sol +++ b/src/GovV3PlaygroundAdvanced.sol @@ -27,6 +27,7 @@ abstract contract DeployPayloads is WithPayloads, Script { require(rawActions.actionCode.length != 0, 'should be at least one payload action per chain'); vm.rpcUrl(rawActions.chainName); + // TODO: after rpc switch we should be checking that chainId is the one we expect, just in case vm.startBroadcast(); // compose actions @@ -112,6 +113,7 @@ abstract contract CreateProposal is WithPayloads, Script { // create proposal vm.rpcUrl('ethereum'); + // TODO: after rpc switch we should be checking that chainId is the one we expect, just in case vm.startBroadcast(); GovV3Helpers.createProposal(vm, payloadsPinned, GovV3Helpers.ipfsHashFile(vm, _ipfsFilePath)); vm.stopBroadcast();