Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
60 changes: 60 additions & 0 deletions contracts/FeeVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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;

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 {}
}
4 changes: 4 additions & 0 deletions test/FeeVaultTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// TODO