Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow upgrade #8

Merged
merged 3 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Alchemy Modular Smart Contract Account (MSCA)

Contracts for an upgradeable modular smart contract account that is compatible with ERC-4337 and ERC-6900, along with a set of plugins.
Contracts for an upgradeable modular smart contract account that is compatible with ERC-4337, along with a set of plugins.

## Development

Expand Down
15 changes: 10 additions & 5 deletions src/account/UpgradeableModularAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {UUPSUpgradeable} from "../../ext/UUPSUpgradeable.sol";

/// @title Upgradeable Modular Account
/// @author Alchemy
/// @notice An ERC-6900 compatible modular smart contract account (MSCA) that supports upgradeability and plugins.
/// @notice A modular smart contract account (MSCA) that supports upgradeability and plugins.
contract UpgradeableModularAccount is
AccountExecutor,
AccountLoupe,
Expand Down Expand Up @@ -616,17 +616,22 @@ contract UpgradeableModularAccount is
if (runtimeValidationFunction.isEmptyOrMagicValue()) {
if (
runtimeValidationFunction == FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE
&& (msg.sig != IPluginManager.installPlugin.selector || msg.sender != address(this))
&& (
(
msg.sig != IPluginManager.installPlugin.selector
|| msg.sig != UUPSUpgradeable.upgradeToAndCall.selector
) && msg.sender != address(this)
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's add to the comment just below this, which for now is only talking about installPlugin.

) {
// Runtime calls cannot be made against functions with no
// validator, except in the special case of self-calls to
// `installPlugin`, to enable removing the plugin protecting
// `installPlugin` and `upgradeToAndCall`, to enable removing the plugin protecting
// `installPlugin` and installing a different one as part of
// a single batch execution.
// a single batch execution, and/or to enable upgrading the account implementation.
revert RuntimeValidationFunctionMissing(msg.sig);
}
// If _RUNTIME_VALIDATION_ALWAYS_ALLOW, or we're in the
// `installPlugin` special case,just let the function finish,
// `installPlugin` and `upgradeToAndCall` special case,just let the function finish,
// without the else branch.
} else {
_updatePluginCallBufferSelector(callBuffer, IPlugin.runtimeValidationFunction.selector);
Expand Down
2 changes: 1 addition & 1 deletion src/factory/MultiOwnerMSCAFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {IEntryPoint} from "../interfaces/erc4337/IEntryPoint.sol";

/// @title Multi Owner Plugin MSCA (Modular Smart Contract Account) Factory
/// @author Alchemy
/// @notice Factory for ERC-6900 compatible upgradeable modular accounts with MultiOwnerPlugin installed.
/// @notice Factory for upgradeable modular accounts with MultiOwnerPlugin installed.
/// @dev There is a reliance on the assumption that the plugin manifest will remain static, following ERC-6900. If
/// this assumption is broken then account deployments would be bricked.
contract MultiOwnerMSCAFactory is Ownable {
Expand Down
3 changes: 1 addition & 2 deletions src/factory/MultiOwnerTokenReceiverMSCAFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {IEntryPoint} from "../interfaces/erc4337/IEntryPoint.sol";

/// @title Multi Owner Plugin + Token Receiver MSCA (Modular Smart Contract Account) Factory
/// @author Alchemy
/// @notice Factory for ERC-6900 compatible upgradeable modular accounts with MultiOwnerPlugin and TokenReceiver
/// installed.
/// @notice Factory for upgradeable modular accounts with MultiOwnerPlugin and TokenReceiver installed.
/// @dev There is a reliance on the assumption that the plugin manifest will remain static, following ERC-6900. If
/// this assumption is broken then account deployments would be bricked.
contract MultiOwnerTokenReceiverMSCAFactory is Ownable {
Expand Down
24 changes: 24 additions & 0 deletions test/upgrade/MSCAToMSCA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {MultiOwnerTokenReceiverMSCAFactory} from "../../src/factory/MultiOwnerTo
import {MultiOwnerPlugin} from "../../src/plugins/owner/MultiOwnerPlugin.sol";
import {TokenReceiverPlugin} from "../../src/plugins/TokenReceiverPlugin.sol";
import {IEntryPoint} from "../../src/interfaces/erc4337/IEntryPoint.sol";
import {Call} from "../../src/interfaces/IStandardExecutor.sol";

import {Utils} from "../Utils.sol";
import {MockERC20} from "../mocks/tokens/MockERC20.sol";
Expand Down Expand Up @@ -77,4 +78,27 @@ contract MSCAToMSCATest is Test {

vm.stopPrank();
}

function test_sameStorageSlot_reinstallUpgradeToAndCall() public {
vm.startPrank(owners[0]);

Call[] memory calls = new Call[](2);
calls[0] = Call(
address(msca),
0,
abi.encodeCall(
UpgradeableModularAccount.uninstallPlugin,
(address(multiOwnerPlugin), bytes(""), bytes(""), new bytes[](0))
)
);

calls[1] =
Call(address(msca), 0, abi.encodeCall(UpgradeableModularAccount.upgradeToAndCall, (mscaImpl2, "")));

emit Upgraded(mscaImpl2);
// In practice, you would want upgradeToAndCall to call `initialize`.
// But that fails when we use the same storage slot for both MSCAs
// This test is still useful in proving that `upgradeToAndCall` succeeded with no installed plugins
msca.executeBatch(calls);
}
}