# Balancer hardfork
## Introduction
Now that the soft fork is active and seems to be holding strong, it's time to prepare for the hardfork. It will happen before Fusaka, so that we can remove all the code related to the soft fork for the Fusaka one. It will be a public hardfork, as there should no longer be any threat from the attacker. That means that all the code should be public as well.
We will give 7-14 days to our validators to upgrade. The target to publish releases is end of next week. Hopefully that's achievable with Devconnect.
## Spec
The spec consists of 2 changes: overriding the EOA and tuning the censoring code. All the code can now be public, but it's totally fine if it's not in the main branch.
### EOA override
Override the EOA of the attacker (`0x506D1f9EFe24f0d47853aDca907EB8d89AE03207`) with the bytecode generated from the following Solidity code:
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
contract HardcodedForwarder {
address public constant owner = 0x7Be579238a6a621601Eae2c346cDA54d68F7dfee;
modifier onlyOwner() {
_onlyOwner();
_;
}
function _onlyOwner() internal view {
require(msg.sender == owner, "not owner");
}
function execute(
address target,
uint256 value,
bytes calldata data
) external onlyOwner returns (bytes memory result) {
require(target != address(0), "zero target");
require(target.code.length > 0, "not a contract");
(bool success, bytes memory returndata) = target.call{value: value}(
data
);
if (!success) {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(returndata, 0x20), returndata_size)
}
} else {
revert("call failed");
}
}
return returndata;
}
receive() external payable {}
}
```
The contract was deployed for testing at [0x87b95414E23f122c00C896d6Ce671B44Cf471C96](https://gnosisscan.io/address/0x87b95414E23f122c00C896d6Ce671B44Cf471C96#code), and the bytecode is:
```
0x60806040526004361061002c575f3560e01c80638da5cb5b14610037578063b61d27f61461006157610033565b3661003357005b5f5ffd5b348015610042575f5ffd5b5061004b610091565b604051610058919061030a565b60405180910390f35b61007b600480360381019061007691906103e9565b6100a9565b60405161008891906104ca565b60405180910390f35b737be579238a6a621601eae2c346cda54d68f7dfee81565b60606100b3610247565b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610121576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161011890610544565b60405180910390fd5b5f8573ffffffffffffffffffffffffffffffffffffffff163b1161017a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610171906105ac565b60405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff168686866040516101a4929190610606565b5f6040518083038185875af1925050503d805f81146101de576040519150601f19603f3d011682016040523d82523d5f602084013e6101e3565b606091505b50915091508161023a575f815111156101ff5780518060208301fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161023190610668565b60405180910390fd5b8092505050949350505050565b737be579238a6a621601eae2c346cda54d68f7dfee73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146102c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c0906106d0565b60405180910390fd5b565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6102f4826102cb565b9050919050565b610304816102ea565b82525050565b5f60208201905061031d5f8301846102fb565b92915050565b5f5ffd5b5f5ffd5b610334816102ea565b811461033e575f5ffd5b50565b5f8135905061034f8161032b565b92915050565b5f819050919050565b61036781610355565b8114610371575f5ffd5b50565b5f813590506103828161035e565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126103a9576103a8610388565b5b8235905067ffffffffffffffff8111156103c6576103c561038c565b5b6020830191508360018202830111156103e2576103e1610390565b5b9250929050565b5f5f5f5f6060858703121561040157610400610323565b5b5f61040e87828801610341565b945050602061041f87828801610374565b935050604085013567ffffffffffffffff8111156104405761043f610327565b5b61044c87828801610394565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61049c8261045a565b6104a68185610464565b93506104b6818560208601610474565b6104bf81610482565b840191505092915050565b5f6020820190508181035f8301526104e28184610492565b905092915050565b5f82825260208201905092915050565b7f7a65726f207461726765740000000000000000000000000000000000000000005f82015250565b5f61052e600b836104ea565b9150610539826104fa565b602082019050919050565b5f6020820190508181035f83015261055b81610522565b9050919050565b7f6e6f74206120636f6e74726163740000000000000000000000000000000000005f82015250565b5f610596600e836104ea565b91506105a182610562565b602082019050919050565b5f6020820190508181035f8301526105c38161058a565b9050919050565b5f81905092915050565b828183375f83830152505050565b5f6105ed83856105ca565b93506105fa8385846105d4565b82840190509392505050565b5f6106128284866105e2565b91508190509392505050565b7f63616c6c206661696c65640000000000000000000000000000000000000000005f82015250565b5f610652600b836104ea565b915061065d8261061e565b602082019050919050565b5f6020820190508181035f83015261067f81610646565b9050919050565b7f6e6f74206f776e657200000000000000000000000000000000000000000000005f82015250565b5f6106ba6009836104ea565b91506106c582610686565b602082019050919050565b5f6020820190508181035f8301526106e7816106ae565b905091905056fea2646970667358221220a8334a26f31db2a806db6c1bcc4107caa8ec5cbdc7b742cfec99b4f0cca066a364736f6c634300081e0033
```
This code intentionally does not require any storage to simplify the code change for the hardfork. The address is yet to be defined, and will be a Safe{Wallet} deployed before the shadowfork.
This override needs to happen at the very beginning of block execution, before EIP-4788 and EIP-2935. The hardfork will get activated at a specific timestamp rather than a specific block height. This thus differs from how the previous bytecode override (for the bridge token implementation) was executed. The bytecode override should be executed if the current block time is bigger or equal to the hardfork time, and the previous block time was smaller than the hardfork block time.
### Censoring code
The censoring code put in place for the softfork obviously has to stay active until the hardfork activates, so that there's no timeframe during which the attacker could recover the funds.
The additional change is that the censoring should be disabled once the hardfork gets activated. In theory it is not necessary, as the recovery scripts will be called from a Safe to the attacker's EOA (which is only banned as a "from"), but I don't see a point in keeping it active any longer.
The current, live configuration is the following:
```json
"censoringSchedule": [
{
"timestamp": "0x690b5158",
"senders": [
"0x506d1f9efe24f0d47853adca907eb8d89ae03207",
"0x491837cc85bbeab5f9b3110ad61f39d87f8ec618"
],
"to": [
"0x5e7fa86cfdd10de6129e53377335b78bb34eabd3",
"0x234490fa3cd6c899681c8e93ba88e97183a71fe4",
"0x49b5ce67b22b1d596842ca071ac3da93ee593e11",
"0x7b23c07a0bbbe652bf7069c9c4143a2c85132166",
"0x1bdc1febebf92bffab3a2e49c5cf3b7e35a9e81e"
],
"is7702PatchEnabled": false
},
{
"timestamp": "0x690cfe40",
"senders": [
"0x506d1f9efe24f0d47853adca907eb8d89ae03207",
"0x491837cc85bbeab5f9b3110ad61f39d87f8ec618"
],
"to": [
"0x5e7fa86cfdd10de6129e53377335b78bb34eabd3",
"0x234490fa3cd6c899681c8e93ba88e97183a71fe4",
"0x49b5ce67b22b1d596842ca071ac3da93ee593e11",
"0x7b23c07a0bbbe652bf7069c9c4143a2c85132166",
"0x1bdc1febebf92bffab3a2e49c5cf3b7e35a9e81e"
],
"is7702PatchEnabled": true
}
]
```
This will need to be updated with the following configuration, or something similar to disable the soft fork on the hardfork slot:
```json
{
"timestamp": BALANCER_HARDFORK_TIMESTAMP,
"senders": [],
"to": [],
"is7702PatchEnabled": false
}
```
## Testing
For testing purposes, we will spin up a shadowfork with all 4 consensus layer clients. There are 2 things we're going to test:
1) We can actually recover all the funds, and all clients follow consensus
2) I also want to double check that [EIP-3607](https://eips.ethereum.org/EIPS/eip-3607) works as expected. For this, I would like to also override another random EOA with the same bytecode to make sure that the EOA can no longer execute transactions. This EOA is:
- Address: `0xd573BC65602d4Ea7e4ABe707c15FB5FC461CE0F1`
- Private key: `0x85123b7b9a957824a871223e04bd826aa96c85b52dc72900e932d694680f657d`
## Configuration
There are 2 pending configuration variables for this hardfork:
- The traditional fork timestamp
- The bytecode to set on `0x506D1f9EFe24f0d47853aDca907EB8d89AE03207` (and `0xd573BC65602d4Ea7e4ABe707c15FB5FC461CE0F1` on the shadowfork)