@@ -3,68 +3,88 @@ pragma solidity ^0.8.0;
33
44/**
55 * @title SharedDecimalsLib
6- * @notice Library for handling shared decimals conversions for OFT bridging.
7- * @dev Logic adapted from LayerZero's OFTCore.sol
6+ * @notice Copied from LZ implementation here:
7+ * `https://github.com/LayerZero-Labs/devtools/blob/16daaee36fe802d11aa99b89c29bb74447354483/packages/oft-evm/contracts/OFTCore.sol#L364`
8+ * Code was not modified beyond removing unrelated OFT/OApp concerns.
89 */
9- library SharedDecimalsLib {
10+ abstract contract SharedDecimalsLib {
1011 error InvalidLocalDecimals ();
1112 error AmountSDOverflowed (uint256 amountSD );
1213
14+ // @notice Provides a conversion rate when swapping between denominations of SD and LD
15+ // - shareDecimals == SD == shared Decimals
16+ // - localDecimals == LD == local decimals
17+ // @dev Considers that tokens have different decimal amounts on various chains.
18+ // @dev eg.
19+ // For a token
20+ // - locally with 4 decimals --> 1.2345 => uint(12345)
21+ // - remotely with 2 decimals --> 1.23 => uint(123)
22+ // - The conversion rate would be 10 ** (4 - 2) = 100
23+ // @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote,
24+ // you can only display 1.23 -> uint(123).
25+ // @dev To preserve the dust that would otherwise be lost on that conversion,
26+ // we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh
27+ uint256 public immutable decimalConversionRate;
28+
1329 /**
14- * @notice Convert an amount from local decimals into shared decimals.
15- * @dev Internal function to convert an amount from local decimals into shared decimals.
30+ * @dev Constructor.
31+ * @param _localDecimals The decimals of the token on the local chain (this chain).
32+ * @param _endpoint Unused (kept for parity with OFTCore signature).
33+ * @param _delegate Unused (kept for parity with OFTCore signature).
34+ */
35+ constructor (uint8 _localDecimals , address _endpoint , address _delegate ) {
36+ _endpoint;
37+ _delegate;
38+ if (_localDecimals < sharedDecimals ()) revert InvalidLocalDecimals ();
39+ decimalConversionRate = 10 ** (_localDecimals - sharedDecimals ());
40+ }
41+
42+ /**
43+ * @dev Retrieves the shared decimals of the OFT.
44+ * @return The shared decimals of the OFT.
45+ *
46+ * @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap
47+ * Lowest common decimal denominator between chains.
48+ * Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).
49+ * For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.
50+ * ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615
51+ */
52+ function sharedDecimals () public view virtual returns (uint8 ) {
53+ return 6 ;
54+ }
55+
56+ /**
57+ * @dev Internal function to remove dust from the given local decimal amount.
1658 * @param _amountLD The amount in local decimals.
17- * @param _localDecimals The decimals of the token on the local chain.
18- * @param _sharedDecimals The shared decimals of the OFT.
19- * @return amountSD The amount in shared decimals.
59+ * @return amountLD The amount after removing dust.
2060 *
21- * @dev Reverts if the _amountLD in shared decimals overflows uint64.
61+ * @dev Prevents the loss of dust when moving amounts between chains with different decimals.
62+ * @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).
2263 */
23- function toSD (
24- uint256 _amountLD ,
25- uint8 _localDecimals ,
26- uint8 _sharedDecimals
27- ) internal pure returns (uint64 amountSD ) {
28- if (_localDecimals < _sharedDecimals) revert InvalidLocalDecimals ();
29- uint256 conversionRate = 10 ** (_localDecimals - _sharedDecimals);
30- uint256 _amountSD = _amountLD / conversionRate;
31- if (_amountSD > type (uint64 ).max) revert AmountSDOverflowed (_amountSD);
32- return uint64 (_amountSD);
64+ function _removeDust (uint256 _amountLD ) internal view virtual returns (uint256 amountLD ) {
65+ return (_amountLD / decimalConversionRate) * decimalConversionRate;
3366 }
3467
3568 /**
36- * @notice Convert an amount from shared decimals into local decimals.
3769 * @dev Internal function to convert an amount from shared decimals into local decimals.
3870 * @param _amountSD The amount in shared decimals.
39- * @param _localDecimals The decimals of the token on the local chain.
40- * @param _sharedDecimals The shared decimals of the OFT.
4171 * @return amountLD The amount in local decimals.
4272 */
43- function toLD (
44- uint64 _amountSD ,
45- uint8 _localDecimals ,
46- uint8 _sharedDecimals
47- ) internal pure returns (uint256 amountLD ) {
48- if (_localDecimals < _sharedDecimals) revert InvalidLocalDecimals ();
49- uint256 conversionRate = 10 ** (_localDecimals - _sharedDecimals);
50- return uint256 (_amountSD) * conversionRate;
73+ function _toLD (uint64 _amountSD ) internal view virtual returns (uint256 amountLD ) {
74+ return _amountSD * decimalConversionRate;
5175 }
5276
5377 /**
54- * @notice Remove dust from the given local decimal amount.
55- * @dev Internal function to remove dust from the given local decimal amount.
78+ * @dev Internal function to convert an amount from local decimals into shared decimals.
5679 * @param _amountLD The amount in local decimals.
57- * @param _localDecimals The decimals of the token on the local chain.
58- * @param _sharedDecimals The shared decimals of the OFT.
59- * @return amountLD The amount after removing dust.
80+ * @return amountSD The amount in shared decimals.
81+ *
82+ * @dev Reverts if the _amountLD in shared decimals overflows uint64.
83+ * @dev eg. uint(2**64 + 123) with a conversion rate of 1 wraps around 2**64 to uint(123).
6084 */
61- function removeDust (
62- uint256 _amountLD ,
63- uint8 _localDecimals ,
64- uint8 _sharedDecimals
65- ) internal pure returns (uint256 amountLD ) {
66- if (_localDecimals < _sharedDecimals) revert InvalidLocalDecimals ();
67- uint256 conversionRate = 10 ** (_localDecimals - _sharedDecimals);
68- return (_amountLD / conversionRate) * conversionRate;
85+ function _toSD (uint256 _amountLD ) internal view virtual returns (uint64 amountSD ) {
86+ uint256 _amountSD = _amountLD / decimalConversionRate;
87+ if (_amountSD > type (uint64 ).max) revert AmountSDOverflowed (_amountSD);
88+ return uint64 (_amountSD);
6989 }
7090}
0 commit comments