owned this note
owned this note
Published
Linked with GitHub
# Darkfix Technical Overview
## CREATE2 Opcode
Using `CREATE2`, we can determine the address of a contract before it is deployed. To do this, we need the following three items:
1. (`bytes`) init bytecode of the contract (currently undeployed)
2. (`address`) address of contract that will deploy the contract
3. (`bytes32`) salt (also referred to as the nonce)
The most simple option is to use a `CREATE2` generated address as the 'action' address in a spell, deploy, lift to the hat, and schedule the spell. Then, once beyond the 24 hour GSM delay, deploy the pre-authorized spell action contract, and then cast the plotted spell.
Typically, the 'SpellAction' contracts consists of a handful of constant state variables and an execute() function with no parameters. Within the execute function are the privileged calls to the DSS system, where the bug fix would occur. We're mostly copying the SpellAction contract style, so the bytecode size should be relatively small.
Successful `CREATE2` contract address generation requires that an existing contract deploys the new contract, so we need to deploy an 'deployer' contract beforehand that can populate the `CREATE2` contract address after the GSM delay has passed for a successful cast.
Example of the 'deployer' contract:
```
// pseudo-code
contract Create2 {
function deploy(bytes32 salt, bytes memory bytecode)
public
returns (address)
{
address addr;
assembly {
addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
return addr;
}
}
```
Example of a darkfix spell action:
```
contract DarkFixSpellAction {
OsmAbstract constant osm = OsmAbstract(_OSM_ADDRESS_);
function execute() public {
// stop the OSM price feed
osm.stop();
}
}
```
Example of the spell that points to the darkfix:
```
pragma solidity ^0.5.15;
import "ds-math/math.sol";
import "lib/dss-interfaces/src/dapp/DSPauseAbstract.sol";
contract DeployLike {
function deploy(bytes32, bytes memory) public returns (address);
}
contract DarkFix is DSMath {
DSPauseAbstract public pause = DSPauseAbstract(
_PAUSE_
);
DeployLike public deployer = DeployLike(
_DEPLOYED_
);
address public action;
bytes32 public tag;
uint256 public eta;
bytes public sig;
bool public done;
constructor() public {
sig = abi.encodeWithSignature(
"execute()"
);
tag = _DEPLOYHASH_;
action = _CREATE2_;
}
function schedule() public {
require(eta == 0, "spell-already-scheduled");
eta = add(now, pause.delay());
pause.plot(action, tag, sig, eta);
}
function cast(bytes memory _bytecode, bytes32 _salt) public {
require(!done, "spell-already-cast");
done = true;
deployer.deploy(_salt, _bytecode);
pause.exec(action, tag, sig, eta);
}
}
```
## What changes?
There are 2 changes in the above spell compared to our `traditional` spells:
1. The action address variable is changed to what currently looks like an unused externally owned account.
2. The assembly code block retrieving the `extcodehash` of the action address is removed, and instead the `byte32` hash of the deploy bytecode of the bug fix is hardcoded into the spell.
## Why this helps us?
1. The Solidity source code and the compiled bytecode is hidden prior to casting of the spell. Only after the SpellAction bytecode is deployed to the `CREATE2` address can the deployed bytecode be seen. The Solidity source code does not have to be published nor do we need to verify the Spell Action contract on Etherscan.
2. Malicious actors will have no source code or bytecode to reverse engineer and attempt to exploit.