• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SizeCredit / size-solidity / 18691556051

21 Oct 2025 04:58PM UTC coverage: 92.514% (-0.5%) from 93.036%
18691556051

Pull #191

github

web-flow
Merge 76e707811 into f3ea9de82
Pull Request #191: v1.8.1 copy limit order config per collection

327 of 364 branches covered (89.84%)

Branch coverage included in aggregate %.

20 of 24 new or added lines in 4 files covered. (83.33%)

2 existing lines in 2 files now uncovered.

1712 of 1840 relevant lines covered (93.04%)

4268.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.88
/src/factory/SizeFactory.sol
1
// SPDX-License-Identifier: MIT
2
pragma solidity 0.8.23;
3

4
import {IPool} from "@aave/interfaces/IPool.sol";
5
import {ERC721EnumerableUpgradeable} from
6
    "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
7

8
import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
9
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
10
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
11
import {CopyLimitOrderConfig} from "@src/market/libraries/OfferLibrary.sol";
12

13
import {ICollectionsManager} from "@src/collections/interfaces/ICollectionsManager.sol";
14
import {YieldCurve} from "@src/market/libraries/YieldCurveLibrary.sol";
15
import {BuyCreditLimitOnBehalfOfParams, BuyCreditLimitParams} from "@src/market/libraries/actions/BuyCreditLimit.sol";
16
import {
17
    SellCreditLimitOnBehalfOfParams, SellCreditLimitParams
18
} from "@src/market/libraries/actions/SellCreditLimit.sol";
19

20
import {Math, PERCENT} from "@src/market/libraries/Math.sol";
21
import {
22
    InitializeDataParams,
23
    InitializeFeeConfigParams,
24
    InitializeOracleParams,
25
    InitializeRiskConfigParams
26
} from "@src/market/libraries/actions/Initialize.sol";
27

28
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
29
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
30
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
31
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
32

33
import {Errors} from "@src/market/libraries/Errors.sol";
34

35
import {ISize} from "@src/market/interfaces/ISize.sol";
36

37
import {ISizeFactory} from "@src/factory/interfaces/ISizeFactory.sol";
38
import {MarketFactoryLibrary} from "@src/factory/libraries/MarketFactoryLibrary.sol";
39

40
import {NonTransferrableRebasingTokenVaultLibrary} from
41
    "@src/factory/libraries/NonTransferrableRebasingTokenVaultLibrary.sol";
42
import {PriceFeedFactoryLibrary} from "@src/factory/libraries/PriceFeedFactoryLibrary.sol";
43
import {NonTransferrableRebasingTokenVault} from "@src/market/token/NonTransferrableRebasingTokenVault.sol";
44

45
import {IPriceFeedV1_5_2} from "@src/oracle/v1.5.2/IPriceFeedV1_5_2.sol";
46

47
import {PriceFeed, PriceFeedParams} from "@src/oracle/v1.5.1/PriceFeed.sol";
48

49
import {SizeFactoryEvents} from "@src/factory/SizeFactoryEvents.sol";
50
import {SizeFactoryOffchainGetters} from "@src/factory/SizeFactoryOffchainGetters.sol";
51
import {Action, ActionsBitmap, Authorization} from "@src/factory/libraries/Authorization.sol";
52

53
import {ISizeFactoryV1_7} from "@src/factory/interfaces/ISizeFactoryV1_7.sol";
54
import {ISizeFactoryV1_8} from "@src/factory/interfaces/ISizeFactoryV1_8.sol";
55

56
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
57

58
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
59
import {CollectionsManager} from "@src/collections/CollectionsManager.sol";
60

61
import {BORROW_RATE_UPDATER_ROLE, KEEPER_ROLE, PAUSER_ROLE} from "@src/factory/interfaces/ISizeFactory.sol";
62

63
/// @title SizeFactory
64
/// @custom:security-contact security@size.credit
65
/// @author Size (https://size.credit/)
66
/// @notice See the documentation in {ISizeFactory}.
67
/// @dev Expects `AccessControlUpgradeable` to have a single DEFAULT_ADMIN_ROLE role address set.
68
contract SizeFactory is
69
    ISizeFactory,
70
    SizeFactoryOffchainGetters,
71
    SizeFactoryEvents,
72
    MulticallUpgradeable,
73
    AccessControlUpgradeable,
74
    UUPSUpgradeable
75
{
76
    using EnumerableSet for EnumerableSet.AddressSet;
77

78
    /// @custom:oz-upgrades-unsafe-allow constructor
79
    constructor() {
423✔
80
        _disableInitializers();
423✔
81
    }
82

83
    function initialize(address _owner) external initializer {
422✔
84
        __Multicall_init();
422✔
85
        __AccessControl_init();
422✔
86
        __UUPSUpgradeable_init();
422✔
87

88
        _grantRole(DEFAULT_ADMIN_ROLE, _owner);
422✔
89
        _grantRole(PAUSER_ROLE, _owner);
422✔
90
        _grantRole(KEEPER_ROLE, _owner);
422✔
91
        _grantRole(BORROW_RATE_UPDATER_ROLE, _owner);
422✔
92
    }
93

94
    function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) {}
2✔
95

96
    /// @inheritdoc ISizeFactory
97
    function setSizeImplementation(address _sizeImplementation) external onlyRole(DEFAULT_ADMIN_ROLE) {
426✔
98
        if (_sizeImplementation == address(0)) {
426✔
99
            revert Errors.NULL_ADDRESS();
1✔
100
        }
101
        emit SizeImplementationSet(sizeImplementation, _sizeImplementation);
425✔
102
        sizeImplementation = _sizeImplementation;
425✔
103
    }
104

105
    /// @inheritdoc ISizeFactory
106
    function setNonTransferrableRebasingTokenVaultImplementation(address _nonTransferrableTokenVaultImplementation)
426✔
107
        external
108
        onlyRole(DEFAULT_ADMIN_ROLE)
109
    {
110
        if (_nonTransferrableTokenVaultImplementation == address(0)) {
426✔
111
            revert Errors.NULL_ADDRESS();
1✔
112
        }
113
        emit NonTransferrableRebasingTokenVaultImplementationSet(
425✔
114
            nonTransferrableTokenVaultImplementation, _nonTransferrableTokenVaultImplementation
115
        );
116
        nonTransferrableTokenVaultImplementation = _nonTransferrableTokenVaultImplementation;
425✔
117
    }
118

119
    function setCollectionsManager(ICollectionsManager _collectionsManager) external onlyRole(DEFAULT_ADMIN_ROLE) {
422✔
120
        emit CollectionsManagerSet(address(collectionsManager), address(_collectionsManager));
422✔
121
        collectionsManager = _collectionsManager;
422✔
122
    }
123

124
    /// @inheritdoc ISizeFactory
125
    function createMarket(
495✔
126
        InitializeFeeConfigParams calldata feeConfigParams,
127
        InitializeRiskConfigParams calldata riskConfigParams,
128
        InitializeOracleParams calldata oracleParams,
129
        InitializeDataParams calldata dataParams
130
    ) external onlyRole(DEFAULT_ADMIN_ROLE) returns (ISize market) {
131
        address admin = msg.sender;
493✔
132
        market = MarketFactoryLibrary.createMarket(
493✔
133
            sizeImplementation, admin, feeConfigParams, riskConfigParams, oracleParams, dataParams
134
        );
135
        // slither-disable-next-line unused-return
136
        markets.add(address(market));
493✔
137
        emit CreateMarket(address(market));
493✔
138
    }
139

140
    /// @inheritdoc ISizeFactory
141
    function createBorrowTokenVault(IPool variablePool, IERC20Metadata underlyingBorrowToken)
425✔
142
        external
143
        onlyRole(DEFAULT_ADMIN_ROLE)
144
        returns (NonTransferrableRebasingTokenVault borrowTokenVault)
145
    {
146
        address admin = msg.sender;
424✔
147
        borrowTokenVault = NonTransferrableRebasingTokenVaultLibrary.createNonTransferrableRebasingTokenVault(
424✔
148
            nonTransferrableTokenVaultImplementation, admin, variablePool, underlyingBorrowToken
149
        );
150
        emit CreateBorrowTokenVault(address(borrowTokenVault));
424✔
151
    }
152

153
    /// @inheritdoc ISizeFactory
154
    function createPriceFeed(PriceFeedParams memory _priceFeedParams)
2✔
155
        external
156
        onlyRole(DEFAULT_ADMIN_ROLE)
157
        returns (PriceFeed priceFeed)
158
    {
159
        priceFeed = PriceFeedFactoryLibrary.createPriceFeed(_priceFeedParams);
1✔
160
        emit CreatePriceFeed(address(priceFeed));
1✔
161
    }
162

163
    /// @inheritdoc ISizeFactory
164
    function isMarket(address candidate) public view returns (bool) {
44,275✔
165
        return markets.contains(candidate);
44,285✔
166
    }
167

168
    /// @inheritdoc ISizeFactoryV1_7
169
    function setAuthorization(address operator, ActionsBitmap actionsBitmap) external override(ISizeFactoryV1_7) {
42✔
170
        // validate msg.sender
171
        // N/A
172

173
        _setAuthorization(operator, msg.sender, actionsBitmap);
42✔
174
    }
175

176
    function _setAuthorization(address operator, address onBehalfOf, ActionsBitmap actionsBitmap) internal {
42✔
177
        // validate operator
178
        if (operator == address(0)) {
42✔
179
            revert Errors.NULL_ADDRESS();
1✔
180
        }
181
        // validate actionsBitmap
182
        if (!Authorization.isValid(actionsBitmap)) {
41✔
183
            revert Errors.INVALID_ACTIONS_BITMAP(Authorization.toUint256(actionsBitmap));
3✔
184
        }
185

186
        uint256 nonce = authorizationNonces[onBehalfOf];
38✔
187
        emit SetAuthorization(onBehalfOf, operator, Authorization.toUint256(actionsBitmap), nonce);
38✔
188
        authorizations[nonce][operator][onBehalfOf] = actionsBitmap;
38✔
189
    }
190

191
    /// @inheritdoc ISizeFactoryV1_7
192
    function revokeAllAuthorizations() external override(ISizeFactoryV1_7) {
1✔
193
        emit RevokeAllAuthorizations(msg.sender);
1✔
194
        authorizationNonces[msg.sender]++;
1✔
195
    }
196

197
    /// @inheritdoc ISizeFactoryV1_7
198
    function isAuthorized(address operator, address onBehalfOf, Action action) public view returns (bool) {
61,031✔
199
        if (operator == onBehalfOf) {
61,087✔
200
            return true;
61,017✔
201
        } else {
202
            uint256 nonce = authorizationNonces[onBehalfOf];
70✔
203
            return Authorization.isActionSet(authorizations[nonce][operator][onBehalfOf], action);
70✔
204
        }
205
    }
206

207
    /// @inheritdoc ISizeFactoryV1_8
208
    function callMarket(ISize market, bytes calldata data) external returns (bytes memory result) {
10✔
209
        if (!isMarket(address(market))) {
10✔
210
            revert Errors.INVALID_MARKET(address(market));
1✔
211
        }
212
        result = Address.functionCall(address(market), data);
9✔
213
    }
214

215
    /// @inheritdoc ISizeFactoryV1_8
216
    function subscribeToCollections(uint256[] memory collectionIds) external {
35✔
217
        return subscribeToCollectionsOnBehalfOf(collectionIds, msg.sender);
35✔
218
    }
219

220
    /// @inheritdoc ISizeFactoryV1_8
221
    function unsubscribeFromCollections(uint256[] memory collectionIds) external {
4✔
222
        return unsubscribeFromCollectionsOnBehalfOf(collectionIds, msg.sender);
4✔
223
    }
224

225
    /// @inheritdoc ISizeFactoryV1_8
226
    function subscribeToCollectionsOnBehalfOf(uint256[] memory collectionIds, address onBehalfOf) public {
2✔
227
        if (!isAuthorized(msg.sender, onBehalfOf, Action.MANAGE_COLLECTION_SUBSCRIPTIONS)) {
37✔
228
            revert Errors.UNAUTHORIZED_ACTION(msg.sender, onBehalfOf, uint8(Action.MANAGE_COLLECTION_SUBSCRIPTIONS));
1✔
229
        }
230
        collectionsManager.subscribeUserToCollections(onBehalfOf, collectionIds);
36✔
231
    }
232

233
    /// @inheritdoc ISizeFactoryV1_8
234
    function unsubscribeFromCollectionsOnBehalfOf(uint256[] memory collectionIds, address onBehalfOf) public {
2✔
235
        if (!isAuthorized(msg.sender, onBehalfOf, Action.MANAGE_COLLECTION_SUBSCRIPTIONS)) {
6✔
236
            revert Errors.UNAUTHORIZED_ACTION(msg.sender, onBehalfOf, uint8(Action.MANAGE_COLLECTION_SUBSCRIPTIONS));
1✔
237
        }
238
        collectionsManager.unsubscribeUserFromCollections(onBehalfOf, collectionIds);
5✔
239
    }
240

241
    function setUserCollectionCopyLimitOrderConfigs(
13✔
242
        uint256 collectionId,
243
        CopyLimitOrderConfig memory copyLoanOfferConfig,
244
        CopyLimitOrderConfig memory copyBorrowOfferConfig
245
    ) external {
246
        return setUserCollectionCopyLimitOrderConfigsOnBehalfOf(
13✔
247
            collectionId, copyLoanOfferConfig, copyBorrowOfferConfig, msg.sender
248
        );
249
    }
250

NEW
251
    function setUserCollectionCopyLimitOrderConfigsOnBehalfOf(
×
252
        uint256 collectionId,
253
        CopyLimitOrderConfig memory copyLoanOfferConfig,
254
        CopyLimitOrderConfig memory copyBorrowOfferConfig,
255
        address onBehalfOf
256
    ) public {
257
        if (!isAuthorized(msg.sender, onBehalfOf, Action.MANAGE_COLLECTION_SUBSCRIPTIONS)) {
13!
NEW
258
            revert Errors.UNAUTHORIZED_ACTION(msg.sender, onBehalfOf, uint8(Action.MANAGE_COLLECTION_SUBSCRIPTIONS));
×
259
        }
260
        collectionsManager.setUserCollectionCopyLimitOrderConfigs(
13✔
261
            onBehalfOf, collectionId, copyLoanOfferConfig, copyBorrowOfferConfig
262
        );
263
    }
264

265
    /// @inheritdoc ISizeFactoryV1_8
266
    function getLoanOfferAPR(address user, uint256 collectionId, ISize market, address rateProvider, uint256 tenor)
15,698✔
267
        external
268
        view
269
        returns (uint256)
270
    {
271
        return collectionsManager.getLoanOfferAPR(user, collectionId, market, rateProvider, tenor);
15,698✔
272
    }
273

274
    /// @inheritdoc ISizeFactoryV1_8
275
    function getBorrowOfferAPR(address user, uint256 collectionId, ISize market, address rateProvider, uint256 tenor)
5,314✔
276
        external
277
        view
278
        returns (uint256)
279
    {
280
        return collectionsManager.getBorrowOfferAPR(user, collectionId, market, rateProvider, tenor);
5,314✔
281
    }
282

283
    function isBorrowAPRLowerThanLoanOfferAPRs(address user, uint256 borrowAPR, ISize market, uint256 tenor)
2,375✔
284
        external
285
        view
286
        returns (bool)
287
    {
288
        return collectionsManager.isBorrowAPRLowerThanLoanOfferAPRs(user, borrowAPR, market, tenor);
2,375✔
289
    }
290

291
    function isLoanAPRGreaterThanBorrowOfferAPRs(address user, uint256 loanAPR, ISize market, uint256 tenor)
7,570✔
292
        external
293
        view
294
        returns (bool)
295
    {
296
        return collectionsManager.isLoanAPRGreaterThanBorrowOfferAPRs(user, loanAPR, market, tenor);
7,570✔
297
    }
298
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc