xanoutas/solidity-security-findings huggingface dataset:
Incorrect Calculation of Tier Odds in `getTierOdds` Function.
Audit: 2023-07-pooltogether-findings
Severity: HIGH

# Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/TierCalculationLib.sol#L17-L27
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/TierCalculationLib.sol#L26


# Vulnerability details

## Impact
**Risk Breakdown:**
The incorrect calculation of tier odds can have several implications:

1. The incorrect odds can lead to imbalances in the prize distribution among different tiers. Some tiers may receive more or fewer prizes than intended, impacting the fairness of the system.

2. Inaccurate prize distributions can erode user trust in the platform. Users may perceive the system as unfair or unreliable, leading to a negative impact on the platform's reputation.

3. If the incorrect odds result in significant imbalances in prize distributions, participants may experience financial losses if they expected a different probability of winning.


## Proof of Concept
[TierCalculationLib.sol#L17-L27](https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/TierCalculationLib.sol#L17-L27)
```solidity
  function getTierOdds(
    uint8 _tier,
    uint8 _numberOfTiers,
    uint16 _grandPrizePeriod
  ) internal pure returns (SD59x18) {
    SD59x18 _k = sd(1).div(sd(int16(_grandPrizePeriod))).ln().div(
      sd((-1 * int8(_numberOfTiers) + 1))
    );


    return E.pow(_k.mul(sd(int8(_tier) - (int8(_numberOfTiers) - 1))));
  }
```
The getTierOdds function calculates the odds of a tier occurring for a single draw. However, there is a bug in the calculation of the exponentiation. The line [`E.pow(_k.mul(sd(int8(_tier) - (int8(_numberOfTiers) - 1))));`](https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/TierCalculationLib.sol#L26) should be `E.pow(_k.mul(sd(int8(_tier) - int8(_numberOfTiers) + 1)));`. The incorrect calculation could lead to incorrect odds for each tier, resulting in inaccurate prize distributions.

To prove the bug, we can use a simple example. Let's assume `_tier = 2`, `_numberOfTiers = 3`, and `_grandPrizePeriod = 10`. We can calculate the expected odds manually:

```solidity
_k = sd(1).div(sd(int16(10))).ln().div(sd((-1 * int8(3) + 1))) = ...

_expectedOdds = E.pow(_k.mul(sd(int8(2) - (int8(3) - 1)))) = ...
```

By fixing the calculation, we should get the expected odds. Let's demonstrate this:

```solidity
_k = sd(1).div(sd(int16(10))).ln().div(sd((-1 * int8(3) + 1))) = ...

_fixedOdds = E.pow(_k.mul(sd(int8(2) - int8(3) + 1))) = ...
```

Implementation of the proof:

```solidity
pragma solidity 0.8.17;

import { E, SD59x18, sd, unwrap, toSD59x18, fromSD59x18, ceil } from "prb-math/SD59x18.sol";

contract TierCalculationLibProof {
  function calculateExpectedOdds() external pure returns (SD59x18) {
    SD59x18 _k = sd(1).div(sd(int16(10))).ln().div(sd((-1 * int8(3) + 1)));
    return
Invalid Draw Range Vulnerability in getDisbursedBetween, the subsequent check for `_endDrawId < drawIds.first`.
Audit: 2023-07-pooltogether-findings
Severity: HIGH

# Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/DrawAccumulatorLib.sol#L173
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/DrawAccumulatorLib.sol#L166-L307


# Vulnerability details

## Impact
An attacker can bypass the check for a valid draw range and potentially manipulate the calculation of the disbursed balance, by providing an invalid draw range, an attacker could trick the contract into returning an incorrect disbursed balance or cause the contract to revert unexpectedly.

## Proof of Concept
Error `InvalidDrawRange` is emitted in the `getDisbursedBetween` function of the `DrawAccumulatorLib` library when a draw range is not strictly increasing,the specific line of code where the error is emitted:

[DrawAccumulatorLib.sol#L173](https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/DrawAccumulatorLib.sol#L173)
```solidity
revert InvalidDrawRange(_startDrawId, _endDrawId);
```
This code line is triggered when the `_startDrawId` provided as input is greater than the `_endDrawId`, indicating that the draw range is not in ascending order. The `InvalidDrawRange` error is emitted to indicate this invalid condition.

In the `getDisbursedBetween` function, the vulnerability allows an attacker to retrieve the disbursed balance between a start and end draw ID, even if the end draw ID is not within the expected range. This can lead to incorrect disbursed balance calculations and potential exploitability.

Affected Code Block: [DrawAccumulatorLib.sol#L166-L](https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/DrawAccumulatorLib.sol#L166-L307)
```solidity
function getDisbursedBetween(
    Accumulator storage _accumulator,
    uint16 _startDrawId,
    uint16 _endDrawId,
    SD59x18 _alpha
) internal view returns (uint256) {
    // ...

    // This check intentionally limits the `_endDrawId` to be no more than one draw before the latest observation.
    // This allows us to make assumptions on the value of `lastObservationDrawIdOccurringAtOrBeforeEnd`
    // and removes the need for an additional binary search to find it.
    if (_endDrawId < drawIds.second - 1) {
        revert InvalidDisbursedEndDrawId(_endDrawId);
    }

    // ...

    // if a "body" exists
    if (
        firstObservationDrawIdOccurringAtOrAfterStart > 0 &&
        firstObservationDrawIdOccurringAtOrAfterStart < lastObservationDrawIdOccurringAtOrBeforeEnd
    ) {
        Observation memory atOrAfterStart = _accumulator.observations[firstObservationDrawIdOccurringAtOrAfterStart];
        Observation memory atOrBeforeEnd = _accumulator.observations[lastObservationDrawIdOccurringAtOrBeforeEnd];
        uint amount = atOrBeforeEnd.disbursed - atOrAfterStart.disbursed;
        total += amount;
    }

    // ...

    r
When expanding the number of tiers during a new draw, the prizeTokenPerShare of the new Tiers is not the right one
Audit: 2023-07-pooltogether-findings
Severity: HIGH

# Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/abstract/TieredLiquidityDistributor.sol#L361-L366


# Vulnerability details

## Impact
New created tiers will have the wrong prizeTokenPerShare

## Proof of Concept
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/abstract/TieredLiquidityDistributor.sol#L361-L366

## Tools Used
VSC

## Recommended Mitigation Steps
Line 364, set 'newPrizeTokenPerShare' instead of 'prizeTokenPerShare' as the new Tier prizeTokenPerShare.


## Assessed type

Error
Upgraded Q -> 2 from #93 [1689707967381]
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

Judge has assessed an item in Issue #93 as 2 risk. The relevant finding follows:

 [L-01] - no check on the deployedVaults mapping in the VaultFactory can lead to duplicate vaults being created
Mitigation - add an if check to not recreate the same vault:  if(deployedVaults[_vault]) revert....
Upgraded Q -> 2 from #392 [1689707598962]
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

Judge has assessed an item in Issue #392 as 2 risk. The relevant finding follows:

 4 - The liquidator can be frontrunned while is depositing prizeTokens to the prizePool
The liquidator should introduce prizeTokens to the prizePool before he calls the Vault.liquidate() function. The problem is that a malicious actor can be frontrunned and make the introduced prizeTokens to be accumulated to another vault. The liquidator can lost his prizeTokens.
Upgraded Q -> 2 from #422 [1689707351452]
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

Judge has assessed an item in Issue #422 as 2 risk. The relevant finding follows:

 [01] In the function PrizePool.setDrawManager(), anyone can frontrun it and become the drawManager
Reading the documentation of the Prize Pool contract, the following is specified: The Prize Pool allows a 'draw manager' contract to complete the Draw and withdraw tokens from the reserve. In the code, on line 296, it is specified that the PrizePool.setDrawManager() function Allows a caller to set the DrawManager if not already set. This function is not protected in cases where a malicious attacker wants to front-run and take control of the draw manager permissions.

PROOF OF CONCEPT
PoolTogether docs link :

The Prize Pool allows a "draw manager" contract to complete the Draw and withdraw tokens from the reserve.
Malicious Yield Vault could deny Pool Together withdrawing assets
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L254


# Vulnerability details

## Impact
Since vaults can be created by anyone as long as they provide an ERC-4626 compliant yield source, an attacker could set up a malicious ERC-4626 contract and set that as the yield source for a newly created Vault. The attacker could then have the malicious contract use revert whenever a withdraw call is made to it.

## Proof of Concept
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L254

## Tools Used
Manual Review

## Recommended Mitigation Steps


## Assessed type

DoS
withdrawReserve will revert when withdrawing tokens with on chain tx fees
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L339


# Vulnerability details

## Impact
Function will revert when _reserve is equal to _amount, when the token being transferred is a fee on transfer token.

## Proof of Concept
 function withdrawReserve(
        address _to,
        uint104 _amount
    ) external onlyDrawManager {
        function withdrawReserve(
        address _to,
        uint104 _amount
    ) external onlyDrawManager {
        if (_amount > _reserve) {
            revert InsufficientReserve(_amount, _reserve);
        }
        _reserve -= _amount;
        _transfer(_to, _amount); {
            revert InsufficientReserve(_amount, _reserve);
        }
        _reserve -= _amount;
        _transfer(_to, _amount);


Let's say _reserve is is 5 and _amount is 5 when you subtract, the balance will be zero but since the token is a fee on transfer token it will revert since you're trying to send exactly  all the tokens out.

## Tools Used
Manual review 
## Recommended Mitigation Steps

Change the  function  if (_amount > _reserve) to >= or implement another mitigation step that checks for fee on transfer


## Assessed type

Token-Transfer
IF THE UNDERLYING ASSET IS A FEE ON TRANSFER TOKEN IT COULD BREAK THE INTERNAL ACCOUNTING OF THE VAULT
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L951-L956
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L959
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1026-L1027


# Vulnerability details

## Impact
The `Vault._deposit` function is used by the users to deposit `_assets` to the vault and mint vault shares to the `recipient` address. The amount of `_assets` are transferred to the `Vault` as follows:

      SafeERC20.safeTransferFrom(
        _asset,
        _caller,
        address(this),
        _assetsDeposit != 0 ? _assetsDeposit : _assets
      );

The `Vault.deposit` function uses this `_assets` amount to calculate the number of `shares` to be minted to the `_recipient` address.

The issue here is if the underlying `_asset` is a fee on transfer token then the actual received amount to the vault will be less than what is referred in the `Vault.deposit` function `_assets` input parameter. But the shares to mint is calculated using the entire `_assets` amount.

This issue could be further aggravated since the `_asset` is again `deposited` to the `_yieldVault` and when needing to be redeemed will be `withdrawn` from the `_yieldVault` as well. These operations will again charge a fee if the `_asset` is a fee on transfer token. Hence the actual left `_asset` amount for particular user will be less than the amount he initially transferred in.

Hence when the user `redeems` the minted shares back to the `_assets`, the contract will not have enough assets to transfer to the `redeemer` thus reverting the transaction. 

## Proof of Concept

```solidity
      SafeERC20.safeTransferFrom(
        _asset,
        _caller,
        address(this),
        _assetsDeposit != 0 ? _assetsDeposit : _assets
      );
```

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L951-L956

```solidity
    _yieldVault.deposit(_assets, address(this));
```

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L959

```solidity
    _yieldVault.withdraw(_assets, address(this), address(this));
    SafeERC20.safeTransfer(IERC20(asset()), _receiver, _assets);
```

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1026-L1027

## Tools Used
Manual Review and VSCode

## Recommended Mitigation Steps

Hence it is recommended to compute the `_assets` amount balance of the contract before and after the `safeTransferFrom` call and get the difference between the two as the actually transferred amount to the `Vault`. Then this actually transferred amount can be converted to shares and mint the correct amount of shares to the `recipient`.

```solidity
  uint256 balanceBefore = _asset.balanceOf(address(this));
Permit does not revert for tokens that do not implement it.
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L435
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L468


# Vulnerability details

## Impact
Callers should not rely on `permit` to revert for arbitrary tokens especially if `permit` is used as a security check. Tokens which do not revert on `permit` either do not implement it or have a non-reverting fallback function. Most notable among them is WETH. In the case of Pool Together, `permit` is used to allow the vault to make deposit's on behalf of users but this call will always fail because the approval part of the `permit` is never executed, thereby bricking a main functionality of the protocol. 
 

## Proof of Concept
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1103
More details on this kind of vulnerability can be found [here](https://media.dedaub.com/phantom-functions-and-the-billion-dollar-no-op-c56f062ae49f?gi=267df0286765)

## Tools Used
Manual Review

## Recommended Mitigation Steps


## Assessed type

ERC20
_winningRandomNumber vartiable used in calculating if caller is winner can be read via web3.getStorageAt() and user can predict if he wins or not before hand
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L237


# Vulnerability details

## Impact
the variable _winningRandomNumber used in isWinner() to calc if caller has won the tier can be read, and the calculation can be predicted. 

## Proof of Concept
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L237C41-L237C41


that a variable is marked internal doesnt mean it cannot be read

## Tools Used
vs code
## Recommended Mitigation Steps
find better ways to do the determination of the winner 


## Assessed type

Other
Unintended or Malicious Use of Prize Winners' Hooks
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L653
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1053
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L1068


# Vulnerability details

## Impact
The setHooks function in Vault.sol allows users to set arbitrary hooks, potentially enabling them to make external calls with unintended consequences. This vulnerability could lead to various unexpected behaviors, such as unauthorized side transactions with gas paid unbeknownst to the claimer, reentrant calls, or denial-of-service attacks on claiming transactions.

[Vault.sol#L653](https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L653)
```solidity
function setHooks(VaultHooks memory hooks) external {
    _hooks[msg.sender] = hooks; 

    emit SetHooks(msg.sender, hooks);
  }
```

## Proof of Concept
Consider the following side contract and malicious hook implementation:

Side Contract:
```solidity
// SPDX-License_Identifier: MIT
pragma solidity 0.8.17;

import "forge-std/console.sol";

contract SideContract {
  uint256 public codex;

  function execute() external {
    codex = 1;
    console.log("Entered side contract");
  }
}
```

Malicious Hook:
```solidity
// SPDX-License_Identifier: MIT
pragma solidity 0.8.17;

import { SideContract } from "./SideContract.sol";

contract ViciousHook {
  SideContract public sideContract = new SideContract();

  function beforeClaimPrize(
    address winner,
    uint8 tier,
    uint32 prizeIndex
  ) external returns (address) {
    sideContract.execute();

    return address(this);
  }
}
```

Modified Test File:
```diff
diff --git a/test/unit/Vault/Vault.t.sol b/test/unit/Vault/Vault.t.sol
index d0d6d30..65caca1 100644
--- a/test/unit/Vault/Vault.t.sol
+++ b/test/unit/Vault/Vault.t.sol
@@ -4,6 +4,7 @@ pragma solidity 0.8.17;
 import { UnitBaseSetup, LiquidationPair, PrizePool, TwabController, VaultMock, ERC20, IERC20, IERC4626 } from "test/utils/UnitBaseSetup.t.sol";
 import { IVaultHooks, VaultHooks } from "../../../src/interfaces/IVaultHooks.sol";
 import "src/Vault.sol";
+import { ViciousHook } from "./ViciousHook.sol";
 
 contract VaultTest is UnitBaseSetup {
   /* ============ Events ============ */
@@ -174,6 +175,25 @@ contract VaultTest is UnitBaseSetup {
     vm.stopPrank();
   }
 
+  function testClaimPrize_viciousHook() public {
+    ViciousHook viciousHook = new ViciousHook();
+    vm.startPrank(alice);
+    VaultHooks memory hooks = VaultHooks({
+      useBeforeClaimPrize: true,
+      useAfterClaimPrize: false,
+      implementation: IVaultHooks(address(viciousHook))
+    });
+    vault.setHooks(hooks);
+    vm.stopPrank();
+
+    vm.startPrank(address(claimer));
+
+    mockPrizePoolClaimPrize(uint8(1), alice, 0, address(viciousHook), 1e18, addr
`TwabLib::getTwabBetween` can return innacurate balances if `_startTime` and `_endTime` aren't safely bounded
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L920, https://github.com/GenerationSoftware/pt-v5-twab-controller/blob/0145eeac23301ee5338c659422dd6d69234f5d50/src/libraries/TwabLib.sol#L281, https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L429


# Vulnerability details

## M-01 `TwabLib::getTwabBetween` can return innacurate balances if `_startTime` and `_endTime` aren't safely bounded

## Vulnerability details
Here's the documentation of the get `TwabLib::getTwabBetween` function :

```solidity
File: twab-controller\src\libraries\TwabLib.sol

278:   /**
279:    * @notice Looks up a users TWAB for a time range.
280:    * @dev If the timestamps in the range are not exact matches of observations, the balance is extrapolated using the previous observation.
281:    * @dev Ensure timestamps are safe using isTimeRangeSafe.
282:    * @param _observations The circular buffer of observations
283:    * @param _accountDetails The account details to query with
284:    * @param _startTime The start of the time range
285:    * @param _endTime The end of the time range
286:    * @return twab The TWAB for the time range
287:    */
288:   function getTwabBetween(  //@audit - M01: dev comment (isTimeRangeSafe) doesn't seems to be followed in PrizePool calling it
289:     uint32 PERIOD_OFFSET,
290:     ObservationLib.Observation[MAX_CARDINALITY] storage _observations,
291:     AccountDetails memory _accountDetails,
292:     uint32 _startTime,
293:     uint32 _endTime
294:   ) internal view returns (uint256) {
```

`TwabLib::getTwabBetween` function get called in `PrizePool::_getVaultUserBalanceAndTotalSupplyTwab`, which itself get called by `PrizePool::claimPrize` returning twab for a specified time-range, which finally is called by `PrizePool::isWinner` in `PrizePool::claimPrize`.

The thing is, as well explained by [the documentation](https://v4.docs.pooltogether.com/protocol/next/design/twab-controller/#sample-loss-of-historic-information), values from balance history isn't guaranteed to be accurate the if timestamp at which it is queried time do not fall between :
- (or at) the newest observation in a period
- and the end of that period (period must have ended)

That is because, until a period has ended we cannot be sure the value we are querying haven't changed in the future (from pov of the timestamp)

 ### Impact

This means that if a prize is claimed, but timestamps at which the twab is getting requested do not follow these rules, the Prize Pool contract might distribute prizes based on inaccurate data. This could lead to prizes being distributed to users who should not have won, or not being distributed to users who should have won.

```solidity
File: prize-pool\src\PrizePool.sol

920:   function _getVaultUserBalanceAndTotalSupplyTwab(
921:     address _vault,
922:     address _user,
923:     uint25
Vault funds can be stolen by a malicious Yield Vault.
Audit: 2023-07-pooltogether-findings
Severity: MEDIUM

# Lines of code

https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L282


# Vulnerability details

## Impact
When a vault is initialized, it sets Max Token Approval for the Yield Vault which allows the Yield Vault to ALWAYS have access to the funds in the vault. Since vaults can be created by anyone as long as they provide an ERC-4626 compliant yield source, an attacker could set up a malicious ERC-4626 contract and set that as the yield source for a newly created Vault. The attacker could then have the malicious contract use SafeTransferFrom to periodically empty the vault of assets that haven't yet been sent to the malicious yield vault.

## Proof of Concept
https://github.com/GenerationSoftware/pt-v5-vault/blob/b1deb5d494c25f885c34c83f014c8a855c5e2749/src/Vault.sol#L282

## Tools Used
Manual review

## Recommended Mitigation Steps
Vaults should only approve tokens when they are being transferred out.


## Assessed type

Token-Transfer