-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ethereum contracts): Introduce governance-driven
ProxyUpdater
(#…
…179)
- Loading branch information
Showing
10 changed files
with
208 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
pragma solidity ^0.8.24; | ||
|
||
import {IMessageQueueReceiver} from "./interfaces/IMessageQueue.sol"; | ||
import {ProxyContract} from "./ProxyContract.sol"; | ||
|
||
contract ProxyUpdater is IMessageQueueReceiver { | ||
error NotAuthorized(); | ||
error NotGovernance(); | ||
error BadArguments(); | ||
error WrongDiscriminator(); | ||
|
||
ProxyContract proxy; | ||
bytes32 governance; | ||
address immutable MESSAGE_QUEUE_ADDRESS; | ||
|
||
constructor( | ||
address payable _proxy, | ||
bytes32 _governance, | ||
address message_queue | ||
) payable { | ||
proxy = ProxyContract(_proxy); | ||
governance = _governance; | ||
MESSAGE_QUEUE_ADDRESS = message_queue; | ||
} | ||
|
||
/** @dev Accept request from MessageQueue. Based on the first byte of the payload | ||
* make the decision what to do. | ||
* | ||
* If first byte = `0x00` then update implementation of underlying proxy. | ||
* If first byte = `0x01` then change admin of the underlying proxy. | ||
* If first byte = `0x02` then change governance. | ||
* | ||
* @param sender sender of message on the gear side. | ||
* @param payload payload of the message. | ||
*/ | ||
function processVaraMessage( | ||
bytes32 sender, | ||
bytes calldata payload | ||
) external returns (bool) { | ||
if (msg.sender != MESSAGE_QUEUE_ADDRESS) { | ||
revert NotAuthorized(); | ||
} | ||
if (sender != governance) { | ||
revert NotGovernance(); | ||
} | ||
|
||
uint8 discriminator = uint8(payload[0]); | ||
|
||
if (discriminator == 0x00) { | ||
if (payload.length < 1 + 20) { | ||
revert BadArguments(); | ||
} | ||
|
||
address new_implementation = address(bytes20(payload[1:21])); | ||
bytes calldata data = payload[21:]; | ||
|
||
proxy.upgradeToAndCall(new_implementation, data); | ||
} else if (discriminator == 0x01) { | ||
if (payload.length != 1 + 20) { | ||
revert BadArguments(); | ||
} | ||
|
||
address new_admin = address(bytes20(payload[1:])); | ||
|
||
proxy.changeProxyAdmin(new_admin); | ||
} else if (discriminator == 0x02) { | ||
if (payload.length != 1 + 32) { | ||
revert BadArguments(); | ||
} | ||
|
||
governance = bytes32(payload[1:]); | ||
} else { | ||
revert WrongDiscriminator(); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
function getGovernance() external view returns (bytes32) { | ||
return governance; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
pragma solidity ^0.8.13; | ||
|
||
import {Test} from "forge-std/Test.sol"; | ||
import {ProxyContract} from "../src/ProxyContract.sol"; | ||
import {ProxyUpdater} from "../src/ProxyUpdater.sol"; | ||
|
||
contract Empty {} | ||
|
||
contract ProxyUpdaterTest is Test { | ||
address constant MESSAGE_QUEUE = address(500); | ||
address constant NEW_ADMIN = address(1000); | ||
|
||
address initialImpl; | ||
address changedImpl; | ||
|
||
bytes32 constant GOVERNANCE = bytes32("governance_governance_governance"); | ||
bytes32 constant NEW_GOVERNANCE = | ||
bytes32("new_governance_governance_govern"); | ||
|
||
ProxyContract public proxy; | ||
ProxyUpdater public updater; | ||
|
||
function setUp() public { | ||
initialImpl = address(new Empty()); | ||
changedImpl = address(new Empty()); | ||
|
||
proxy = new ProxyContract(); | ||
proxy.upgradeToAndCall(initialImpl, ""); | ||
|
||
updater = new ProxyUpdater( | ||
payable(address(proxy)), | ||
GOVERNANCE, | ||
MESSAGE_QUEUE | ||
); | ||
|
||
proxy.changeProxyAdmin(address(updater)); | ||
} | ||
|
||
function test_updateImpl() public { | ||
vm.startPrank(MESSAGE_QUEUE); | ||
|
||
assertEq(proxy.implementation(), initialImpl); | ||
|
||
updater.processVaraMessage( | ||
GOVERNANCE, | ||
abi.encodePacked(uint8(0), changedImpl, "") | ||
); | ||
|
||
assertEq(proxy.implementation(), changedImpl); | ||
} | ||
|
||
function test_updateAdmin() public { | ||
vm.startPrank(MESSAGE_QUEUE); | ||
|
||
assertEq(proxy.proxyAdmin(), address(updater)); | ||
|
||
updater.processVaraMessage( | ||
GOVERNANCE, | ||
abi.encodePacked(uint8(1), NEW_ADMIN) | ||
); | ||
|
||
assertEq(proxy.proxyAdmin(), NEW_ADMIN); | ||
} | ||
|
||
function test_updateGovernance() public { | ||
vm.startPrank(MESSAGE_QUEUE); | ||
|
||
assertEq(updater.getGovernance(), GOVERNANCE); | ||
|
||
updater.processVaraMessage( | ||
GOVERNANCE, | ||
abi.encodePacked(uint8(2), NEW_GOVERNANCE) | ||
); | ||
|
||
assertEq(updater.getGovernance(), NEW_GOVERNANCE); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters