智能合约代理
智能合约为了能够升级的需求,重要的合约基本都是代理模式。AAVE
的代理非常复杂,要想深入理解 AAVE
的代理体系,就需要剥茧抽丝,一层一层的去仔细研究,才能理解其精髓。
AAVE 代理全局图:
按照 openzeppelin
对代理的定义, 智能合约的代理通常分为两种类型, 一种是透明代理(transparent),一种是 uups 代理。两种代理的区别是:
目前, openzeppelin
更推荐使用 uups
方式的代理,更易用,也更简洁。
LendingPoolAddressesProvider
首先,要讲一下位于核心地位的 LendingPoolAddressesProvider
合约,这个合约是一个注册中心,也是一个管理中心。这个合约主要有两个作用:
- 创建、升级、管理其他合约;
- 作为注册中心,报错各个合约的地址,并未其他合约提供地址, 其他合约通过
LendingPoolAddressesProvider
来查询其他合约的地址;
以下几个核心合约都是通过这个合约创建、升级、初始化、管理的:
- LENDING_POOL
- LENDING_POOL_CONFIGURATOR
LendingPoolAddressesProvider
,从名字可以看出,这个合约的一大功能就是提供 Address, 为谁提供 Address 呢? 以下地址通过 LendingPoolAddressesProvider
来配置:
- LENDING_POOL
- LENDING_POOL_CONFIGURATOR
- LENDING_POOL_COLLATERAL_MANAGER
- POOL_ADMIN
- EMERGENCY_ADMIN
- PRICE_ORACLE
- LENDING_RATE_ORACLE
LendingPoolAddressesProvider
是如何创建、管理合约的呢?大概的步骤如下:
- 合约创建时,会先创建一个 Proxy 模板,然后把具体的实现设置到 Proxy 合约中;
- 上面几个合约中,都有一个
addressesProvider
变量,初始化第一步创建的合约时,将本合约的地址作为参数,初始化; - 这几个合约需要相互调用,当调用时,首先通过
addressesProvider
来获取对方的地址,然后再调用。
创建其他合约的Proxy并设置代理的代码如下:
// 升级或创建合约
function _updateImpl(bytes32 id, address newAddress) internal {
address payable proxyAddress = payable(_addresses[id]);
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(proxyAddress);
bytes memory params = abi.encodeWithSignature('initialize(address)', address(this));
if (proxyAddress == address(0)) {
// 代理合约不存在时,先创建代理合约模板,然后初始化代理合约
proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
proxy.initialize(newAddress, params);
_addresses[id] = address(proxy);
emit ProxyCreated(id, address(proxy));
} else {
// 已经存在时, 升级合约
proxy.upgradeToAndCall(newAddress, params);
}
}
LendingPoolConfigurator
与 LendingPoolAddressesProvider
, LendingPoolConfigurator
用来创建以下合约的代理:
- AToken
- StableDebtToken
- VariableDebtToken
代码如下:
function _initTokenWithProxy(address implementation, bytes memory initParams)
internal
returns (address)
{
// 部署 proxy 合约
InitializableImmutableAdminUpgradeabilityProxy proxy =
new InitializableImmutableAdminUpgradeabilityProxy(address(this));
// 将proxy合约的实现指向 implementation, 并初始化 proxy 合约
proxy.initialize(implementation, initParams);
return address(proxy);
}
升级合约:
function _upgradeTokenImplementation(
address proxyAddress,
address implementation,
bytes memory initParams
) internal {
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress));
proxy.upgradeToAndCall(implementation, initParams);
}
关系图: