Skip to content

Update Base Contracts & Add Dictionary Deployment Types #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
May 21, 2024
Merged
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
8 changes: 1 addition & 7 deletions devkit/MCScript.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {System} from "devkit/system/System.sol";

// 💬 ABOUT
// Meta Contract's default Script based on Forge Std Script

// 📦 BOILERPLATE
import {MCScriptBase} from "./MCBase.sol";

// ⭐️ MC SCRIPT
abstract contract MCScript is MCScriptBase {
constructor() {
if (System.Config().SETUP.STD_FUNCS) mc.setupStdFunctions();
}
}
abstract contract MCScript is MCScriptBase {}
20 changes: 6 additions & 14 deletions devkit/MCTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,28 @@ import {System} from "devkit/system/System.sol";
import {Receive} from "mc-std/functions/Receive.sol";
import {Formatter} from "devkit/types/Formatter.sol";
import {ProxyUtils} from "@ucs.mc/proxy/ProxyUtils.sol";
import {Dummy} from "test/utils/Dummy.sol";
import {Dummy} from "devkit/test/dummy/Dummy.sol";

// 💬 ABOUT
// Meta Contract's default Test based on Forge Std Test

// 📦 BOILERPLATE
import {MCTestBase} from "./MCBase.sol";

// ⭐️ MC TEST
abstract contract MCTest is MCTestBase {
constructor() {
if (System.Config().SETUP.STD_FUNCS) mc.setupStdFunctions();
}
struct Function {
bytes4 selector;
address implementation;
}

// 🌟 MC State Fuzzing Test
abstract contract MCStateFuzzingTest is MCTestBase, OZProxy { // solhint-disable-line payable-fallback
struct Function {
bytes4 selector;
address implementation;
}

abstract contract MCTest is MCTestBase, OZProxy { // solhint-disable-line payable-fallback
mapping(bytes4 selector => address) implementations;
address target = address(this);
Function[] internal functions;
address dictionary;

constructor() {
// System.Config().load();
implementations[bytes4(0)] = address(new Receive());
_use(bytes4(0), address(new Receive()));
}

function _use(bytes4 selector_, address impl_) internal {
Expand Down
38 changes: 35 additions & 3 deletions devkit/core/Dictionary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import {Validator} from "devkit/system/Validator.sol";
import {ForgeHelper} from "devkit/utils/ForgeHelper.sol";

// External Libs
import {IDictionary} from "@ucs.mc/dictionary/IDictionary.sol";
import {IDictionary} from "@ucs.mc/dictionary/interfaces/IDictionary.sol";
import {Dictionary as UCSDictionary} from "@ucs.mc/dictionary/Dictionary.sol";
import {ImmutableDictionary, Function as Func} from "@ucs.mc/dictionary/ImmutableDictionary.sol";
import {BeaconDictionary} from "@ucs.mc/dictionary/BeaconDictionary.sol";
// Mock
import {MockDictionary} from "devkit/mocks/MockDictionary.sol";
import {MockDictionary} from "devkit/test/mocks/MockDictionary.sol";

// Core Types
import {Function} from "devkit/core/Function.sol";
Expand Down Expand Up @@ -60,6 +62,9 @@ library DictionaryLib {

/**-------------------------
🚀 Deploy Dictionary
- Verifiable
- Immutable
- Beacon
---------------------------*/
function deploy(address owner) internal returns(Dictionary memory dictionary) {
uint pid = dictionary.startProcess("deploy", param(owner));
Expand All @@ -71,6 +76,31 @@ library DictionaryLib {
return dictionary.finishProcess(pid);
}

function deployImmutable(Function[] storage functions, address facade) internal returns(Dictionary memory dictionary) {
uint pid = dictionary.startProcess("deployImmutable", param(functions, facade));
Validator.SHOULD_FacadeIsContract(facade);
dictionary.startBuilding();
Func[] memory funcs;
for (uint i; i < functions.length; ++i) {
funcs[i] = Func(functions[i].selector, functions[i].implementation);
}
dictionary.addr = address(new ImmutableDictionary(funcs, facade));
dictionary.kind = DictionaryKind.Immutable;
dictionary.finishBuilding();
return dictionary.finishProcess(pid);
}

function deployBeacon(address implementation, address owner) internal returns(Dictionary memory dictionary) {
uint pid = dictionary.startProcess("deployBeacon", param(implementation, owner));
Validator.MUST_AddressIsContract(implementation);
Validator.SHOULD_OwnerIsNotZeroAddress(owner);
dictionary.startBuilding();
dictionary.addr = address(new BeaconDictionary(implementation, owner));
dictionary.kind = DictionaryKind.Beacon;
dictionary.finishBuilding();
return dictionary.finishProcess(pid);
}

/**-----------------------
📩 Load Dictionary
-------------------------*/
Expand Down Expand Up @@ -114,7 +144,7 @@ library DictionaryLib {
function set(Dictionary memory dictionary, bytes4 selector, address implementation) internal returns(Dictionary memory) {
uint pid = dictionary.startProcess("set", param(selector, implementation));
Validator.MUST_Completed(dictionary);
Validator.MUST_NotEmptySelector(selector);
Validator.SHOULD_NotEmptySelector(selector);
Validator.MUST_AddressIsContract(implementation);
IDictionary(dictionary.addr).setImplementation({
functionSelector: selector,
Expand Down Expand Up @@ -177,6 +207,8 @@ library DictionaryLib {
enum DictionaryKind {
undefined,
Verifiable,
Immutable,
Beacon,
Mock
}
using Inspector for DictionaryKind global;
2 changes: 1 addition & 1 deletion devkit/core/Proxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {Validator} from "devkit/system/Validator.sol";
// External Lib Contract
import {Proxy as UCSProxy} from "@ucs.mc/proxy/Proxy.sol";
// Mock Contract
import {SimpleMockProxy} from "devkit/mocks/SimpleMockProxy.sol";
import {SimpleMockProxy} from "devkit/test/mocks/SimpleMockProxy.sol";

// Core Types
import {Dictionary} from "devkit/core/Dictionary.sol";
Expand Down
3 changes: 3 additions & 0 deletions devkit/system/Tracer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ function param(Function[] memory functions) pure returns(string memory res) {
res = res.comma(functions[i].name);
}
}
function param(Function[] memory functions, address facade) pure returns(string memory res) {
return param(functions).comma(facade);
}

function param(Bundle memory bundle) pure returns(string memory) {
return bundle.name;
Expand Down
8 changes: 5 additions & 3 deletions devkit/system/Validator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,15 @@ library Validator {
function MUST_NotEmptyEnvKey(string memory envKey) internal view {
validate(MUST, envKey.isNotEmpty(), HEAD.ENV_KEY_REQUIRED, BODY.ENV_KEY_REQUIRED);
}
function MUST_NotEmptySelector(bytes4 selector) internal view {
validate(MUST, selector.isNotEmpty(), HEAD.SELECTOR_REQUIRED, BODY.SELECTOR_REQUIRED);
function SHOULD_NotEmptySelector(bytes4 selector) internal view {
validate(SHOULD, selector.isNotEmpty(), HEAD.SELECTOR_RECOMMENDED, BODY.SELECTOR_RECOMMENDED);
}
function MUST_AddressIsContract(address addr) internal view {
validate(MUST, addr.isContract(), HEAD.ADDRESS_NOT_CONTRACT, BODY.ADDRESS_NOT_CONTRACT);
}
function SHOULD_FacadeIsContract(address facade) internal view {
validate(SHOULD, facade.isContract(), HEAD.FACADE_NOT_CONTRACT, BODY.FACADE_NOT_CONTRACT);
}
function SHOULD_OwnerIsNotZeroAddress(address owner) internal view {
validate(MUST, owner.isNotZero(), HEAD.OWNER_ZERO_ADDRESS_RECOMMENDED, BODY.OWNER_ZERO_ADDRESS_RECOMMENDED);
}
Expand All @@ -96,7 +99,6 @@ library Validator {
function ValidateBuilder(Function storage func) internal view returns(bool) {
return (
validate(COMPLETION, func.name.isAssigned(), HEAD.FUNC_NAME_UNASSIGNED, BODY.FUNC_NAME_UNASSIGNED) &&
validate(COMPLETION, func.selector.isAssigned(), HEAD.FUNC_SELECTOR_UNASSIGNED, BODY.FUNC_SELECTOR_UNASSIGNED) &&
validate(COMPLETION, func.implementation.isContract(), HEAD.FUNC_CONTRACT_UNASSIGNED, BODY.FUNC_CONTRACT_UNASSIGNED)
);
}
Expand Down
4 changes: 2 additions & 2 deletions devkit/system/message/MessageBody.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ library MessageBody {
// Primitives
string constant NAME_REQUIRED = "The provided name cannot be an empty string. Please enter a non-empty value for the name and try again.";
string constant ENV_KEY_REQUIRED = "The provided environment key cannot be an empty string. Please enter a non-empty value for the key and try again.";
string constant SELECTOR_REQUIRED = "The provided function selector cannot be empty (0x00000000). Please provide a non-empty 4-byte selector value and try again.";
string constant SELECTOR_RECOMMENDED = "The provided function selector is empty (0x00000000). It is recommended to use a non-empty selector.";
string constant ADDRESS_NOT_CONTRACT = "The provided address is not a contract address. Please provide the address of a deployed contract and try again.";
string constant FACADE_NOT_CONTRACT = "The provided facade address is not a contract address. It is recommended to use the address of a deployed facade contract and try again.";
string constant OWNER_ZERO_ADDRESS_RECOMMENDED = "The provided owner address is the zero address (0x0). It is recommended to use a non-zero address for the owner to ensure proper access control and security.";
// Current Context
string constant CURRENT_NAME_NOT_FOUND = "Current Name Not Found";
// Function
string constant FUNC_NAME_UNASSIGNED = "The function name is currently unassigned. It is recommended to provide a non-empty value for the name.";
string constant FUNC_SELECTOR_UNASSIGNED = "The 4-byte function selector is currently unassigned. It is recommended to provide a non-zero value for the selector.";
string constant FUNC_CONTRACT_UNASSIGNED = "The implementation contract address is currently unassigned. It is recommended to set the address of a deployed contract.";
string constant FUNC_NOT_COMPLETE = "The function is not marked as complete. Please ensure all requirements are met before proceeding.";
string constant FUNC_LOCKED = "The function object is currently locked and cannot be modified.";
Expand Down
4 changes: 2 additions & 2 deletions devkit/system/message/MessageHead.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ library MessageHead {
// Primitives
string constant NAME_REQUIRED = "Name Required";
string constant ENV_KEY_REQUIRED = "EnvKey Required";
string constant SELECTOR_REQUIRED = "Selector Required";
string constant SELECTOR_RECOMMENDED = "Empty Selector";
string constant ADDRESS_NOT_CONTRACT = "Address Not Contract";
string constant FACADE_NOT_CONTRACT = "Facade Not Contract";
string constant OWNER_ZERO_ADDRESS_RECOMMENDED = "Owner Zero Address";
// Current Context
string constant CURRENT_NAME_NOT_FOUND = "Current Name Not Found";
// Function
string constant FUNC_NAME_UNASSIGNED = "Function Name Unassigned";
string constant FUNC_SELECTOR_UNASSIGNED = "Function Selector Unassigned";
string constant FUNC_CONTRACT_UNASSIGNED = "Implementation Contract Unassigned";
string constant FUNC_NOT_COMPLETE = "Function Not Complete";
string constant FUNC_LOCKED = "Function Locked";
Expand Down
22 changes: 19 additions & 3 deletions test/utils/Dummy.sol → devkit/test/dummy/Dummy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,26 @@ pragma solidity ^0.8.24;
import {MCDevKit} from "devkit/MCDevKit.sol";
import {DummyFunction} from "./DummyFunction.sol";
import {DummyFacade} from "./DummyFacade.sol";
import {DummyContract} from "test/utils/DummyContract.sol";
import {MCStateFuzzingTest} from "devkit/MCTest.sol";
import {DummyContract} from "devkit/test/dummy/DummyContract.sol";
import {Function} from "devkit/MCTest.sol";

library Dummy {
function bundleName() internal returns(string memory) {
return "DummyBundleName";
}

function functionSelector() internal returns(bytes4) {
return DummyFunction.dummy.selector;
}

function functionAddress() internal returns(address) {
return address(new DummyFunction());
}

function facadeAddress() internal returns(address) {
return address(new DummyFacade());
}

function setBundle(MCDevKit storage mc) internal {
mc.init("DummyBundle");
mc.use(DummyFunction.dummy.selector, address(new DummyFunction()));
Expand All @@ -19,7 +35,7 @@ library Dummy {
return mc.createMockDictionary().addr;
}

function dictionary(MCDevKit storage mc, MCStateFuzzingTest.Function[] memory functions) internal returns(address) {
function dictionary(MCDevKit storage mc, Function[] memory functions) internal returns(address) {
mc.init("DummyBundle");
for (uint i; i < functions.length; ++i) {
mc.use(functions[i].selector, functions[i].implementation);
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {Dictionary} from "@ucs.mc/dictionary/Dictionary.sol";
contract MockDictionary is Dictionary {
constructor (address owner, Function[] memory functions) Dictionary(owner) {
for (uint i; i < functions.length; ++i) {
setImplementation(functions[i].selector, functions[i].implementation);
_setImplementation(functions[i].selector, functions[i].implementation);
}
}
}
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion devkit/types/Inspector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {Inspector} from "devkit/types/Inspector.sol";
import {TypeStatus} from "devkit/types/TypeGuard.sol";
import {ForgeHelper} from "devkit/utils/ForgeHelper.sol";
// External Library
import {IDictionary} from "@ucs.mc/dictionary/IDictionary.sol";
import {IDictionary} from "@ucs.mc/dictionary/interfaces/IDictionary.sol";
import {IBeacon as IVerifiable} from "@oz.mc/proxy/beacon/IBeacon.sol";
// Core Types
import {Function} from "devkit/core/Function.sol";
Expand Down
5 changes: 5 additions & 0 deletions devkit/utils/global/MCDeployLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {NameGenerator} from "devkit/utils/mapping/NameGenerator.sol";
/************************************
* 🚀 Deployment
* 🌞 Deploy Meta Contract
* - Deploy
* - DeployImmutable
* - DeployRestrictedUpgradeable
* - DeployContractUpgradeable
* 🏠 Deploy Proxy
* 📚 Deploy Dictionary
* 🔂 Duplicate Dictionary
Expand Down Expand Up @@ -168,6 +172,7 @@ library MCDeployLib {
mc.finishProcess(pid);
}


/**------------------------
💽 Load Dictionary
--------------------------*/
Expand Down
16 changes: 9 additions & 7 deletions devkit/utils/global/MCHelpers.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

// Forge-std
import {Vm, VmSafe} from "forge-std/Vm.sol";
// Constants
/// @dev address(uint160(uint256(keccak256("hevm cheat code"))));
Vm constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

import {ProxyUtils} from "@ucs.mc/proxy/ProxyUtils.sol";

import {Logger} from "devkit/system/Logger.sol";
Expand All @@ -18,7 +12,7 @@ import {MCDevKit} from "devkit/MCDevKit.sol";
import {System} from "devkit/system/System.sol";
// Utils
import {param} from "devkit/system/Tracer.sol";
import {ForgeHelper} from "devkit/utils/ForgeHelper.sol";
import {ForgeHelper, vm} from "devkit/utils/ForgeHelper.sol";
// Core
// functions
import {Bundle} from "devkit/core/Bundle.sol";
Expand Down Expand Up @@ -131,4 +125,12 @@ library MCHelpers {
function resumeBroadcast(MCDevKit storage, bool isBroadcasting, address currentSender) internal {
ForgeHelper.resumeBroadcast(isBroadcasting, currentSender);
}


/**----------------------
🛠️ Forge Extender
------------------------*/
function expectRevert(MCDevKit storage, string memory message) internal {
vm.expectRevert(bytes(message));
}
}
6 changes: 3 additions & 3 deletions devkit/utils/global/MCInitLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ library MCInitLib {
uint pid = mc.startProcess("use", param(name, selector, implementation));
// Register new function
Validator.MUST_NotEmptyName(name);
Validator.MUST_NotEmptySelector(selector);
Validator.SHOULD_NotEmptySelector(selector);
Validator.MUST_AddressIsContract(implementation);
mc.functions.register(name, selector, implementation);
// Push to current bundle
Expand All @@ -54,8 +54,8 @@ library MCInitLib {
function use(MCDevKit storage mc, bytes4 selector, address implementation) internal returns(MCDevKit storage) {
return use(mc, ForgeHelper.getLabel(implementation), selector, implementation);
}
function use(MCDevKit storage mc, Function storage functionInfo) internal returns(MCDevKit storage) {
return use(mc, functionInfo.name, functionInfo.selector, functionInfo.implementation);
function use(MCDevKit storage mc, Function storage func) internal returns(MCDevKit storage) {
return use(mc, func.name, func.selector, func.implementation);
}
function use(MCDevKit storage mc, string memory functionName) internal returns(MCDevKit storage) {
return use(mc, mc.functions.find(functionName));
Expand Down
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ libs = ["lib"]
optimizer = false
fs_permissions = [{ access = "read", path = "./mc.toml" }, { access = "read", path = "./lib/mc/mc.toml" }]

evm_version = "cancun"

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
2 changes: 1 addition & 1 deletion lib/forge-std
11 changes: 11 additions & 0 deletions script/DeployLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@
pragma solidity ^0.8.24;

import {MCDevKit} from "devkit/MCDevKit.sol";
import {StdFacade} from "mc-std/interfaces/StdFacade.sol";
import {InitSetAdmin} from "mc-std/functions/protected/InitSetAdmin.sol";

library DeployLib {
using DeployLib for MCDevKit;
string internal constant BUNDLE_NAME = "Std";

function deployStd(MCDevKit storage mc, address admin) internal returns(address) {
for (uint i; i < mc.std.all.functions.length; ++i) {
mc.use(mc.std.all.functions[i]);
}
mc.useFacade(address(new StdFacade()));
bytes memory initData = abi.encodeCall(InitSetAdmin.initSetAdmin, admin);
return mc.deploy(initData).toProxyAddress();
}

function deployStdFunctions(MCDevKit storage mc) internal returns(MCDevKit storage) {
mc.std.functions.deployIfNotExists();
return mc;
Expand Down
2 changes: 1 addition & 1 deletion src/std/functions/GetFunctions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.22;

import {ProxyUtils} from "@ucs.mc/proxy/ProxyUtils.sol";
import {IDictionary} from "@ucs.mc/dictionary/IDictionary.sol";
import {IDictionary} from "@ucs.mc/dictionary/interfaces/IDictionary.sol";

/** < MC Standard Function >
* @title GetFunctions
Expand Down
Loading
Loading