Skip to content

Commit d58de7e

Browse files
committed
add main contracts
1 parent f28d5c0 commit d58de7e

File tree

19 files changed

+1175
-8
lines changed

19 files changed

+1175
-8
lines changed

script/Deploy.sol

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// script/DeployDiamond.s.sol
2+
pragma solidity ^0.8.0;
3+
4+
import {Script, console2} from "forge-std/Script.sol";
5+
import {IDiamondCut} from "../src/interfaces/IDiamondCut.sol";
6+
7+
// 1. Manually import all required contracts/facets
8+
import {Registry} from "../src/registry/Registry.sol";
9+
import {Diamond} from "../src/Diamond/Diamond.sol";
10+
import {DiamondCutFacet} from "../src/facets/Diamond/DiamondCutFacet.sol";
11+
import {DiamondLoupeFacet} from "../src/facets/Diamond/DiamondLoupeFacet.sol";
12+
import {OwnershipFacet} from "../src/facets/Ownership/OwnershipFacet.sol";
13+
import {ERC20Facet} from "../src/facets/ERC20/ERC20Facet.sol";
14+
15+
contract DeployDiamondScript is Script {
16+
// Define the contract owner/governance
17+
address public constant OWNER = address(0xBEEF);// Replace with your desired owner address
18+
19+
function run() external {
20+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
21+
// vm.startBroadcast() is called with the private key to sign and submit transactions
22+
vm.startBroadcast(deployerPrivateKey);
23+
24+
// --- 1. Deploy Facets and Registry ---
25+
console2.log("1. Deploying Facets and Registry...");
26+
DiamondCutFacet cutFacet = new DiamondCutFacet();
27+
DiamondLoupeFacet loupeFacet = new DiamondLoupeFacet();
28+
OwnershipFacet ownershipFacet = new OwnershipFacet();
29+
ERC20Facet erc20Facet = new ERC20Facet();
30+
Registry registry = new Registry();
31+
32+
console2.log("Registry Address:", address(registry));
33+
34+
// --- 2. Deploy the Diamond Proxy ---
35+
console2.log("2. Deploying Diamond Proxy...");
36+
Diamond diamond = new Diamond();
37+
address diamondAddress = address(diamond);
38+
console2.log("Diamond Address:", diamondAddress);
39+
40+
// --- 3. Construct the DiamondCut array (The 'Add' operation) ---
41+
IDiamondCut.FacetCut[] memory cuts = new IDiamondCut.FacetCut[](4);
42+
43+
cuts[0] = buildCut(address(cutFacet));
44+
cuts[1] = buildCut(address(loupeFacet));
45+
cuts[2] = buildCut(address(ownershipFacet));
46+
cuts[3] = buildCut(address(erc20Facet));
47+
48+
// --- 4. Execute the Initial DiamondCut ---
49+
console2.log("4. Executing initial DiamondCut...");
50+
IDiamondCut diamondCut = IDiamondCut(diamondAddress);
51+
52+
// Execute the cut to link all facets to the Diamond proxy
53+
diamondCut.diamondCut(
54+
cuts,
55+
address(0), // _init: Address of initializer contract (0x0 since we use an immediate cut)
56+
"" // _calldata: Calldata for the initializer function
57+
);
58+
59+
// --- 5. Optional: Initialize/Configure ---
60+
// Call the OwnershipFacet function on the Diamond address to set the final owner
61+
OwnershipFacet(diamondAddress).transferOwnership(OWNER);
62+
63+
// Register the Diamond itself in the registry for tracking
64+
registry.register("Diamond_V1", diamondAddress, 1);
65+
66+
console2.log("Deployment and initial DiamondCut completed.");
67+
68+
// vm.stopBroadcast() tells Foundry to stop recording transactions
69+
vm.stopBroadcast();
70+
}
71+
72+
// --- Helper Function using vm.parseSelectors ---
73+
function buildCut(address _facetAddress)
74+
internal
75+
view // Changed to view since we are using vm.parseSelectors which is off-chain
76+
returns (IDiamondCut.FacetCut memory)
77+
{
78+
// vm.parseSelectors reads the bytecode of the contract at _facetAddress
79+
// and returns all exposed function signatures (bytes[]).
80+
bytes[] memory sigs = vm.parseSelectors(_facetAddress);
81+
bytes4[] memory selectors = new bytes4[](sigs.length);
82+
83+
for (uint256 i = 0; i < sigs.length; i++) {
84+
// Convert the full signature bytes to the 4-byte selector
85+
selectors[i] = bytes4(sigs[i]);
86+
}
87+
88+
return IDiamondCut.FacetCut({
89+
facetAddress: _facetAddress,
90+
action: IDiamondCut.FacetCutAction.Add,
91+
functionSelectors: selectors
92+
});
93+
}
94+
}

src/Diamond.sol

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
/******************************************************************************\
5+
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
6+
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
7+
*
8+
* Implementation of a diamond.
9+
/******************************************************************************/
10+
11+
import {LibDiamond} from "./facets/Diamond/LibDiamond.sol";
12+
import {IDiamondCut} from "./facets/Diamond/IDiamondCut.sol";
13+
14+
import {LibOwnership} from "./facets/Ownership/LibOwnership.sol";
15+
import {iOwnership} from "./facets/Ownership/_Ownership.sol";
16+
17+
contract Diamond is iOwnership {
18+
constructor(address _owner, address _registry, IDiamondCut.FacetCut[] memory _cuts) payable {
19+
LibOwnership._setRegistry(_registry);
20+
LibOwnership._setEcosystemOwner(_owner);
21+
LibDiamond.diamondCut(_cuts, address(0), "");
22+
}
23+
24+
25+
26+
// Find facet for function that is called and execute the
27+
// function if a facet is found and return any value.
28+
fallback() external payable {
29+
LibDiamond.DiamondStorage storage ds;
30+
bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
31+
// get diamond storage
32+
assembly {
33+
ds.slot := position
34+
}
35+
// get facet from function selector
36+
console.logBytes4(msg.sig);
37+
address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
38+
require(facet != address(0), "Diamond: Function does not exist");
39+
// Execute external function from facet using delegatecall and return any value.
40+
assembly {
41+
// copy function selector and any arguments
42+
calldatacopy(0, 0, calldatasize())
43+
// execute function call using the facet
44+
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
45+
// get any return value
46+
returndatacopy(0, 0, returndatasize())
47+
// return any return value or error back to the caller
48+
switch result
49+
case 0 {
50+
revert(0, returndatasize())
51+
}
52+
default {
53+
return(0, returndatasize())
54+
}
55+
}
56+
}
57+
58+
receive() external payable {}
59+
}

src/TokenVault.sol

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ contract TokenVault {
2727
_transferEth(msg.sender, amount); // Uses the optimized internal transfer
2828
}
2929
// In src/TokenVault.sol
30-
function withdrawUnoptimized(uint256 amount) public {
31-
require(balances[msg.sender] >= amount, "Insufficient balance");
32-
balances[msg.sender] -= amount;
33-
totalValue -= amount;
34-
// Less gas-efficient way (e.g., using transfer, which forwards a fixed amount of gas)
35-
// The previous 'withdrawOptimized' uses call, which is typically cheaper for simple transfers
36-
payable(msg.sender).transfer(amount);
30+
function withdrawUnoptimized(uint256 amount) public {
31+
require(balances[msg.sender] >= amount, "Insufficient balance");
32+
balances[msg.sender] -= amount;
33+
totalValue -= amount;
34+
// Less gas-efficient way (e.g., using transfer, which forwards a fixed amount of gas)
35+
// The previous 'withdrawOptimized' uses call, which is typically cheaper for simple transfers
36+
payable(msg.sender).transfer(amount);
37+
}
3738
}
38-
}

src/deploy/IDiamondDeploy.sol

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.9;
3+
import "../facets/Diamond/IDiamondCut.sol";
4+
5+
/// @title DiamondDeploy Interface
6+
/// @notice Interface for the DiamondDeploy contract
7+
/// @dev This interface describes the methods available in the DiamondDeploy contract
8+
interface IDiamondDeploy {
9+
10+
11+
/// @notice Deploy a new Diamond contract
12+
/// @dev Deploys a new Diamond contract and returns its address
13+
/// @param _bytecode The bytecode of the contract to deploy
14+
/// @return diamond_ The address of the newly deployed Diamond
15+
function deploy(address _owner, uint256 _salt, bytes memory _bytecode, IDiamondCut.FacetCut[] memory _facetCuts) external returns (address diamond_);
16+
17+
/// @notice Get the address of the DiamondCutFacet
18+
/// @dev Returns the address of the DiamondCutFacet associated with this DiamondDeploy contract
19+
/// @return The address of the DiamondCutFacet
20+
function diamondCutFacet() external view returns (address);
21+
}
22+

src/deploy/diamondDeploy.sol

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.9;
3+
4+
import "../facets/Diamond/IDiamondCut.sol";
5+
import "./IDiamondDeploy.sol";
6+
import "hardhat/console.sol";
7+
8+
contract DiamondDeploy {
9+
address public registryAddress;
10+
bool isRegistrySet = false;
11+
bytes32 bytecodeHash;
12+
13+
14+
constructor(address registry, bytes memory _bytecode ) {
15+
registryAddress = registry;
16+
bytecodeHash = keccak256(_bytecode);
17+
}
18+
19+
function deploy(address owner, uint256 _salt, bytes calldata _bytecode, IDiamondCut.FacetCut[] memory _facetCuts) external returns (address diamond_) {
20+
console.log(3);
21+
require(msg.sender == registryAddress,"Must be initiated from the MassDX registry.");
22+
console.log(4);
23+
// Initialize a variable to hold the deployed address
24+
address deployedAddress;
25+
26+
require(keccak256(_bytecode) == bytecodeHash, "Bytecode must match that of the Diamond associated with this contract.");
27+
console.log(5);
28+
// ABI encode the constructor parameters
29+
bytes memory encodedParams = abi.encode(owner, msg.sender, _facetCuts);
30+
31+
// Concatenate the pseudoBytecode and encoded constructor parameters
32+
bytes memory finalBytecode = abi.encodePacked(_bytecode, encodedParams);
33+
34+
// Use CREATE2 opcode to deploy the contract with static bytecode
35+
// Generate a unique salt based on msg.sender
36+
bytes32 salt = keccak256(abi.encodePacked(msg.sender, _salt, encodedParams));
37+
console.log(55);
38+
// The following assembly block deploys the contract using CREATE2 opcode
39+
assembly {
40+
deployedAddress := create2(
41+
0, // 0 wei sent with the contract
42+
add(finalBytecode, 32), // skip the first 32 bytes (length)
43+
mload(finalBytecode), // size of bytecode
44+
salt // salt
45+
)
46+
// Check if contract deployment was successful
47+
if iszero(extcodesize(deployedAddress)) {
48+
revert(0, 0)
49+
}
50+
}
51+
console.log(6);
52+
return deployedAddress;
53+
}
54+
55+
56+
}
57+
58+
/**
59+
* We store hash of bytecode.
60+
* Client deploys bytecode.
61+
* Checks hash, deploys.
62+
*/
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
/******************************************************************************\
5+
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
6+
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
7+
/******************************************************************************/
8+
9+
import { IDiamondCut } from "./IDiamondCut.sol";
10+
import { LibDiamond } from "./LibDiamond.sol";
11+
12+
import {iOwnership} from "../Ownership/_Ownership.sol";
13+
14+
// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.
15+
// The loupe functions are required by the EIP2535 Diamonds standard
16+
17+
contract DiamondCutFacet is IDiamondCut, iOwnership {
18+
/// @notice Add/replace/remove any number of functions and optionally execute
19+
/// a function with delegatecall
20+
/// @param _diamondCut Contains the facet addresses and function selectors
21+
/// @param _init The address of the contract or facet to execute _calldata
22+
/// @param _calldata A function call, including function selector and arguments
23+
/// _calldata is executed with delegatecall on _init
24+
function diamondCut(
25+
FacetCut[] calldata _diamondCut,
26+
address _init,
27+
bytes calldata _calldata
28+
) external override {
29+
isEffectiveOwner();
30+
LibDiamond.diamondCut(_diamondCut, _init, _calldata);
31+
}
32+
33+
/**
34+
* @notice Initiate a migration away from the massDX ecosystem versions.
35+
* There is a 3 day minimum required timespan
36+
*/
37+
function initiateMigration() external returns (uint32 expireTime) {
38+
isEcosystemOwnerVerification();
39+
40+
return _initiateMigration();
41+
}
42+
43+
/**
44+
* @notice If an ongoing migration exists and hasn't surpassed the 3 day
45+
* minimum wait time, then the migration will be cancelled.
46+
*/
47+
function cancelMigration() external returns (uint32 expireTime){
48+
isEcosystemOwnerVerification();
49+
50+
return _cancelMigration();
51+
}
52+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
/******************************************************************************\
4+
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
5+
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
6+
/******************************************************************************/
7+
8+
import {LibDiamond} from "./LibDiamond.sol";
9+
import {IDiamondLoupe} from "./IDiamondLoupe.sol";
10+
import {IERC165} from "../../IERC165.sol";
11+
12+
// The functions in DiamondLoupeFacet MUST be added to a diamond.
13+
// The EIP-2535 Diamond standard requires these functions.
14+
15+
contract DiamondLoupeFacet is IDiamondLoupe, IERC165 {
16+
// Diamond Loupe Functions
17+
////////////////////////////////////////////////////////////////////
18+
/// These functions are expected to be called frequently by tools.
19+
//
20+
// struct Facet {
21+
// address facetAddress;
22+
// bytes4[] functionSelectors;
23+
// }
24+
25+
/// @notice Gets all facets and their selectors.
26+
/// @return facets_ Facet
27+
function facets() external view override returns (Facet[] memory facets_) {
28+
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
29+
uint256 numFacets = ds.facetAddresses.length;
30+
facets_ = new Facet[](numFacets);
31+
for (uint256 i; i < numFacets; i++) {
32+
address facetAddress_ = ds.facetAddresses[i];
33+
facets_[i].facetAddress = facetAddress_;
34+
facets_[i].functionSelectors = ds.facetFunctionSelectors[facetAddress_].functionSelectors;
35+
}
36+
}
37+
38+
/// @notice Gets all the function selectors provided by a facet.
39+
/// @param _facet The facet address.
40+
/// @return facetFunctionSelectors_
41+
function facetFunctionSelectors(address _facet) external view override returns (bytes4[] memory facetFunctionSelectors_) {
42+
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
43+
facetFunctionSelectors_ = ds.facetFunctionSelectors[_facet].functionSelectors;
44+
}
45+
46+
/// @notice Get all the facet addresses used by a diamond.
47+
/// @return facetAddresses_
48+
function facetAddresses() external view override returns (address[] memory facetAddresses_) {
49+
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
50+
facetAddresses_ = ds.facetAddresses;
51+
}
52+
53+
/// @notice Gets the facet that supports the given selector.
54+
/// @dev If facet is not found return address(0).
55+
/// @param _functionSelector The function selector.
56+
/// @return facetAddress_ The facet address.
57+
function facetAddress(bytes4 _functionSelector) external view override returns (address facetAddress_) {
58+
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
59+
facetAddress_ = ds.selectorToFacetAndPosition[_functionSelector].facetAddress;
60+
}
61+
62+
// This implements ERC-165.
63+
function supportsInterface(bytes4 _interfaceId) external view override returns (bool) {
64+
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
65+
return ds.supportedInterfaces[_interfaceId];
66+
}
67+
}

0 commit comments

Comments
 (0)