|
| 1 | +// SPDX-License-Identifier: UNLICENSED |
| 2 | +pragma solidity ^0.8.23; |
| 3 | + |
| 4 | +import {EIP7702ProxyBase} from "../base/EIP7702ProxyBase.sol"; |
| 5 | +import {EIP7702Proxy} from "../../src/EIP7702Proxy.sol"; |
| 6 | +import {CoinbaseSmartWallet} from "../../lib/smart-wallet/src/CoinbaseSmartWallet.sol"; |
| 7 | +import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; |
| 8 | + |
| 9 | +contract UpgradeToAndCallTest is EIP7702ProxyBase { |
| 10 | + DummyImplementation newImplementation; |
| 11 | + |
| 12 | + function setUp() public override { |
| 13 | + super.setUp(); |
| 14 | + |
| 15 | + // Initialize the proxy first |
| 16 | + bytes memory initArgs = _createInitArgs(_newOwner); |
| 17 | + bytes memory signature = _signInitData(_EOA_PRIVATE_KEY, initArgs); |
| 18 | + EIP7702Proxy(_eoa).initialize(initArgs, signature); |
| 19 | + |
| 20 | + // Deploy new implementation |
| 21 | + newImplementation = new DummyImplementation(); |
| 22 | + } |
| 23 | + |
| 24 | + function testUpgradeToAndCall_succeedsForOwner() public { |
| 25 | + // Wallet owner should be able to upgrade |
| 26 | + vm.prank(_newOwner); |
| 27 | + |
| 28 | + CoinbaseSmartWallet(payable(_eoa)).upgradeToAndCall( |
| 29 | + address(newImplementation), |
| 30 | + abi.encodeWithSignature("dummy()") |
| 31 | + ); |
| 32 | + |
| 33 | + // Verify upgrade worked by calling new function |
| 34 | + vm.expectEmit(true, true, true, true, _eoa); |
| 35 | + emit DummyImplementation.DummyCalled(); |
| 36 | + DummyImplementation(payable(_eoa)).dummy(); |
| 37 | + } |
| 38 | + |
| 39 | + function testUpgradeToAndCall_succeedsForEOA() public { |
| 40 | + // EOA should be able to upgrade |
| 41 | + vm.prank(_eoa); |
| 42 | + |
| 43 | + CoinbaseSmartWallet(payable(_eoa)).upgradeToAndCall( |
| 44 | + address(newImplementation), |
| 45 | + abi.encodeWithSignature("dummy()") |
| 46 | + ); |
| 47 | + |
| 48 | + // Verify upgrade worked by calling new function |
| 49 | + vm.expectEmit(true, true, true, true, _eoa); |
| 50 | + emit DummyImplementation.DummyCalled(); |
| 51 | + DummyImplementation(payable(_eoa)).dummy(); |
| 52 | + } |
| 53 | + |
| 54 | + function testUpgradeToAndCall_revertsForNonOwner() public { |
| 55 | + vm.prank(address(0xBAD)); |
| 56 | + vm.expectRevert(); // CoinbaseSmartWallet will revert for non-owner |
| 57 | + CoinbaseSmartWallet(payable(_eoa)).upgradeToAndCall( |
| 58 | + address(newImplementation), |
| 59 | + "" |
| 60 | + ); |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +contract DummyImplementation is UUPSUpgradeable { |
| 65 | + event DummyCalled(); |
| 66 | + |
| 67 | + function dummy() external { |
| 68 | + emit DummyCalled(); |
| 69 | + } |
| 70 | + |
| 71 | + function _authorizeUpgrade(address) internal override {} |
| 72 | +} |
0 commit comments