# Dappnode APM Surgery
## Context
These are the two repos to upgrade:
- [besu.public.dappnode.eth](https://etherscan.io/address/0x2914045962C6ea7706311D47937Be373b71A6060) (PM: [nabsku.eth](https://etherscan.io/address/0x9cbBCD3B4129B1c00F0cd851BAf118ebb0c4F168))
- [Kernel](https://etherscan.io/address/0x0F3b8eC182DEee2381A9041e30f65f10098A3B91) (PM: [baylina.eth](https://etherscan.io/address/0x1dba1131000664b884a1ba238464159892252d3a))
- [ACL](https://etherscan.io/address/0xFCb2C44E61031AE29e5c54A700FB6B4FB430dA4C) (PM: [baylina.eth](https://etherscan.io/address/0x1dba1131000664b884a1ba238464159892252d3a))
- [goerli-besu.dnp.dappnode.eth](https://etherscan.io/address/0xf508C8Fc3F121B18794489659a5e2CcC255E9CA2) (PM: [nabsku.eth](https://etherscan.io/address/0x9cbBCD3B4129B1c00F0cd851BAf118ebb0c4F168))
- [Kernel](https://etherscan.io/address/0xFCdEDC0397603346788b2567fb5E6d9Fd2AEdF4C) (PM: [baylina.eth](https://etherscan.io/address/0x1dba1131000664b884a1ba238464159892252d3a))
- [ACL](https://etherscan.io/address/0x89d0A07b792754460Faa49e57437B40aA33FB757) (PM: [baylina.eth](https://etherscan.io/address/0x1dba1131000664b884a1ba238464159892252d3a))
## Actors
Three actors will have to intervene in order to change the Besu repo admin:
- **Jordi Baylina** (0x1dba...2d3a) as the deployer of the Dappnode Package Manager.
- **DappNode multisig** (0x5339...5efc4) signers as the future owners of the Dappnode Package Manager.
- **New Besu Repo Admin** (0xf359...bf1c1) as the new owner of the repo.
## Steps
1. **Jordi Baylina** transfers the Dappnode Package Manager permissions to the **DappNode multisig**.
- **Jordi Baylina** should execute the following script: [Transfer DappNode Package Manager Ownership](https://evmcrispr.com/#/terminal/QmbUhbzGqviChgWK3SUFiQL9kzP3FrfktoiWERo2c88fVd).
2. The **Dappnode Multisig** executes a batch transaction in which:
- For each public.dappnode.eth and dnp.dappnode.eth:
- As permission manager of the Kernel and the ACL permissions, it gives itself permission to execute functions in them.
- It upgrades the ACL to the Surgery contract.
- It sets a bypass with the previous ACL implementation.
- It modifies an ACL storage slot so the permission manager of the Besu Repo is the **DappNode Multisig**.
- It downgrades the ACL so it does not point to the Surgery anymore.
- It revokes the permissions from the previous admin **nabsuku.eth**.
- It sets the **New Besu Repo Admin** as the permission manager.
3. The **New Besu Repo Admin** should now be able to publish new versions of Besu in both DappNode Package Managers.
- This is tested with EVMcrispr + Tenderly: [Dappnode Surgery](https://evmcrispr.com/#/terminal/Qmd3Yg2i6bnqdrrbLP9bBkaxeHgNqER42qGFr7APGnkMXP).
## Update: May 1, 2024
Jordi executed the script so the repos now belong to the DappNode Safe.
We decided to separate the script in two batches, one for each repo:
- [Besu Repo script](https://evmcrispr.com/#/terminal/QmdtffGxJLrTVDQ4ewecbVMWULCxDtBqtV73AyVSko8Gpo) - [Simulation](https://dashboard.tenderly.co/explorer/fork/39893525-2a4f-4e88-89b6-244342d1730a/transactions) - [Txs Batch](https://ipfs.blossom.software/ipfs/QmfEs6QtGXZENoG4fHU4qsQD3TpNBZ2KrWjAJ1qBeajVt8/dappnode-surgery.json)
- [Goerli Besu Repo script](https://evmcrispr.com/#/terminal/QmYRURG7wVwkjfB6xt9bPzoLWPbzC2uzjTyqn9r75irYeM) - [Simulation](https://dashboard.tenderly.co/explorer/fork/a20c7581-53da-4432-bbdc-7934ff0abd04/transactions) - [Txs Batch](https://ipfs.blossom.software/ipfs/QmfEs6QtGXZENoG4fHU4qsQD3TpNBZ2KrWjAJ1qBeajVt8/dappnode-surgery-goerli.json)
## Surgery Smart Contract
The following smart contract [deployed on mainnet](https://etherscan.io/address/0xfb0c6eac700d5ba5e5c7ccf13a2b38d2f31776bc#code) is used to make the surgery:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Surgery {
// The storage slot where the address of the bypass contract is stored
// uint private constant BYPASS_SLOT = uint(keccak256("surgery.bypass"));
uint private constant BYPASS_SLOT = 0x53edf09d858352d72f64ef79097f9ffaee955e2757de83b69ff2afe447984250;
event Operation(uint256 slot, uint256 value, uint256 offset, uint256 size);
event BypassSet(address target);
function operate(uint256 slot, uint256 value) external {
assembly {
sstore(slot, value)
}
emit Operation(slot, value, 0, 32);
}
function getBypass() public view returns (address bypass) {
assembly {
bypass := sload(BYPASS_SLOT)
}
}
function setBypass(address _target) public {
assembly {
sstore(BYPASS_SLOT, _target)
}
emit BypassSet(_target);
}
function _delegate(address _implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
// calldatacopy(t, f, s) - copy s bytes from calldata at position f to mem at position t
// calldatasize() - size of call data in bytes
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
// delegatecall(g, a, in, insize, out, outsize) -
// - call contract at address a
// - with input mem[in…(in+insize))
// - providing g gas
// - and output area mem[out…(out+outsize))
// - returning 0 on error (eg. out of gas) and 1 on success
let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
// returndatacopy(t, f, s) - copy s bytes from returndata at position f to mem at position t
// returndatasize() - size of the last returndata
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
// revert(p, s) - end execution, revert state changes, return data mem[p…(p+s))
revert(0, returndatasize())
}
default {
// return(p, s) - end execution, return data mem[p…(p+s))
return(0, returndatasize())
}
}
}
function _fallback() private {
_delegate(getBypass());
}
fallback() external payable {
_fallback();
}
receive() external payable {
_fallback();
}
}
```