Skip to content

Commit

Permalink
feat: add migration to upgrade contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
fedealconada committed Jan 23, 2024
1 parent 81c1b99 commit 47496f6
Show file tree
Hide file tree
Showing 16 changed files with 606 additions and 18 deletions.
190 changes: 190 additions & 0 deletions broadcast/21-multiple_upgrade.sol/7887/dry-run/run-1706036947.json

Large diffs are not rendered by default.

190 changes: 190 additions & 0 deletions broadcast/21-multiple_upgrade.sol/7887/dry-run/run-latest.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion script/deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "../src/viewers/KYCViewer.sol";
import "../src/interfaces/IKintoWallet.sol";
import "../src/wallet/KintoWalletFactory.sol";
import "../src/paymasters/SponsorPaymaster.sol";
import {KintoWalletV3 as KintoWallet} from "../src/wallet/KintoWallet.sol";
import "../src/wallet/KintoWallet.sol";

import "../test/helpers/Create2Helper.sol";
import "../test/helpers/ArtifactsReader.sol";
Expand Down
6 changes: 6 additions & 0 deletions script/migrations/10-upgrade_wallet_v3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,9 @@ contract KintoMigration10DeployScript is Create2Helper, ArtifactsReader {
console.log(string.concat('"KintoWalletV3-impl": "', vm.toString(address(_kintoWalletImpl)), '"'));
}
}

contract KintoWalletV3 is KintoWallet {
constructor(IEntryPoint _entryPoint, IKintoID _kintoID, IKintoAppRegistry _appRegistry)
KintoWallet(_entryPoint, _kintoID, _appRegistry)
{}
}
4 changes: 4 additions & 0 deletions script/migrations/11-upgrade_paymasterv2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@ contract KintoMigration11DeployScript is Create2Helper, ArtifactsReader {
console.log(string.concat('"SponsorPaymasterV2-impl": "', vm.toString(address(_paymasterImpl)), '"'));
}
}

contract SponsorPaymasterV2 is SponsorPaymaster {
constructor(IEntryPoint __entryPoint) SponsorPaymaster(__entryPoint) {}
}
4 changes: 4 additions & 0 deletions script/migrations/13-upgrade_id_paymasterv3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,7 @@ contract KintoMigration13DeployScript is Create2Helper, ArtifactsReader {
console.log(string.concat('"KintoIDV3-impl": "', vm.toString(address(_kintoIDImpl)), '"'));
}
}

contract SponsorPaymasterV3 is SponsorPaymaster {
constructor(IEntryPoint __entryPoint) SponsorPaymaster(__entryPoint) {}
}
10 changes: 10 additions & 0 deletions script/migrations/20-faucet_fund_fix.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,13 @@ contract KintoMigration20DeployScript is Create2Helper, ArtifactsReader {
console.log(string.concat('"KintoWalletFactoryV6-impl": "', vm.toString(address(_factoryImpl)), '"'));
}
}

contract KintoWalletFactoryV6 is KintoWalletFactory {
constructor(IKintoWallet _implAddressP) KintoWalletFactory(_implAddressP) {}
}

contract KintoWalletV3 is KintoWallet {
constructor(IEntryPoint _entryPoint, IKintoID _kintoID, IKintoAppRegistry _appRegistry)
KintoWallet(_entryPoint, _kintoID, _appRegistry)
{}
}
176 changes: 176 additions & 0 deletions script/migrations/21-multiple_upgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "../../src/wallet/KintoWalletFactory.sol";
import "../../src/wallet/KintoWallet.sol";
import "../../src/apps/KintoAppRegistry.sol";
import "../../src/paymasters/SponsorPaymaster.sol";
import "../../src/viewers/KYCViewer.sol";
import "../../src/KintoID.sol";

import "../../test/helpers/Create2Helper.sol";
import "../../test/helpers/ArtifactsReader.sol";
import "../../test/helpers/UUPSProxy.sol";
import "../../test/helpers/UserOp.sol";

import "forge-std/Script.sol";
import "forge-std/console.sol";

contract KintoMigration21DeployScript is Create2Helper, ArtifactsReader, UserOp {
using ECDSAUpgradeable for bytes32;

KintoWalletFactory _walletFactory;
uint256 deployerPrivateKey;

// NOTE: this migration must be run from the ledger admin
function run() public {
console.log("RUNNING ON CHAIN WITH ID", vm.toString(block.chainid));

deployerPrivateKey = vm.envUint("PRIVATE_KEY");

// execute this script with the with the ledger
console.log("Executing from address", msg.sender);

// set wallet factory
_walletFactory = KintoWalletFactory(payable(_getChainDeployment("KintoWalletFactory")));

SponsorPaymasterV4 _paymasterImpl = SponsorPaymasterV4(upgradePaymaster());
console.log(string.concat("SponsorPaymasterV4-impl: ", vm.toString(address(_paymasterImpl))));

KintoAppRegistryV3 _registryImpl = KintoAppRegistryV3(upgradeRegistry());
console.log(string.concat("KintoAppRegistryV3-impl: ", vm.toString(address(_registryImpl))));

KintoWalletV4 _walletImpl = KintoWalletV4(payable(upgradeWallet()));
console.log(string.concat("KintoWalletV4-impl: ", vm.toString(address(_walletImpl))));

KintoWalletFactoryV7 _factoryImpl = KintoWalletFactoryV7(upgradeFactory());
console.log(string.concat("KintoWalletFactoryV7-impl: ", vm.toString(address(_factoryImpl))));

KYCViewerV2 _kycViewerImpl = KYCViewerV2(upgradeKYCViewer());
console.log(string.concat("KYCViewerV2-impl: ", vm.toString(address(_kycViewerImpl))));

// writes the addresses to a file
console.log("TODO: Manually add these new addresses to the artifacts file");
console.log(string.concat("SponsorPaymasterV4-impl: ", vm.toString(address(_paymasterImpl))));
console.log(string.concat("KintoAppRegistryV3-impl: ", vm.toString(address(_registryImpl))));
console.log(string.concat("KintoWalletV4-impl: ", vm.toString(address(_walletImpl))));
console.log(string.concat("KintoWalletFactoryV7-impl: ", vm.toString(address(_factoryImpl))));
console.log(string.concat("KYCViewerV2-impl: ", vm.toString(address(_kycViewerImpl))));
}

function upgradePaymaster() public returns (address _paymasterImpl) {
// (1). deploy new paymaster implementation via wallet factory
address paymasterProxy = _getChainDeployment("SponsorPaymaster");
require(paymasterProxy != address(0), "Need to execute main deploy script first");

bytes memory bytecode =
abi.encodePacked(type(SponsorPaymasterV4).creationCode, abi.encode(_getChainDeployment("EntryPoint")));

vm.broadcast(deployerPrivateKey);
_paymasterImpl = _walletFactory.deployContract(vm.rememberKey(deployerPrivateKey), 0, bytecode, bytes32(0));

// (3). upgrade paymaster to new implementation
vm.broadcast(); // requires LEDGER_ADMIN
// vm.prank(vm.envAddress("LEDGER_ADMIN"));
SponsorPaymaster(payable(paymasterProxy)).upgradeTo(address(_paymasterImpl));
}

function upgradeRegistry() public returns (address _registryImpl) {
// (1). deploy new kinto registry implementation via wallet factory
address registryProxy = _getChainDeployment("KintoAppRegistry");
require(registryProxy != address(0), "Need to execute main deploy script first");

bytes memory bytecode =
abi.encodePacked(type(KintoAppRegistryV3).creationCode, abi.encode(address(_walletFactory)));

vm.broadcast(deployerPrivateKey);
_registryImpl =
_walletFactory.deployContract{value: 0}(vm.rememberKey(deployerPrivateKey), 0, bytecode, bytes32("1"));

// (2). upgrade registry to new implementation
_upgradeTo(payable(registryProxy), _registryImpl, deployerPrivateKey);
}

function upgradeWallet() public returns (address _walletImpl) {
// (1). deploy new kinto wallet implementation via wallet factory
bytes memory bytecode = abi.encodePacked(
type(KintoWalletV4).creationCode,
abi.encode(
_getChainDeployment("EntryPoint"),
IKintoID(_getChainDeployment("KintoID")),
IKintoAppRegistry(_getChainDeployment("KintoAppRegistry"))
)
);
vm.broadcast(deployerPrivateKey);
_walletImpl = _walletFactory.deployContract(vm.rememberKey(deployerPrivateKey), 0, bytecode, bytes32(0));

// (2). upgrade all implementations
vm.broadcast(); // requires LEDGER_ADMIN
// vm.prank(vm.envAddress("LEDGER_ADMIN"));
_walletFactory.upgradeAllWalletImplementations(IKintoWallet(_walletImpl));
}

function upgradeFactory() public returns (address _factoryImpl) {
// (1). deploy new kinto factory
address factoryProxy = _getChainDeployment("KintoWalletFactory");
require(factoryProxy != address(0), "Need to execute main deploy script first");

address _walletImpl = _getChainDeployment("KintoWalletV3-impl");
require(_walletImpl != address(0), "Need to deploy the new wallet first");

bytes memory bytecode = abi.encodePacked(
type(KintoWalletFactoryV7).creationCode,
abi.encode(_walletImpl) // Encoded constructor arguments
);

vm.broadcast(deployerPrivateKey);
_factoryImpl = _walletFactory.deployContract(vm.rememberKey(deployerPrivateKey), 0, bytecode, bytes32(0));

// (2). upgrade factory to new implementation
vm.broadcast(); // requires LEDGER_ADMIN
// vm.prank(vm.envAddress("LEDGER_ADMIN"));
KintoWalletFactory(payable(factoryProxy)).upgradeTo(address(_factoryImpl));
}

function upgradeKYCViewer() public returns (address _kycViewer) {
// (1). deploy new kyc viewer
address viewerProxy = _getChainDeployment("KYCViewer");
require(viewerProxy != address(0), "Need to execute main deploy script first");

bytes memory bytecode = abi.encodePacked(
type(KYCViewerV2).creationCode,
abi.encode(_walletFactory) // Encoded constructor arguments
);

vm.broadcast(deployerPrivateKey);
_kycViewer = _walletFactory.deployContract(vm.rememberKey(deployerPrivateKey), 0, bytecode, bytes32(0));

// (2). upgrade viewer to new implementation
vm.broadcast(); // requires LEDGER_ADMIN
// vm.prank(vm.envAddress("LEDGER_ADMIN"));
KYCViewer(payable(viewerProxy)).upgradeTo(address(_kycViewer));
}

function _upgradeTo(address proxy, address _newFaucetImpl, uint256 _signerPk) internal {
address payable adminWallet = payable(_getChainDeployment("KintoWallet-admin"));

// prep upgradeTo user op
uint256 nonce = IKintoWallet(adminWallet).getNonce();
uint256[] memory privateKeys = new uint256[](1);
privateKeys[0] = _signerPk;
UserOperation[] memory userOps = new UserOperation[](1);
userOps[0] = _createUserOperation(
block.chainid,
adminWallet,
proxy,
0,
nonce,
privateKeys,
abi.encodeWithSelector(UUPSUpgradeable.upgradeTo.selector, address(_newFaucetImpl)),
_getChainDeployment("SponsorPaymaster")
);

vm.broadcast(deployerPrivateKey);
IEntryPoint(_getChainDeployment("EntryPoint")).handleOps(userOps, payable(vm.addr(_signerPk)));
}
}
4 changes: 4 additions & 0 deletions src/apps/KintoAppRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,7 @@ contract KintoAppRegistry is
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
}
}

contract KintoAppRegistryV3 is KintoAppRegistry {
constructor(IKintoWalletFactory _walletFactory) KintoAppRegistry(_walletFactory) {}
}
6 changes: 1 addition & 5 deletions src/paymasters/SponsorPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,6 @@ contract SponsorPaymaster is Initializable, BasePaymaster, UUPSUpgradeable, Reen
}
}

contract SponsorPaymasterV2 is SponsorPaymaster {
constructor(IEntryPoint __entryPoint) SponsorPaymaster(__entryPoint) {}
}

contract SponsorPaymasterV3 is SponsorPaymaster {
contract SponsorPaymasterV4 is SponsorPaymaster {
constructor(IEntryPoint __entryPoint) SponsorPaymaster(__entryPoint) {}
}
4 changes: 4 additions & 0 deletions src/viewers/KYCViewer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,7 @@ contract KYCViewer is Initializable, UUPSUpgradeable, OwnableUpgradeable, IKYCVi
return _address;
}
}

contract KYCViewerV2 is KYCViewer {
constructor(address _kintoWalletFactory) KYCViewer(_kintoWalletFactory) {}
}
2 changes: 1 addition & 1 deletion src/wallet/KintoWallet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ contract KintoWallet is Initializable, BaseAccount, TokenCallbackHandler, IKinto
}

// Upgradeable version of KintoWallet
contract KintoWalletV3 is KintoWallet {
contract KintoWalletV4 is KintoWallet {
constructor(IEntryPoint _entryPoint, IKintoID _kintoID, IKintoAppRegistry _appRegistry)
KintoWallet(_entryPoint, _kintoID, _appRegistry)
{}
Expand Down
8 changes: 6 additions & 2 deletions src/wallet/KintoWalletFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,11 @@ contract KintoWalletFactory is Initializable, UUPSUpgradeable, OwnableUpgradeabl
* @param target The target address
*/
function sendMoneyToAccount(address target) external payable override {
require(owner() == msg.sender || kintoID.isKYC(msg.sender), "KYC required");
require(
owner() == msg.sender || kintoID.isKYC(msg.sender)
|| IAccessControl(address(kintoID)).hasRole(kintoID.KYC_PROVIDER_ROLE(), msg.sender),
"KYC or Provider role required"
);
(bool sent,) = target.call{value: msg.value}("");
require(sent, "Failed to send Ether");
}
Expand Down Expand Up @@ -293,6 +297,6 @@ contract KintoWalletFactory is Initializable, UUPSUpgradeable, OwnableUpgradeabl
}
}

contract KintoWalletFactoryV6 is KintoWalletFactory {
contract KintoWalletFactoryV7 is KintoWalletFactory {
constructor(IKintoWallet _implAddressP) KintoWalletFactory(_implAddressP) {}
}
12 changes: 6 additions & 6 deletions test/KYCViewer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import "./helpers/UserOp.sol";
import "./helpers/UUPSProxy.sol";
import {AATestScaffolding} from "./helpers/AATestScaffolding.sol";

contract KYCViewerV2 is KYCViewer {
contract KYCViewerUpgraded is KYCViewer {
function newFunction() external pure returns (uint256) {
return 1;
}
Expand All @@ -26,9 +26,9 @@ contract KYCViewerTest is UserOp, AATestScaffolding {

UUPSProxy _proxyViewer;
KYCViewer _implkycViewer;
KYCViewerV2 _implkycViewerV2;
KYCViewerUpgraded _implKYCViewerUpgraded;
KYCViewer _kycViewer;
KYCViewerV2 _kycViewer2;
KYCViewerUpgraded _kycViewer2;

function setUp() public {
vm.chainId(_chainID);
Expand Down Expand Up @@ -59,16 +59,16 @@ contract KYCViewerTest is UserOp, AATestScaffolding {

function testOwnerCanUpgradeViewer() public {
vm.startPrank(_owner);
KYCViewerV2 _implementationV2 = new KYCViewerV2(address(_walletFactory));
KYCViewerUpgraded _implementationV2 = new KYCViewerUpgraded(address(_walletFactory));
_kycViewer.upgradeTo(address(_implementationV2));
// re-wrap the _proxy
_kycViewer2 = KYCViewerV2(address(_kycViewer));
_kycViewer2 = KYCViewerUpgraded(address(_kycViewer));
assertEq(_kycViewer2.newFunction(), 1);
vm.stopPrank();
}

function test_RevertWhen_OthersCannotUpgradeFactory() public {
KYCViewerV2 _implementationV2 = new KYCViewerV2(address(_walletFactory));
KYCViewerUpgraded _implementationV2 = new KYCViewerUpgraded(address(_walletFactory));
vm.expectRevert("only owner");
_kycViewer.upgradeTo(address(_implementationV2));
}
Expand Down
2 changes: 1 addition & 1 deletion test/KintoWalletFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import "../src/wallet/KintoWalletFactory.sol";
import "../src/KintoID.sol";
import "../src/sample/Counter.sol";
import "../src/interfaces/IKintoWallet.sol";
import {KintoWalletV3 as KintoWallet} from "../src/wallet/KintoWallet.sol";
import "../src/wallet/KintoWallet.sol";

import {AATestScaffolding} from "./helpers/AATestScaffolding.sol";
import {UserOp} from "./helpers/UserOp.sol";
Expand Down
4 changes: 2 additions & 2 deletions test/helpers/AATestScaffolding.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import "../../src/KintoID.sol";
import "../../src/apps/KintoAppRegistry.sol";
import "../../src/tokens/EngenCredits.sol";
import "../../src/paymasters/SponsorPaymaster.sol";
import {KintoWalletV3 as KintoWallet} from "../../src/wallet/KintoWallet.sol";
import {KintoWalletFactoryV6 as KintoWalletFactory} from "../../src/wallet/KintoWalletFactory.sol";
import "../../src/wallet/KintoWallet.sol";
import "../../src/wallet/KintoWalletFactory.sol";

import "../helpers/UUPSProxy.sol";
import "../helpers/KYCSignature.sol";
Expand Down

0 comments on commit 47496f6

Please sign in to comment.