Contract changes
⚠️ Warning
While the contract changes contained in this upgrade have been carefully tested, they haven't been audited by a third party. Make sure you review/audit the upgrade before using it in production.
All contract changes are done in Linear-finance/linear. The upgrade is submitted as the dev/multi_collateral branch.
For any modified contracts, the modifications are all made in a backward-compatible, upgrade-safe manner, as this upgrade needs to be deployed to production.
ℹ️ Note
Mock/interface files are excluded from this page.
ℹ️ Note
This page only documents the source code changes for each file modified/added. The actual deployment steps (i.e. what contracts to upgrade; what new contracts to deploy) are documented separately.
Notable changes
Architecture change
Originally, only one instance of each of the following contracts is deployed:
LnBuildBurnSystemLnCollateralSystemLnDebtSystemLnLiquidationLnRewardSystem
With the upgrade, these 5 contracts will be deployed for each supported collateral token. A new contract DebtDistribution has been added to govern the different collateral tokens.
ℹ️ Note
Each set of the 5 collateral-specific contracts is not linked to, nor aware of the existence of, the set of contracts of any other collateral token. The new
DebtDistributioncontract is necessary as each collateral needs to know how much (in terms of proportion) of the whole debt pool it's entitled to.
Reduced usage of registry pattern
The Linear smart contract system was originally designed to use the registry pattern heavily (with LnAddressCache), with the LnAssetSystem serving as the contract address registry. However, newer contracts (e.g. LnLiquidation) stopped using the pattern. Right before the multicollateral upgrade, these contracts still used this pattern:
LnBuildBurnSystemLnCollateralSystemLnDebtSystemLnAssetUpgradeableLnExchangeSystem
Out of the 5 contracts, these 3 contracts used the pattern in a way that's incompatible with the multicollateral upgrade:
LnBuildBurnSystemLnCollateralSystemLnDebtSystem
ℹ️ Note
What makes them incompatible is that these 3 contracts assume that only a single instance of the collateral-specific contracts is deployed, which is no longer true. See the architecture change section for details.
As such, the use of the registry pattern in these 3 contracts has been removed and replaced with setting the addresses via the initializer function, or via specific setter functions if circular dependency is involved.
ℹ️ Note
The initializer function is only run on proxy contract deployment and not on contract upgrades. This means the new address setting behavior would only be effective for newly-deployed collateral-specific contracts, and not for
LINA-specific contracts.But this is fine as
LINA-specific contracts already had the addresses configured via the registry pattern. It would be as if the new initializer has been run on them.
Code change of SafeDecimalMath
Two new functions have been added to the SafeDecimalMath library. Since SafeDecimalMath is a dynamically-linked library, a new instance would need to be deployed and all new dependant contracts to be linked to the new instance.
ℹ️ Note
Writing library contracts with an external API, and thus requiring explicit linking (like the
SafeDecimalMathwe have) is now widely considered an anti-pattern.However, the multicollateral upgrade leaves this questionable design unchanged to minimize the scope of changes. A follow-up on this shall be made to migrate away from external libraries.
Per-file changes
ℹ️ Note
This section only summarizes the major changes for each relevant file, and does not replace actually reading the source code.
DebtDistribution.sol
This is a new contract for tracking how much (in terms of proportion) debt each collateral token is entitled to. See the architecture change section for details.
LnBuildBurnSystem.sol
Main changes to this contract include:
- Removed the registry pattern for setting contract addresses. See this section for details.
- Removed the debt changes calculation logic, and changed to delegate to
LnDebtSysteminstead. - Changed to use collateral-specific config keys for reading config values.
LnCollateralSystem.sol
This contract has been largely rewritten (with backward compatibility preserved).
The original codebase assumed that all collateral types will be aggregated into a single USD amount, which is now considered impractical, as different collaterals have different risk characteristics. The new design is to have each LnCollateralSystem contract handle only a single collateral token.
LnDebtSystem.sol
This contract has been largely rewritten (with backward compatibility preserved).
The original implementation is essentially a simple key-value store, accepting already-computed latest values from LnBuildBurnSystem. With this upgrade, LnDebtSystem now handles and encapsulates debt changes calculations, and exposes increaseDebt() and decreaseDebt() instead.
LnLiquidation.sol
Only minimal changes were made to this contract:
- Changed to use collateral-specific config keys for reading config values.
- Added the ability to handle collateral tokens that are not 18 decimals in precision.
SafeDecimalMath.sol
Two functions have been added to allow handling collateral tokens that are not 18 decimals in precision:
multiplyDecimalWith()divideDecimalWith()
utilities/ConfigHelper.sol
This library provides helper functions for computing config key values based on the collateral token used. This is needed as different collateral tokens have different settings.
ℹ️ Note
Unlike
SafeDecimalMath, this contract does not expose a public API, and is thus statically linked to dependant contracts. You don't need to deploy this library itself.