Skip to content

Commit

Permalink
Merge pull request #210 from etherfi-protocol/syko/feature/admin_can_…
Browse files Browse the repository at this point in the history
…unpause_liquifier

Upgrade Liquifier so that Admin can {unPause, update the deposit cap} + Deterministic Deploy via create2
  • Loading branch information
seongyun-ko authored Dec 21, 2024
2 parents 02c3d8f + 467cfcf commit 3519897
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 224 deletions.
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ optimizer_runs = 2000
extra_output = ["storageLayout"]
bytecode_hash = 'none'
solc-version = '0.8.24'
bytecode_hash = 'none'

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
[rpc_endpoints]
Expand Down
13 changes: 13 additions & 0 deletions operations/20241212_upgrade_liquifier.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{ "version": "1.0", "chainId": "1", "meta": { "name": "Transactions Batch", "description": "", "txBuilderVersion": "1.16.5", "createdFromSafeAddress": "0xcdd57D11476c22d265722F68390b036f3DA48c21" }, "transactions": [
{
"to": "0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
"value": "0",
"data": "0x01d5062a0000000000000000000000009ffdf407cde9a93c47611799da23924af3ef764f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f48000000000000000000000000000000000000000000000000000000000000000243659cfe6000000000000000000000000a1a15fb15cbda9e6c480c5bca6e9aba9c5e2ff9500000000000000000000000000000000000000000000000000000000"
}
,
{
"to": "0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
"value": "0",
"data": "0x134008d30000000000000000000000009ffdf407cde9a93c47611799da23924af3ef764f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243659cfe6000000000000000000000000a1a15fb15cbda9e6c480c5bca6e9aba9c5e2ff9500000000000000000000000000000000000000000000000000000000"
}
] }
194 changes: 194 additions & 0 deletions script/ContractCodeChecker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {console} from "forge-std/console.sol";
import {console2} from "forge-std/console2.sol";


contract ContractCodeChecker {

event ByteMismatchSegment(
uint256 startIndex,
uint256 endIndex,
bytes aSegment,
bytes bSegment
);

function compareBytes(bytes memory a, bytes memory b) internal returns (bool) {
if (a.length != b.length) {
// Length mismatch, emit one big segment for the difference if that’s desirable
// or just return false. For clarity, we can just return false here.
return false;
}

uint256 len = a.length;
uint256 start = 0;
bool inMismatch = false;
bool anyMismatch = false;

for (uint256 i = 0; i < len; i++) {
bool mismatch = (a[i] != b[i]);
if (mismatch && !inMismatch) {
// Starting a new mismatch segment
start = i;
inMismatch = true;
} else if (!mismatch && inMismatch) {
// Ending the current mismatch segment at i-1
emitMismatchSegment(a, b, start, i - 1);
inMismatch = false;
anyMismatch = true;
}
}

// If we ended with a mismatch still open, close it out
if (inMismatch) {
emitMismatchSegment(a, b, start, len - 1);
anyMismatch = true;
}

// If no mismatch segments were found, everything matched
return !anyMismatch;
}

function emitMismatchSegment(
bytes memory a,
bytes memory b,
uint256 start,
uint256 end
) internal {
// endIndex is inclusive
uint256 segmentLength = end - start + 1;

bytes memory aSegment = new bytes(segmentLength);
bytes memory bSegment = new bytes(segmentLength);

for (uint256 i = 0; i < segmentLength; i++) {
aSegment[i] = a[start + i];
bSegment[i] = b[start + i];
}

string memory aHex = bytesToHexString(aSegment);
string memory bHex = bytesToHexString(bSegment);

console2.log("- Mismatch segment at index [%s, %s]", start, end);
console2.logString(string.concat(" - ", aHex));
console2.logString(string.concat(" - ", bHex));

emit ByteMismatchSegment(start, end, aSegment, bSegment);
}

function bytesToHexString(bytes memory data) internal pure returns (string memory) {
bytes memory alphabet = "0123456789abcdef";

// Every byte corresponds to two hex characters
bytes memory str = new bytes(2 + data.length * 2);
str[0] = '0';
str[1] = 'x';
for (uint256 i = 0; i < data.length; i++) {
str[2 + i * 2] = alphabet[uint8(data[i] >> 4)];
str[3 + i * 2] = alphabet[uint8(data[i] & 0x0f)];
}
return string(str);
}

// Compare the full bytecode of two deployed contracts, ensuring a perfect match.
function verifyFullMatch(address deployedImpl, address localDeployed) public {
console2.log("Verifying full bytecode match...");
bytes memory localBytecode = address(localDeployed).code;
bytes memory onchainRuntimeBytecode = address(deployedImpl).code;

if (compareBytes(localBytecode, onchainRuntimeBytecode)) {
console2.log("-> Full Bytecode Match: Success\n");
} else {
console2.log("-> Full Bytecode Match: Fail\n");
}
}

function verifyPartialMatch(address deployedImpl, address localDeployed) public {
console2.log("Verifying partial bytecode match...");

// Fetch runtime bytecode from on-chain addresses
bytes memory localBytecode = localDeployed.code;
bytes memory onchainRuntimeBytecode = deployedImpl.code;

// Optionally check length first (not strictly necessary if doing a partial match)
if (localBytecode.length == 0 || onchainRuntimeBytecode.length == 0) {
revert("One of the bytecode arrays is empty, cannot verify.");
}

// Attempt to trim metadata from both local and on-chain bytecode
bytes memory trimmedLocal = trimMetadata(localBytecode);
bytes memory trimmedOnchain = trimMetadata(onchainRuntimeBytecode);

// If trimmed lengths differ significantly, it suggests structural differences in code
if (trimmedLocal.length != trimmedOnchain.length) {
revert("Post-trim length mismatch: potential code differences.");
}

// Compare trimmed arrays byte-by-byte
if (compareBytes(trimmedLocal, trimmedOnchain)) {
console2.log("-> Partial Bytecode Match: Success\n");
} else {
console2.log("-> Partial Bytecode Match: Fail\n");
}
}

function verifyLengthMatch(address deployedImpl, address localDeployed) public {
console2.log("Verifying length match...");
bytes memory localBytecode = localDeployed.code;
bytes memory onchainRuntimeBytecode = deployedImpl.code;

if (localBytecode.length == onchainRuntimeBytecode.length) {
console2.log("-> Length Match: Success\n");
} else {
console2.log("-> Length Match: Fail\n");
}
}

function verifyContractByteCodeMatch(address deployedImpl, address localDeployed) public {
verifyLengthMatch(deployedImpl, localDeployed);
verifyPartialMatch(deployedImpl, localDeployed);
verifyFullMatch(deployedImpl, localDeployed);
}

// A helper function to remove metadata (CBOR encoded) from the end of the bytecode.
// This is a heuristic based on known patterns in the metadata.
function trimMetadata(bytes memory code) internal pure returns (bytes memory) {
// Metadata usually starts with 0xa2 or a similar tag near the end.
// We can scan backward for a known marker.
// In Solidity 0.8.x, metadata often starts near the end with 0xa2 0x64 ... pattern.
// This is a simplified approach and may need refinement.

// For a more robust approach, you'd analyze the last bytes.
// Typically, the CBOR metadata is at the very end of the bytecode.
uint256 length = code.length;
if (length < 4) {
// Bytecode too short to have metadata
return code;
}

// Scan backward for a CBOR header (0xa2).
// We'll just look for 0xa2 from the end and truncate there.
for (uint256 i = length - 1; i > 0; i--) {
if (code[i] == 0xa2) {
console2.log("Found metadata start at index: ", i);
// print 8 bytes from this point
bytes memory tmp = new bytes(8);
for (uint256 j = 0; j < 8; j++) {
tmp[j] = code[i + j];
}

// Found a possible metadata start. We'll cut just before 0xa2.
bytes memory trimmed = new bytes(i);
for (uint256 j = 0; j < i; j++) {
trimmed[j] = code[j];
}
return trimmed;
}
}

// If no metadata marker found, return as is.
return code;
}

}
15 changes: 15 additions & 0 deletions script/Create2Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Create2.sol";

contract Create2Factory {
event Deployed(address addr, address deployer, bytes32 bytecode_hash, bytes32 salt);

function deploy(bytes memory code, bytes32 salt) external payable returns (address) {
address addr = Create2.deploy(msg.value, salt, code);

emit Deployed(addr, address(this), keccak256(code), salt);
return addr;
}
}
29 changes: 29 additions & 0 deletions script/deploys/DeployImplementationContract.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Script.sol";
// import "../../src/eBtcRateProvider.sol";
// import "../../src/helpers/EtherFiViewer.sol";
import "../../src/EtherFiNodesManager.sol";
import "../../src/EtherFiNode.sol";
import "../../src/EtherFiAdmin.sol";
import "../../src/EtherFiOracle.sol";
import "../../src/LiquidityPool.sol";
import "../../src/Liquifier.sol";

import "../Create2Factory.sol";


contract Deploy is Script {
bytes32 immutable salt = keccak256("ETHER_FI");
Create2Factory immutable factory = Create2Factory(0x6521991A0BC180a5df7F42b27F4eE8f3B192BA62);

function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.selectFork(vm.createFork(vm.envString("MAINNET_RPC_URL")));

vm.startBroadcast(deployerPrivateKey);
bytes memory code = abi.encodePacked(type(Liquifier).creationCode);
factory.deploy(code, salt);
}
}
Loading

0 comments on commit 3519897

Please sign in to comment.