From 3b2313847fdcc85f442129c2540555512820f35d Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:49:01 -0800 Subject: [PATCH 1/3] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 564c83a..477128d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,14 @@ To enable bridging to native ether, bridging contracts need be able to mint/burn - `mint`: allows whitelisted addresses to mint specific amount of native ether to any account. - `burn`: allows whitelisted addresses to burn specific amount of native ether from any account. +### Fee Vault + +The mev-commit chain implements a fee mechanism where all base fees accumulate to a "fee vault" contract. The predetermined address for such a contract is hardcoded into mev-commit-geth. + +The fee vault contract is initiated with an immutable treasury address. The contract owner can invoke transfers of the accumulated fees from the sidechain contract, to the treasury address on L1, including bridging. + +Since the treasury address is immutable, the contract owner only has the power to initiate transfers. The separation between the owner account and treasury account is useful in that key management can be separate. Ie. a secure multisig governing the protocol treasury doesn't need to submit regular transfer transactions. + ## Tests The tests in this repository perform the following: @@ -186,6 +194,7 @@ ProviderRegistry deployed to: 0xBdd9CEd825167c0D616B0284BfACD034fF02D41D PreConfCommitmentStore deployed to: 0xFF435EC71C7cB6fEFbFfA8B1275c08c7e121E9Aa Oracle deployed to: 0xC68573B65444c21A4D9cE88B92DFEA222956B4E5 Whitelist deployed to: 0xC2009B1b9036db2931349F2242eDA081FEc43D91 +Fee Vault deployed to: TODO ``` #### Test Contracts From 81bd4084754029924a6caf130c212f8af8ca41fd Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:32:13 -0800 Subject: [PATCH 2/3] contract init --- contracts/FeeVault.sol | 67 ++++++++++++++++++++++++++++++++++++++++++ test/FeeVaultTest.sol | 4 +++ 2 files changed, 71 insertions(+) create mode 100644 contracts/FeeVault.sol create mode 100644 test/FeeVaultTest.sol diff --git a/contracts/FeeVault.sol b/contracts/FeeVault.sol new file mode 100644 index 0000000..81f2119 --- /dev/null +++ b/contracts/FeeVault.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSL 1.1 +pragma solidity ^0.8.15; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +// See hyperlane token router: https://github.com/primevprotocol/hyperlane-monorepo/blob/1c8cdc9e57389024274242d28e032a2de535c2c7/solidity/contracts/token/libs/TokenRouter.sol +interface ITokenRouter { + function transferRemote(uint32 _destination, bytes32 _recipient, uint256 _amountOrId) external payable returns (bytes32); +} + +// TODO: Make this it's own file, hyperlane should ref it too +interface IWhitelist { + function mint(address _mintTo, uint256 _amount) external; + function burn(address _burnFrom, uint256 _amount) external; +} + +contract FeeVault is Ownable { + address public immutable treasury; + uint256 public immutable destinationChainId; + ITokenRouter private tokenRouter; + + // Example operational addresses + // These are addresses funded on genesis that use "operational ether" to deploy + // contracts, etc. + address private operationalAddress1 = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + address private operationalAddress2 = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address private operationalAddress3 = 0x4E6564574f4C61241bf8db2B91f74705d3Aaf452; + + constructor(address _treasury, address _tokenRouterAddr, uint256 _destinationChainId) { + require(_treasury != address(0), "Treasury address cannot be zero"); + treasury = _treasury; + require(_tokenRouterAddr != address(0), "TokenRouter address cannot be zero"); + tokenRouter = ITokenRouter(_tokenRouterAddr); + require(_destinationChainId != 0, "Destination chain ID cannot be zero"); + destinationChainId = _destinationChainId; + + // Note the fee vault contract needs to burn funds accumulated from "operational + // accounts" funded on genesis, who submit chain initialization transactions. + // This pre-setup ether does not have corresponding liquidity on the L1 hyperlane contract. + // + // TODO: Address following concerns: + // - Confirm idea works + // - Confirm we can avoid accounting logic altogether? + // - Possibly burn account balances of all hardcoded operational accounts in this constructor? + // - What about burning signer balances? + // - Will most likely need ether buffer deposited into L1 contract equal to cumulative fees needed for sidechain setup + uint256 initialBalance = address(this).balance; + if (initialBalance > 0) { + whitelist.burn(address(this), initialBalance); + emit AmountBurned(initialBalance); + } + } + + function transferToL1() external onlyOwner { + uint256 balance = address(this).balance; + require(balance > 0, "No funds to transfer"); + + // Convert the treasury address to bytes32 for transferRemote call + // TODO: Confirm how this is done in hyperlane repo + bytes32 recipient = bytes32(uint256(uint160(treasury))); + + tokenRouter.transferRemote{value: balance}(destinationChainId, recipient, balance); + } + + // Allows contract to receive ether accumulated before deployment + receive() external payable {} +} diff --git a/test/FeeVaultTest.sol b/test/FeeVaultTest.sol new file mode 100644 index 0000000..3efedf1 --- /dev/null +++ b/test/FeeVaultTest.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +// TODO From e6dcf10859ceba1e3fcdbc27e1a2e522d0a0cfad Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:36:51 -0800 Subject: [PATCH 3/3] Update FeeVault.sol --- contracts/FeeVault.sol | 7 ------- 1 file changed, 7 deletions(-) diff --git a/contracts/FeeVault.sol b/contracts/FeeVault.sol index 81f2119..1bb1703 100644 --- a/contracts/FeeVault.sol +++ b/contracts/FeeVault.sol @@ -19,13 +19,6 @@ contract FeeVault is Ownable { uint256 public immutable destinationChainId; ITokenRouter private tokenRouter; - // Example operational addresses - // These are addresses funded on genesis that use "operational ether" to deploy - // contracts, etc. - address private operationalAddress1 = 0xdAC17F958D2ee523a2206206994597C13D831ec7; - address private operationalAddress2 = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - address private operationalAddress3 = 0x4E6564574f4C61241bf8db2B91f74705d3Aaf452; - constructor(address _treasury, address _tokenRouterAddr, uint256 _destinationChainId) { require(_treasury != address(0), "Treasury address cannot be zero"); treasury = _treasury;