Skip to content

Commit

Permalink
Merge pull request #58 from primevprotocol/whitelist-contract
Browse files Browse the repository at this point in the history
Whitelist contract
  • Loading branch information
shaspitz authored Dec 14, 2023
2 parents 17677df + 4985213 commit 22b54ff
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 2 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,20 @@ This is an interface that must be implemented by the provider registry contract.

Note: In both IProviderRegistry and IUserRegistry - some functions are restrictied to be called exclusively by the preconfimration contract.

## Whitelist

To enable bridging to native ether, bridging contracts need be able to mint/burn native ether. The `Whitelist` is responsible for managing a whitelist of addresses that can mint/burn native ether. An admin account must be specified on deployment, who is the only address that can mutate the whitelist.

## Tests

The tests in this repository perform the following:

- Deployment of the `ProviderRegistry` and `UserRegistry` contracts.
- Deployment of the `ProviderRegistry`, `UserRegistry`, and `Whitelist` contracts.
- Registration and staking of users and providers.
- Verification of bid hashes and pre-confirmation commitment hashes.
- Recovery of signer addresses.
- Storage of valid commitments.
- Tests basic whitelisting functionality.

To run the tests, use the following command:

Expand Down Expand Up @@ -147,12 +152,17 @@ export PRIVATE_KEY="your-private-key"
export CHAIN_ID=17864
```

- Run the deploy script
- Run the deploy script for core conracts

```
forge script scripts/DeployScripts.s.sol:DeployScript --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --chain-id $CHAIN_ID -vvvv
```

- Run deploy script for whitelist contract, HYP_ERC20_ADDR denotes the HypERC20.sol contract address to give native mint/burn privileges.

```
HYP_ERC20_ADDR=0xBe3dEF3973584FdcC1326634aF188f0d9772D57D forge script scripts/DeployScripts.s.sol:DeployWhitelist --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --chain-id $CHAIN_ID -vvvv
```

#### Test Contracts

Expand Down
58 changes: 58 additions & 0 deletions contracts/Whitelist.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: BSL 1.1
pragma solidity ^0.8.15;

// Contract that allows an admin to add/remove addresses from the whitelist,
// and allows whitelisted addresses to mint/burn native tokens.
contract Whitelist {
address public admin;
mapping(address => bool) public whitelistedAddresses;

// Mint/burn precompile addresses.
// See: https://github.com/primevprotocol/go-ethereum/blob/03ae168c6ac15dda8c5a3f123e2b9f3350aad613/core/vm/contracts.go
address constant MINT = address(0x89);
address constant BURN = address(0x90);

constructor(address _admin) {
require(_admin != address(0), "Admin address cannot be zero");
admin = _admin;
}

modifier onlyAdmin() {
require(msg.sender == admin, "Only admin can call this function");
_;
}

function addToWhitelist(address _address) external onlyAdmin {
whitelistedAddresses[_address] = true;
}

function removeFromWhitelist(address _address) external onlyAdmin {
whitelistedAddresses[_address] = false;
}

function isWhitelisted(address _address) public view returns (bool) {
return whitelistedAddresses[_address];
}

// Mints native tokens if the sender is whitelisted.
// See: https://github.com/primevprotocol/go-ethereum/blob/precompile-updates/core/vm/contracts_with_ctx.go#L83
function mint(address _mintTo, uint256 _amount) external {
require(isWhitelisted(msg.sender), "Sender is not whitelisted");
bool success;
(success, ) = MINT.call{value: 0, gas: gasleft()}(
abi.encode(_mintTo, _amount)
);
require(success, "Native mint failed");
}

// Burns native tokens if the sender is whitelisted.
// See: https://github.com/primevprotocol/go-ethereum/blob/precompile-updates/core/vm/contracts_with_ctx.go#L111
function burn(address _burnFrom, uint256 _amount) external {
require(isWhitelisted(msg.sender), "Sender is not whitelisted");
bool success;
(success, ) = BURN.call{value: 0, gas: gasleft()}(
abi.encode(_burnFrom, _amount)
);
require(success, "Native burn failed");
}
}
35 changes: 35 additions & 0 deletions scripts/DeployScripts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import "contracts/UserRegistry.sol";
import "contracts/ProviderRegistry.sol";
import "contracts/PreConfirmations.sol";
import "contracts/Oracle.sol";
import "contracts/Whitelist.sol";

// Deploys core contracts
contract DeployScript is Script {
function run() external {
vm.startBroadcast();
Expand Down Expand Up @@ -40,3 +42,36 @@ contract DeployScript is Script {
vm.stopBroadcast();
}
}

// Deploys whitelist contract and adds HypERC20 to whitelist
contract DeployWhitelist is Script {
function run() external {
vm.startBroadcast();

address create2Proxy = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
require(isContractDeployed(create2Proxy), "Create2 proxy needs to be deployed. See https://github.com/primevprotocol/deterministic-deployment-proxy");

address hypERC20Addr = vm.envAddress("HYP_ERC20_ADDR");
require(hypERC20Addr != address(0), "Whitelist address not provided");

// Forge deploy with salt uses create2 proxy from https://github.com/primevprotocol/deterministic-deployment-proxy
bytes32 salt = 0x8989000000000000000000000000000000000000000000000000000000000000;
address constDeployer = 0xBe3dEF3973584FdcC1326634aF188f0d9772D57D;
Whitelist whitelist = new Whitelist{salt: salt}(constDeployer);
console.log("Whitelist deployed to:", address(whitelist));
console.log("Expected: 0xe57ee51bcb0914EC666703F923e0433d8c4d70b1");

whitelist.addToWhitelist(address(hypERC20Addr));
console.log("Whitelist updated with hypERC20 address:", address(hypERC20Addr));

vm.stopBroadcast();
}

function isContractDeployed(address addr) public view returns (bool) {
uint size;
assembly {
size := extcodesize(addr)
}
return size > 0;
}
}
59 changes: 59 additions & 0 deletions test/WhitelistTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: BSL 1.1
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../contracts/Whitelist.sol";

// Tests the Whitelist contract.
// Note precompile interactions to mint/burn must be tested manually.
contract WhitelistTest is Test {

address admin;
address normalUser;
address addressInstance;
Whitelist whitelist;

function setUp() public {
admin = address(this); // Original contract deployer as admin
normalUser = address(0x100);
addressInstance = address(0x200);
whitelist = new Whitelist(admin);
}

function test_IsWhitelisted() public {
assertFalse(whitelist.isWhitelisted(addressInstance));
vm.prank(admin);
whitelist.addToWhitelist(addressInstance);
assertTrue(whitelist.isWhitelisted(addressInstance));
}

function test_AdminAddToWhitelist() public {
vm.prank(admin);
whitelist.addToWhitelist(addressInstance);
assertTrue(whitelist.isWhitelisted(addressInstance));
}

function test_AdminRemoveFromWhitelist() public {
vm.prank(admin);
whitelist.addToWhitelist(addressInstance);
assertTrue(whitelist.isWhitelisted(addressInstance));
vm.prank(admin);
whitelist.removeFromWhitelist(addressInstance);
assertFalse(whitelist.isWhitelisted(addressInstance));
}

function test_RevertNormalUserAddToWhitelist() public {
vm.prank(normalUser);
vm.expectRevert("Only admin can call this function");
whitelist.addToWhitelist(addressInstance);
}

function test_RevertNormalUserRemoveFromWhitelist() public {
vm.prank(admin);
whitelist.addToWhitelist(addressInstance);
assertTrue(whitelist.isWhitelisted(addressInstance));
vm.prank(normalUser);
vm.expectRevert("Only admin can call this function");
whitelist.removeFromWhitelist(addressInstance);
}
}

0 comments on commit 22b54ff

Please sign in to comment.