智能合约架构--The Default Framework

在阅读 OlympusV3 的合约时，架构的设计给我留下很深的印象，架构清晰，在智能合约领域实现了高内聚低耦合的设计思想，从而可以专注的深入独立的模块阅读，降低了心智负担。

OlympusV3 的架构图如下所示：

后来了解到这种框架也并非 Olympus 独创，在 Olympus 介绍合约架构的文章中提到了Default 框架

智能合约架构的复杂性

在介绍 Default 框架之前，作者首先对比了传统的协议如 AAVE MakerDAO 的架构图

光看架构图，开发者是很难厘清其中的调用链路的，作者将这种设计解释为以过程为中心，按照逻辑链的思路来组织

Today, most projects take a process-centric approach towards protocol development: each smart contract is developed to manage a process along a chain of logic that is triggered when external interactions occur.

那么随着业务的升级和更替，逻辑链路的复杂度会指数级增长，原因在于整个协议呈现网状架构，或许每两个点之间都有逻辑链，那么每增添一个点，带来的复杂度提升是难以估量和覆盖的。

正如软件工程领域的设计模式演进过程一样，智能合约的工程化架构也在不断改进，Default Framework 正是着手解决这个问题

什么是 The Default Framework

光从名字看不出来设计的思路，不像Diamond 框架能够让人产生联想。The Default Framework 也没有做特别的创新，而是借鉴了传统领域开发的设计思想，对整个合约进行了分层

Modules：面向内部，模块可以理解为微服务，每个模块管理一部分数据，彼此之间不存在依赖关系，高度独立，对于模块的访问都到权限管理约束

Policy：面向外部调用，在内部负责组织不同的模块以实现业务逻辑

核心的管理逻辑都收口在Kernal.sol文件中，负责管控全局的 Policy 和 Modules

Modules

每个 Modules 包括独一无二的 KEYCODE 及 VERSION，在定义 Modules 时需要实现此方法，在 Kernal 中会维护所有的 keycode 及其与 Module 的映射关系

在 Kernal 中包括以下方法

_installModule：安装 module

_upgradeModule：升级 module

示例：

Copy
/// @inheritdoc Module
function KEYCODE() public pure override returns (Keycode) {
return toKeycode("MINTR");
}

/// @inheritdoc Module
function VERSION() external pure override returns (uint8 major, uint8 minor) {
major = 1;
minor = 0;
}

Policy

Policy 可以理解为传统软件开发的 service 层，用来组织一系列 Modules，包括以下方法：

configureDependencies：返回支持哪些 Modules

requestPermissions：返回支持的 Modules 的具体函数 selector

在 kernal 中包括以下方法：

_activatePolicy

_deactivatePolicy

示例：

Copy
/// @inheritdoc Policy
function configureDependencies() external override returns (Keycode[] memory dependencies) {
dependencies = new Keycode[](3);
dependencies[0] = toKeycode("MINTR");
dependencies[1] = toKeycode("TRSRY");
dependencies[2] = toKeycode("ROLES");

MINTR = MINTRv1(getModuleAddress(dependencies[0]));
TRSRY = TRSRYv1(getModuleAddress(dependencies[1]));
ROLES = ROLESv1(getModuleAddress(dependencies[2]));

(uint8 TRSRY_MAJOR, ) = TRSRY.VERSION();
(uint8 MINTR_MAJOR, ) = MINTR.VERSION();
(uint8 ROLES_MAJOR, ) = ROLES.VERSION();

// Ensure Modules are using the expected major version.
// Modules should be sorted in alphabetical order.
bytes memory expected = abi.encode([1, 1, 1]);
if (MINTR_MAJOR != 1 || ROLES_MAJOR != 1 || TRSRY_MAJOR != 1)
revert Policy_WrongModuleVersion(expected);
}

/// @inheritdoc Policy
function requestPermissions() external view override returns (Permissions[] memory requests) {
Keycode MINTR_KEYCODE = MINTR.KEYCODE();

requests = new Permissions[](4);
requests[0] = Permissions(MINTR_KEYCODE, MINTR.mintOhm.selector);
requests[1] = Permissions(MINTR_KEYCODE, MINTR.burnOhm.selector);
requests[2] = Permissions(MINTR_KEYCODE, MINTR.increaseMintApproval.selector);
requests[3] = Permissions(MINTR_KEYCODE, MINTR.decreaseMintApproval.selector);
}