Branch data Line data Source code
1 : : // SPDX-License-Identifier: BUSL-1.1
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import {IERC20Metadata} from 'solidity-utils/contracts/oz-common/interfaces/IERC20Metadata.sol';
5 : : import {ITransparentProxyFactory} from 'solidity-utils/contracts/transparent-proxy/interfaces/ITransparentProxyFactory.sol';
6 : : import {Initializable} from 'solidity-utils/contracts/transparent-proxy/Initializable.sol';
7 : : import {IPool, DataTypes} from '../../../contracts/interfaces/IPool.sol';
8 : : import {StataTokenV2} from './StataTokenV2.sol';
9 : : import {IStataTokenFactory} from './interfaces/IStataTokenFactory.sol';
10 : :
11 : : /**
12 : : * @title StataTokenFactory
13 : : * @notice Factory contract that keeps track of all deployed StataTokens for a specified pool.
14 : : * This registry also acts as a factory, allowing to deploy new StataTokens on demand.
15 : : * There can only be one StataToken per underlying on the registry at any time.
16 : : * @author BGD labs
17 : : */
18 : : contract StataTokenFactory is Initializable, IStataTokenFactory {
19 : : IPool public immutable POOL;
20 : : address public immutable PROXY_ADMIN;
21 : : ITransparentProxyFactory public immutable TRANSPARENT_PROXY_FACTORY;
22 : : address public immutable STATA_TOKEN_IMPL;
23 : :
24 : : mapping(address => address) internal _underlyingToStataToken;
25 : : address[] internal _stataTokens;
26 : :
27 : : event StataTokenCreated(address indexed stataToken, address indexed underlying);
28 : :
29 : : constructor(
30 : : IPool pool,
31 : : address proxyAdmin,
32 : : ITransparentProxyFactory transparentProxyFactory,
33 : : address stataTokenImpl
34 : : ) {
35 : 0 : POOL = pool;
36 : 0 : PROXY_ADMIN = proxyAdmin;
37 : 0 : TRANSPARENT_PROXY_FACTORY = transparentProxyFactory;
38 : 0 : STATA_TOKEN_IMPL = stataTokenImpl;
39 : : }
40 : :
41 : : function initialize() external initializer {}
42 : :
43 : : ///@inheritdoc IStataTokenFactory
44 : : function createStataTokens(address[] memory underlyings) external returns (address[] memory) {
45 : 23 : address[] memory stataTokens = new address[](underlyings.length);
46 : 23 : for (uint256 i = 0; i < underlyings.length; i++) {
47 : 69 : address cachedStataToken = _underlyingToStataToken[underlyings[i]];
48 : 69 : if (cachedStataToken == address(0)) {
49 : 69 : DataTypes.ReserveDataLegacy memory reserveData = POOL.getReserveData(underlyings[i]);
50 : 69 : if (reserveData.aTokenAddress == address(0))
51 : 0 : revert NotListedUnderlying(reserveData.aTokenAddress);
52 : 69 : bytes memory symbol = abi.encodePacked(
53 : : 'stat',
54 : : IERC20Metadata(reserveData.aTokenAddress).symbol(),
55 : : 'v2'
56 : : );
57 : 69 : address stataToken = TRANSPARENT_PROXY_FACTORY.createDeterministic(
58 : : STATA_TOKEN_IMPL,
59 : : PROXY_ADMIN,
60 : : abi.encodeWithSelector(
61 : : StataTokenV2.initialize.selector,
62 : : reserveData.aTokenAddress,
63 : : string(
64 : : abi.encodePacked('Static ', IERC20Metadata(reserveData.aTokenAddress).name(), ' v2')
65 : : ),
66 : : string(symbol)
67 : : ),
68 : : bytes32(uint256(uint160(underlyings[i])))
69 : : );
70 : :
71 : 69 : _underlyingToStataToken[underlyings[i]] = stataToken;
72 : 69 : stataTokens[i] = stataToken;
73 : 69 : _stataTokens.push(stataToken);
74 : 69 : emit StataTokenCreated(stataToken, underlyings[i]);
75 : : } else {
76 : 0 : stataTokens[i] = cachedStataToken;
77 : : }
78 : : }
79 : 23 : return stataTokens;
80 : : }
81 : :
82 : : ///@inheritdoc IStataTokenFactory
83 : : function getStataTokens() external view returns (address[] memory) {
84 : 0 : return _stataTokens;
85 : : }
86 : :
87 : : ///@inheritdoc IStataTokenFactory
88 : : function getStataToken(address underlying) external view returns (address) {
89 : 23 : return _underlyingToStataToken[underlying];
90 : : }
91 : : }
|