Skip to content

Commit 662df96

Browse files
authored
fix(protocol-contracts): follow ERC4626 pattern for OperatorStaking decimals (#1746)
1 parent 084f7c0 commit 662df96

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

protocol-contracts/staking/contracts/OperatorStaking.sol

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {ERC1363Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC2
66
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
77
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
88
import {ERC4626, IERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
9+
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
910
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
1011
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
1112
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
@@ -38,6 +39,7 @@ contract OperatorStaking is ERC1363Upgradeable, ReentrancyGuardTransient, UUPSUp
3839
IERC20 _asset;
3940
address _rewarder;
4041
uint256 _totalSharesInRedemption;
42+
uint8 _underlyingDecimals;
4143
mapping(address controller => uint256 sharesReleased) _sharesReleased;
4244
mapping(address controller => Checkpoints.Trace208 redeemRequests) _redeemRequests;
4345
mapping(address controller => mapping(address operator => bool approved)) _operator;
@@ -130,6 +132,10 @@ contract OperatorStaking is ERC1363Upgradeable, ReentrancyGuardTransient, UUPSUp
130132
$._asset = IERC20(protocolStaking_.stakingToken());
131133
$._protocolStaking = protocolStaking_;
132134

135+
// Follow ERC4626 pattern but no need to use `_tryGetAssetDecimals` as the implementation
136+
// used to deploy the asset does expose the `decimals` function.
137+
$._underlyingDecimals = IERC20Metadata(asset()).decimals();
138+
133139
IERC20(asset()).approve(address(protocolStaking_), type(uint256).max);
134140

135141
OperatorRewarder rewarder_ = new OperatorRewarder(
@@ -428,6 +434,16 @@ contract OperatorStaking is ERC1363Upgradeable, ReentrancyGuardTransient, UUPSUp
428434
return _getOperatorStakingStorage()._operator[controller][operator];
429435
}
430436

437+
/**
438+
* @notice Returns the decimals of the shares following the ERC4626 pattern.
439+
* @dev The decimals of the shares is the sum of the decimals of the underlying asset and the
440+
* decimal offset.
441+
* @return The decimals of the shares following the ERC4626 pattern.
442+
*/
443+
function decimals() public view virtual override returns (uint8) {
444+
return _getOperatorStakingStorage()._underlyingDecimals + _decimalsOffset();
445+
}
446+
431447
function _doTransferOut(address to, uint256 amount) internal virtual {
432448
IERC20 asset_ = IERC20(asset());
433449
if (amount > asset_.balanceOf(address(this))) {

protocol-contracts/staking/test/OperatorStaking.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ describe('OperatorStaking', function () {
8585
});
8686
});
8787

88+
describe('decimals', function () {
89+
it('should return the decimals of the shares', async function () {
90+
const assetDecimals = await this.token.decimals();
91+
expect(await this.mock.decimals()).to.equal(assetDecimals + DECIMAL_OFFSET);
92+
});
93+
});
94+
8895
describe('deposit', async function () {
8996
it('should stake into protocol staking', async function () {
9097
await expect(this.mock.connect(this.delegator1).deposit(ethers.parseEther('1'), this.delegator1))

0 commit comments

Comments
 (0)