Skip to content

Commit

Permalink
Merge pull request #54 from bgd-labs/feat/reintroduce-permissions
Browse files Browse the repository at this point in the history
feat: reintroduce permissions on rescuable
  • Loading branch information
sakulstra authored Sep 16, 2024
2 parents 0c419cd + 5b01bdd commit 13caab8
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 21 deletions.
Binary file modified audits/11-09-2024_Certora_StataTokenV2.pdf
Binary file not shown.
20 changes: 10 additions & 10 deletions certora/stata/specs/StataToken/StataToken.spec
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ import "../methods/methods_base.spec";
f.contract == currentContract &&
!harnessOnlyMethods(f) &&
f.selector != sig:initialize(address, string, string).selector) &&
f.selector != sig:emergencyEtherTransfer(uint256).selector &&
f.selector != sig:emergencyTokenTransfer(address,uint256).selector
f.selector != sig:emergencyEtherTransfer(address,uint256).selector &&
f.selector != sig:emergencyTokenTransfer(address,address,uint256).selector
} {
// Assuming single reward
single_RewardToken_setup();
Expand Down Expand Up @@ -137,7 +137,7 @@ import "../methods/methods_base.spec";
&& !harnessMethodsMinusHarnessClaimMethods(f)
&& !claimFunctions(f)
&& f.selector != sig:claimDoubleRewardOnBehalfSame(address, address, address).selector
&& f.selector != sig:emergencyEtherTransfer(uint256).selector
&& f.selector != sig:emergencyEtherTransfer(address,uint256).selector
}
{
preserved redeem(uint256 shares, address receiver, address owner) with (env e1) {
Expand All @@ -152,7 +152,7 @@ import "../methods/methods_base.spec";
requireInvariant solvency_total_asset_geq_total_supply();
require balanceOf(owner) <= totalSupply();
}
preserved emergencyTokenTransfer(address asset, uint256 amount) with (env e3) {
preserved emergencyTokenTransfer(address asset, address to, uint256 amount) with (env e3) {
require rate() >= RAY();
}
}
Expand All @@ -170,7 +170,7 @@ import "../methods/methods_base.spec";
f.contract == currentContract
&& !harnessMethodsMinusHarnessClaimMethods(f)
&& !claimFunctions(f)
&& f.selector != sig:emergencyEtherTransfer(uint256).selector
&& f.selector != sig:emergencyEtherTransfer(address,uint256).selector
&& f.selector != sig:claimDoubleRewardOnBehalfSame(address, address, address).selector }
{
preserved withdraw(uint256 assets, address receiver, address owner) with (env e3) {
Expand Down Expand Up @@ -198,7 +198,7 @@ import "../methods/methods_base.spec";
preserved redeemATokens(uint256 shares, address receiver, address owner) with (env e2) {
require balanceOf(owner) <= totalSupply();
}
preserved emergencyTokenTransfer(address asset, uint256 amount) with (env e1) {
preserved emergencyTokenTransfer(address asset, address to, uint256 amount) with (env e1) {
require rate() >= RAY();
}
}
Expand All @@ -216,7 +216,7 @@ import "../methods/methods_base.spec";
=> (_RewardsController.getUserAccruedReward(_asset, reward, user) == _RewardsController.getUserAccruedRewards(reward, user)))
filtered {f ->
f.contract == currentContract &&
f.selector != sig:emergencyEtherTransfer(uint256).selector &&
f.selector != sig:emergencyEtherTransfer(address,uint256).selector &&
!harnessOnlyMethods(f)
}
{
Expand Down Expand Up @@ -256,8 +256,8 @@ import "../methods/methods_base.spec";
&& !collectAndUpdateFunction(f)
&& !harnessOnlyMethods(f)
&& f.selector != sig:initialize(address,string,string).selector
&& f.selector != sig:emergencyEtherTransfer(uint256).selector
&& f.selector != sig:emergencyTokenTransfer(address,uint256).selector
&& f.selector != sig:emergencyEtherTransfer(address,uint256).selector
&& f.selector != sig:emergencyTokenTransfer(address,address,uint256).selector
}
{
env e;
Expand Down Expand Up @@ -301,7 +301,7 @@ rule getClaimableRewards_stable(method f)
&& !claimFunctions(f)
&& !collectAndUpdateFunction(f)
&& f.selector != sig:initialize(address,string,string).selector
&& f.selector != sig:emergencyEtherTransfer(uint256).selector
&& f.selector != sig:emergencyEtherTransfer(address,uint256).selector
&& !harnessOnlyMethods(f)
}
{
Expand Down
2 changes: 1 addition & 1 deletion certora/stata/specs/StataToken/aTokenProperties.spec
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ import "../methods/methods_base.spec";
!f.isView &&
f.selector != sig:redeem(uint256,address,address).selector &&
f.selector != sig:redeemATokens(uint256,address,address).selector &&
f.selector != sig:emergencyEtherTransfer(uint256).selector &&
f.selector != sig:emergencyEtherTransfer(address,uint256).selector &&
!harnessOnlyMethods(f)}
{
preserved with (env e){
Expand Down
2 changes: 1 addition & 1 deletion certora/stata/specs/erc4626/erc4626Extended.spec
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ import "../methods/methods_base.spec";
f.contract == currentContract &&
!f.isView &&
!harnessOnlyMethods(f) &&
f.selector != sig:emergencyEtherTransfer(uint256).selector &&
f.selector != sig:emergencyEtherTransfer(address,uint256).selector &&
f.selector != sig:deposit(uint256,address).selector &&
f.selector != sig:depositWithPermit(uint256,address,uint256,IERC4626StataToken.SignatureParams,bool).selector &&
f.selector != sig:withdraw(uint256,address,address).selector &&
Expand Down
10 changes: 5 additions & 5 deletions src/periphery/contracts/static-a-token/StataTokenV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.0;
import {ERC20Upgradeable, ERC20PermitUpgradeable} from 'openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol';
import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import {PausableUpgradeable} from 'openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol';
import {IPermissionlessRescuable, PermissionlessRescuable} from 'solidity-utils/contracts/utils/PermissionlessRescuable.sol';
import {IRescuable, Rescuable} from 'solidity-utils/contracts/utils/Rescuable.sol';
import {IRescuableBase, RescuableBase} from 'solidity-utils/contracts/utils/RescuableBase.sol';
import {IERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol';

Expand All @@ -24,7 +24,7 @@ contract StataTokenV2 is
ERC20AaveLMUpgradeable,
ERC4626StataTokenUpgradeable,
PausableUpgradeable,
PermissionlessRescuable,
Rescuable,
IStataTokenV2
{
using Math for uint256;
Expand Down Expand Up @@ -59,9 +59,9 @@ contract StataTokenV2 is
else _unpause();
}

/// @inheritdoc IPermissionlessRescuable
function whoShouldReceiveFunds() public view override returns (address) {
return IAToken(address(aToken())).RESERVE_TREASURY_ADDRESS();
/// @inheritdoc IRescuable
function whoCanRescue() public view override returns (address) {
return POOL_ADDRESSES_PROVIDER.getACLAdmin();
}

/// @inheritdoc IRescuableBase
Expand Down
25 changes: 21 additions & 4 deletions tests/periphery/static-a-token/StataTokenV2Rescuable.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;

import {IRescuable} from 'solidity-utils/contracts/utils/Rescuable.sol';
import {IAToken} from '../../../src/periphery/contracts/static-a-token/StataTokenV2.sol';
import {IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import {BaseTest} from './TestBase.sol';

contract StataTokenV2RescuableTest is BaseTest {
Expand All @@ -12,14 +14,28 @@ contract StataTokenV2RescuableTest is BaseTest {
uint256 amount
);

function test_rescuable_shouldRevertForInvalidCaller() external {
deal(tokenList.usdx, address(stataTokenV2), 1 ether);
vm.expectRevert('ONLY_RESCUE_GUARDIAN');
IRescuable(address(stataTokenV2)).emergencyTokenTransfer(
tokenList.usdx,
address(this),
1 ether
);
}

function test_rescuable_shouldTransferAssetsToCollector() external {
deal(tokenList.usdx, address(stataTokenV2), 1 ether);
stataTokenV2.emergencyTokenTransfer(tokenList.usdx, 1 ether);
vm.startPrank(poolAdmin);
stataTokenV2.emergencyTokenTransfer(tokenList.usdx, address(this), 1 ether);
assertEq(IERC20(tokenList.usdx).balanceOf(address(this)), 1 ether);
}

function test_rescuable_shouldWorkForAToken() external {
_fundAToken(1 ether, address(stataTokenV2));
stataTokenV2.emergencyTokenTransfer(aToken, 1 ether);
vm.startPrank(poolAdmin);
stataTokenV2.emergencyTokenTransfer(aToken, address(this), 1 ether);
assertApproxEqAbs(IERC20(aToken).balanceOf(address(this)), 1 ether, 1);
}

function test_rescuable_shouldNotCauseInsolvency(uint256 donation, uint256 stake) external {
Expand All @@ -31,7 +47,8 @@ contract StataTokenV2RescuableTest is BaseTest {
address treasury = IAToken(aToken).RESERVE_TREASURY_ADDRESS();

vm.expectEmit(true, true, true, true);
emit ERC20Rescued(address(this), aToken, treasury, donation);
stataTokenV2.emergencyTokenTransfer(aToken, donation + stake);
emit ERC20Rescued(poolAdmin, aToken, address(this), donation);
vm.startPrank(poolAdmin);
stataTokenV2.emergencyTokenTransfer(aToken, address(this), donation + stake);
}
}

0 comments on commit 13caab8

Please sign in to comment.