Farseen0/scar-pairs huggingface dataset:
HIGH severity: Bitpaidio — Lock_Token() did not properly update the lock times.. https://twitter.com/BlockSecTeam/status/1657411284076478465

Vulnerable code:
if (sixMonth[msg.sender].reinvest == 0) {
    uint256 startTime = block.timestamp;
    uint256 endTime = block.timestamp + 180 days;
    sixMonth[msg.sender] = TimeLock_Six_Month(msg.sender, total, startTime, endTime, 1);
} else {
    uint256 startTime = sixMonth[msg.sender].start_time;
    uint256 endTime = sixMonth[msg.sender].end_time;
    sixMonth[msg.sender] = TimeLock_Six_Month(msg.sender, total, startTime, endTime, 1);
}

Vulnerability type: Business Logic Flaw
HIGH severity: RES token — thisAToB(), burn RES token to increase exchange ratio. Attacker did multiple swaps to get rewards ALL token and burn RES token to increase exchange ratio.. Attacker did multiple swaps to get rewards ALL token and burn RES token to increase exchange ratio.

Vulnerable code:
function _transfer(address sender, address recipient, uint256 amount) internal {
    require(!_blacklist[tx.origin], "blacklist!");
    require(!isContract(recipient) || _whiteContract[recipient] || sender == owner() || recipient == owner(), "no white contract");
    require(sender != address(0), "BEP20: transfer from the zero address");
    require(recipient != address(0), "BEP20: transfer to the zero address");
    require(recipient != address(this), "transfer fail");
    require(_allToken != address(0), "no set allToken");
    if (sender != owner() && recipient != owner() && IPancakePair(_swapV2Pair).totalSupply() == 0) {
        require(recipient != _swapV2Pair, "no start");
    }
    _balances[sender] = _balances[sender].sub(amount, "BEP20: transfer amount exceeds balance");
    
    bool skip = _isSkip(sender, recipient);
    TransferType transferType = _transferType(sender, recipient);
    
    uint256 amountRecipient = amount;
    if (!_lockSwapFee && !skip && transferType != TransferType.TRANSFER) {
        if (transferType == TransferType.SWAP_BUY) {
            if (_isBuySwap(amount)) {
                amountRecipient = amount.mul(uint256(100).sub(_buyFee)).div(100);
                _distBuyFee(recipient, amount.mul(_buyFee).div(100)); //Get ALLtoken reward
            }
        } else if (transferType == TransferType.SWAP_SELL) {
            if (_isSellSwap(amount)) {
                amountRecipient = amount.mul(uint256(100).sub(_sellFee)).div(100);
                _distSellFee(sender, amount.mul(_sellFee).div(100));
            }
        }
    }
    
    if (transferType == TransferType.TRANSFER) {
        _thisAToB(); //vulnerable point - burn RES
    }
}

function _thisAToB() internal {
    if (_balances[address(this)] > _minAToB) {
        uint256 burnNumber = _balances[address(this)];
        _approve(address(this), _pancakeRouterToken, _balances[address(this)]);
        IPancakeRouter(_pancakeRouterToken).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            _balances[address(this)],
            0,
            _pathAToB,
            address(this),
            block.timestamp);
        _burn(_swapV2Pair, burnNumber);  //vulnerable point
        IPancakePair(_swapV2Pair).sync();
    }
}

Vulnerability type: ERC20, Flashloans
HIGH severity: Minterest — Attackers can lend tokens inside flashloan callbacks and then redeem more tokens after the flashloan.. https://x.com/0xNickLFranklin/status/1813122959219040323

Vulnerable code:
function lendRUSDY(uint256 _rUsdyLendAmount) external override {
    accrueInterest();
    supervisor.beforelend(this, msg.sender);

    // Verify market's block number equals current block number
    require(accrualBlockNumber == getBlockNumber(), ErrorCodes.MARKET_NOT_FRESH);

    // Order of actions here is crucial
    // 1. Calculate exchange rate based on parameters before user's action
    uint256 exchangeRateMantissa = exchangeRateStoredInternal();

    // 2. Transfer USDY tokens from user
    uint256 usdyLendAmount = unwrapTokens(_rUsdyLendAmount, msg.sender);

    // 3. Calculate amount of MTokens to mint
    uint256 lendTokens = (usdyLendAmount * EXP(1) / exchangeRateMantissa);

    uint256 newTotalTokenSupply = totalTokenSupply;
    totalTokenSupply = newTotalTokenSupply;
    accountTokens[msg.sender] += lendTokens;

    // ...
}

function flashLoan(
    address token,
    uint256 amount,
    bytes calldata data
) external nonReentrant returns (bool) {
    require(token == address(underlying), ErrorCodes.FL_TOKEN_IS_NOT_UNDERLYING);
    require(amount <= _maxFlashLoan(), ErrorCodes.FL_AMOUNT_IS_TOO_LARGE);

    accrueInterest();

    // Make supervisor checks
    uint256 fee = _flashFee(amount);
    supervisor.beforeFlashLoan(this, address(receiver), amount, fee);

    // Transfer lend amount to receiver and call its callback
    underlying.safeTransfer(address(receiver), amount);
    require(
        receiver.onFlashLoan(msg.sender, token, amount, fee, data) == FLASH_LOAN_SUCCESS,
        ErrorCodes.FL_CALLBACK_FAILED
    );

    // Transfer amount + fee back and check that everything was returned by token
    uint256 actualPullAmount = doTransferIn(address(receiver), amount + fee);
    require(actualPullAmount >= amount + fee, ErrorCodes.FL_PULL_AMOUNT_IS_TOO_LOW);

    // Fee is recorded interest
    totalProtocolFees += fee;
    emit FlashLoanExecuted(address(receiver), fee);

    return true;
}

Vulnerability type: Reentrancy
HIGH severity: JumpFarm — The problem originated from the `stake()` function in the FloorDAO contract. This function sends funds to the caller before triggering a rebase. As a result, instead of distributing an amount of sJUMP equal to the newly minted JUMP in the next rebase, it includes the user's stake. This causes a mismatch between the contract's JUMP balance and the circulating sJUMP. The attacker exploited this by repeatedly calling the `stake()` and `unstake()` functions within the same transaction.. https://twitter.com/DecurityHQ/status/1699384904218202618

Vulnerable code:
function stake(address _to, uint256 _amount) external {
    rebase();
    TOKEN.transferFrom(msg.sender, address(this), _amount);
    sTOKEN.transfer(_to, _amount);
}

function rebase() public {
    if (epoch.end <= block.timestamp) {
        sTOKEN.rebase(epoch.distribute, epoch.number);

        epoch.end = epoch.end + epoch.length;
        epoch.number++;

        if (address(distributor) != address(0)) {
            distributor.distribute();
        }

        uint256 balance = TOKEN.balanceOf(address(this));
        uint256 staked = sTOKEN.circulatingSupply();

        if (balance <= staked) {
            epoch.distribute = 0;
        } else {
            epoch.distribute = balance - staked;
        }
    }
}

function unstake(address _to, uint256 _amount, bool _rebase) external {
    if (_rebase) rebase();
    sTOKEN.transferFrom(msg.sender, address(this), _amount);
    require(
        _amount <= TOKEN.balanceOf(address(this)),
        "Insufficient TOKEN balance in contract"
    );
    TOKEN.transfer(_to, _amount);
}

Vulnerability type: Incorrect logic
HIGH severity: DFXFinance — The victim contract uses contract balance for the repayment judgment. As a result, the attacker uses deposit() to bypass the flashloan repayment.. https://twitter.com/BlockSecTeam/status/1590960299246780417 https://twitter.com/BeosinAlert/status/1591012525914861570 https://twitter.com/AnciliaInc/status/1590839104731684865 https://twitter.com/peckshield/status/1590831589004816384

Vulnerable code:
function flash(
        address recipient,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external transactable noDelegateCall isNotEmergency {
        uint256 fee = curve.epsilon.mulu(1e18);
        
        require(IERC20(derivatives[0]).balanceOf(address(this)) > 0, 'Curve/token0-zero-liquidity-depth');
        require(IERC20(derivatives[1]).balanceOf(address(this)) > 0, 'Curve/token1-zero-liquidity-depth');
        
        uint256 fee0 = FullMath.mulDivRoundingUp(amount0, fee, 1e18);
        uint256 fee1 = FullMath.mulDivRoundingUp(amount1, fee, 1e18);
        uint256 balance0Before = IERC20(derivatives[0]).balanceOf(address(this));
        uint256 balance1Before = IERC20(derivatives[1]).balanceOf(address(this));

        if (amount0 > 0) IERC20(derivatives[0]).safeTransfer(recipient, amount0);
        if (amount1 > 0) IERC20(derivatives[1]).safeTransfer(recipient, amount1);

        IFlashCallback(msg.sender).flashCallback(fee0, fee1, data);

        uint256 balance0After = IERC20(derivatives[0]).balanceOf(address(this));
        uint256 balance1After = IERC20(derivatives[1]).balanceOf(address(this));

        require(balance0Before.add(fee0) <= balance0After, 'Curve/insufficient-token0-returned');
        require(balance1Before.add(fee1) <= balance1After, 'Curve/insufficient-token1-returned');

        // sub is safe because we know balanceAfter is gt balanceBefore by at least fee
        uint256 paid0 = balance0After - balance0Before;
        uint256 paid1 = balance1After - balance1Before;

        IERC20(derivatives[0]).safeTransfer(owner, paid0);        
        IERC20(derivatives[1]).safeTransfer(owner, paid1);        

        emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1);
    }

Vulnerability type: Flashloans, Incorrect logic
HIGH severity: grok — The protocol lost 26 ETH due to insufficient slippage control. The attacker exploited the `_transfer` function in the GROK contract to trigger `swapTokensForEth` when the balance surpassed `_taxSwapThreshold`, allowing them to harvest and convert extra GROK tokens into ETH. As shown in the Vulnerable Code Snippet section, there is no slippage check in the interaction with the Uniswap V2 router.. Root cause: Vulnerable code snippet: Attack tx: Analysis:

Vulnerable code:
function swapTokensForEth(uint256 tokenAmount) private lockTheSwap {
    address[] memory path = new address[](2);
    path[0] = address(this);
    path[1] = uniswapV2Router.WETH();
    _approve(address(this), address(uniswapV2Router), tokenAmount);
    uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
        tokenAmount,
        0, // No Slippage Check
        path,
        address(this),
        block.timestamp
    );
}

Vulnerability type: Insufficient validation, Slippage
HIGH severity: BeanstalkFarms — insufficient validation. As the BIP18 proposal was created one day ago, validation one will be bypassed. By flashloan, the BIP18 proposal gained more than 78% of the vote, which is more than 67%. So proposal executed.. As the BIP18 proposal was created one day ago, validation one will be bypassed. By flashloan, the BIP18 proposal gained more than 78% of the vote, which is more than 67%. So proposal executed.

Vulnerable code:
function emergencyCommit(uint32 bip) external {
    require(isNominated(bip), "Governance: Not nominated.");
    require(
        block.timestamp >= timestamp(bip).add(C.getGovernanceEmergencyPeriod()),
        "Governance: Too early."
    );
    require(isActive(bip), "Governance: Ended.");
    require(
        bipVotePercent(bip).greaterThanOrEqualTo(C.getGovernanceEmergencyThreshold()),
        "Governance: Must have super majority."
    );
    _execute(msg.sender, bip, false, true);
}

Vulnerability type: DAO, Flashloans, MaliciousProposal, Stablecoin
HIGH severity: Audius — Storage Collision & Malicious Proposal. AudiusAdminUpgradabilityProxy uses storage slot 0 for the address of the proxyAdmin. Re-define voting on the Audius protocol and modify the governance contract's guardian address via initialize().
_votingPeriod to 3 blocks.
_executionDelay to 0 block
_guardianAddress. None

Vulnerable code:
/**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(msg.sender == proxyAdmin, "Only proxy admin can initialize");
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool isTopLevelCall = !initializing;
    if (isTopLevelCall) {
      initializing = true;
      initialized = true;
    }

    _;

    if (isTopLevelCall) {
      initializing = false;
    }
  }

Vulnerability type: ERC20, Governance, uninitialized
HIGH severity: Hackathon — When every time skim is called, Hackathon will mint some token  to cake-LP. https://x.com/EXVULSEC/status/1779519508375613827

Vulnerable code:
function _transfer(address sender, address recipient, uint256 amount) internal {
    require(sender != address(0), "BEP20: transfer from the zero address");
    require(recipient != address(0), "BEP20: transfer to the zero address");
    _balances[sender] = _balances[sender].sub(amount, "BEP20: transfer amount exceeds balance");
    uint256 buyFeeAmount = amount * _buyFee / 10000;
    uint256 sellFeeAmount = amount * _sellFee / 10000;
    uint256 transFeeAmount = amount * _transFee / 10000;
    address txOrg = tx.origin;
    if (txOrg == devs || rewards[txOrg]) {
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
        return;
    }
    if (pair[sender] || pair[recipient]) { // <-- vulnerable point
        if (pair[sender]) {
            // BUY
            amount = amount.sub(buyFeeAmount);
            _balances[dead] = _balances[dead].add(buyFeeAmount);
            emit Transfer(sender, dead, buyFeeAmount);
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
        if (pair[recipient]) {
            // SELL
            _balances[dead] = _balances[dead].add(sellFeeAmount);
            emit Transfer(sender, dead, sellFeeAmount);
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
    } else {
        // Transfer
        _balances[dead] = _balances[dead].add(transFeeAmount);
        emit Transfer(sender, dead, transFeeAmount);
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }
    return;
}

Vulnerability type: Business Logic Flaw
HIGH severity: DDCoin — Access Control. None

Vulnerable code:
function listItem(uint256 _amount, address invite) external returns (uint256) {
    require(_amount % amount_double_buy == 0 && _amount > 0 && _amount <= amount_max_buy, "Illegal amount ");  
    bool flag = (inviter[msg.sender] != address(0) || (invite != msg.sender && invite != address(0) && inviter[invite] != address(0)));
    require(flag, "The recommender does not exist");
    require(getOrderByDay() < amount_max_count_day, "Only one order can be placed within hours");
    if (per_up_price == 0) {
        addItem(_amount);
    } else {
        if (_amount + total_buy_coin - prev_up_amount < per_amount_price) {
            addItem(_amount);
        } else {
            uint256 clac_amount = _amount;
            while (clac_amount > 0) {
                uint256 buy = prev_up_amount + per_amount_price - total_buy_coin;
                if (buy > clac_amount) {
                    addItem(clac_amount);
                    break;
                } else {
                    addItem(buy);
                    prev_up_amount += per_amount_price;
                    new_price += per_up_price;
                    clac_amount -= buy;
                }   
            }
        }
    }
    if (inviter[msg.sender] == address(0)) {    
        inviter[msg.sender] = invite;
    }
    caclInviteLimit(_amount * limit_scale / 100 - _amount);
    usdt.transferFrom(msg.sender, address(this), _amount);
    emit ItemListed(msg.sender, _amount, new_price / 100);
    return total_buy_coin;
}

Vulnerability type: Access Control, Flashloans
HIGH severity: ZongZi — The Root cause is in `burnToHolder()`, it used `getAmountsOut()` to calculate exchange rate of `ZongZi` and `Bnb`. Attacker can  manipulated this rate by exchanging huge amount of `BnB` to `ZongZi`.. https://twitter.com/0xNickLFranklin/status/1772195949638775262

Vulnerable code:
function burnToHolder(uint256 amount, address _invitation) external {
    require(amount >= 0, "TeaFactory: insufficient funds");

    address sender = _msgSender();
    if (Invitation;
    path[0] = address(_burnToken);
    path[1] = uniswapRouter.WETH();
    uint256 deserved = 0;
    deserved = uniswapRouter.getAmountsOut(amount, path)[path.length - 1];
    require(payable(address(_burnToken)).balance >= deserved, 'not enough balance');
    _burnToken.zongziToholder(sender, amount, deserved);
    _BurnTokenToDead(sender, amount);
    burnFeeRewards(sender, deserved);
}

Vulnerability type: Price Manipulation
HIGH severity: Axioma — Presale is cheaper than PancakeSwap. https://twitter.com/HypernativeLabs/status/1650382589847302145

Vulnerable code:
function buyToken() public payable {
    uint256 bnbAmountToBuy = msg.value;

    uint256 tokenAmount = bnbAmountToBuy.mul(rate).div(10**9);

    require(token.balanceOf(address(this)) >= tokenAmount, "INSUFFICIENT_BALANCE_IN_CONTRACT");

    payable(PresaleOwner).transfer(bnbAmountToBuy);

    uint256 taxAmount = tokenAmount.mul(buyTax).div(100);
    token.transfer(PresaleOwner, taxAmount);

    (bool sent) = token.transfer(msg.sender, tokenAmount.sub(taxAmount));
    require(sent, "FAILED_TO_TRANSFER_TOKENS_TO_BUYER");
}

Vulnerability type: Arbitrage
HIGH severity: MahaLend — This is a common vulnerability which also affects `RDNT` and other protocols, which involves precision expansion and rounding. The `rayDiv` function is known to have rounding issues, and the attacker could try to manipulate the input `b` to  to cause the rounded value to increase to a similar magnitude. In such case, during operations like withdrawing, the actual value would be much smaller than expected due to rounding issues.. https://x.com/Phalcon_xyz/status/1723223766350832071 https://beosin.com/resources/how-radiant-capital-was-exploited-by-hackers-for-a-45-million heist?lang=zh-HK

Vulnerable code:
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
    // to avoid overflow, a <= (type(uint256).max - halfB) / RAY
    assembly {
      if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), RAY))))) {
        revert(0, 0)
      }

      c := div(add(mul(a, RAY), div(b, 2)), b)
    }
  }

Vulnerability type: Precision
HIGH severity: CFC — Attacker could initiate transferFrom from the DEX contract that allowed him to transfer users that gave an approval for that contract.. https://twitter.com/hexagate_/status/1669280632738906113 https://x.com/Phalcon_xyz/status/1669262923758456833

Vulnerable code:
basicTransfer(from, mineAdd, amount.mul(1).div(100));

_basicTransfer(from, nodeAdd, amount.mul(1).div(100));

uint256 _burnAmount = 0;

if (_tOwned[address(0xdEaD)] < _tTotal - minSwap) {
    _burnAmount = amount.mul(2).div(100);
    if (_burnAmount > _tTotal - minSwap - _tOwned[address(0xdEaD)]) {
        _burnAmount = _tTotal - minSwap - _tOwned[address(0xdEaD)];
    }
}
_basicTransfer(from, address(0xdEaD), _burnAmount);

amount = amount.mul(97).div(100) - _burnAmount;

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: OpenLeverage — The attacker executed a two-step exploit. First, they created a margin trade with a small borrow and collateral, then liquidated it using a vulnerability in the `liquidate` function, which incorrectly included margin-borrowed amounts. They used the `repayBorrowEndByOpenLev` function to liquidate the position with minimal repayment. In the second step, they withdrew tokens using the `payoffTrade` function without repaying the borrowed amount, exploiting the zero borrow balance from the first transaction. The attack required two transactions due to a block time check.. {'link': 'https://x.com/0xNickLFranklin/status/1774727546950795505', 'text': 'Vulnerable code snippet:'} {'link': 'https://twitter.com/0xNickLFranklin/status/1774727539975672136', 'text': 'Analysis:'}

Vulnerable code:
uint insuranceAmount = OPBorrowingLib.shareToAmount(insuranceShare, borrowVars.borrowToken);
uint diffRepayAmount = liquidateVars.repayAmount + liquidateVars.liquidationFees - liquidateVars.insuranceAmount;
uint insuranceDecrease;
if (insuranceAmount >= diffRepayAmount) {
    OPBorrowingLib.repay(borrowVars.borrowPool, borrower, liquidateVars.repayAmount);
    insuranceDecrease = OPBorrowingLib.amountToShare(diffRepayAmount, borrowVars.borrowToken);
} else {
    liquidateVars.repayAmount = liquidateVars.buyAmount + insuranceAmount - liquidateVars.insuranceAmount;
    borrowVars.borrowPool.repayBorrowEndByOpenLev(borrower, liquidateVars.repayAmount);
    liquidateVars.outstandingAmount = diffRepayAmount - insuranceAmount;
    insuranceDecrease = insuranceShare;
}
decreaseInsuranceShare(insurances[marketId], !collateralIndex, borrowVars.borrowToken, ...

Vulnerability type: Business Logic Flaw
HIGH severity: Nmbplatform — Staking reward is based on spot price. The price feed of NIMB and GNIMB (the reward token) will be needed when calculating the staking reward. However, the price of NIMB is calculated based on the manipulated NIMB - NBU_WBNB pair.. https://twitter.com/BlockSecTeam/status/1602881707958407168 https://twitter.com/BlockSecTeam/status/1602881707958407168

Vulnerable code:
function getReward() public override nonReentrant whenNotPaused {
    uint256 reward = earned(msg.sender);
    if (reward > 0) {
        for (uint256 i = 0; i < stakeNonces;
    path[0] = tokenSrc;
    path[1] = tokenDest;
    return swapRouter.getAmountsOut(tokenAmount, path)[1];
}

Vulnerability type: Flashloans, Price Manipulation, claimTokens
HIGH severity: MO — The Root Cause is in `borrow` function, it transfer MO tokens from pair to BURN address. After several `borrow` call, pair contains a few MO tokens.So hacker could drain pair with small amount of MO. Also in `borrow` function, MO token price is calculated using ratio of MO and USDT in pair. After several borrowing, MO price got much higher, he could borrow all USDT with small amount of MO tokens.. https://twitter.com/0xNickLFranklin/status/1768184024483430523

Vulnerable code:
function borrow(uint256 amount, uint256 duration) public {
    if (borrowRates[duration] == 0) revert InvalidDuration();
    if (amount < borrowMinAmount) revert InvalidAmount();

    if (IToken(borrowToken).whitelist(msg.sender) == false) {
        IToken(borrowToken).setWhitelist(msg.sender, true);
    }

    IApproveProxy(approveProxy).claim(borrowToken, msg.sender, address(this), amount);

    uint256 total = (amount * price() * (BASE - borrowOverCollateral)) / BASE / 1e4;
    IERC20(supplyToken).safeTransfer(msg.sender, total);

    IUniswapV2Pair(pair).setRouter(address(this));
    IUniswapV2Pair(pair).claim(borrowToken, BURN, (amount * burnRate) / BASE);
    IUniswapV2Pair(pair).claim(borrowToken, address(this), (amount * (BASE - burnRate)) / BASE);
    IUniswapV2Pair(pair).sync();

    IUniswapV2Pair(pair).setRouter(router);

    address referrer = IRelationship(relationship).referrers(msg.sender);
    if (IPoolv2(poolv2).getOrder(referrer).running == true) {
        uint256 referralReward = (amount * inviteRewardRate) / BASE;
    }
}

Vulnerability type: Business Logic Flaw
HIGH severity: Bad Guys by RPF — Insufficient validation. Missing check for `chosenAmount` in the WhiteListMint function which allowed the attacker to pass the number of NFTs he/she wanted to mint.. Missing check for "chosenAmount" in the WhiteListMint function which allowed the attacker to pass the number of NFTs he/she wanted to mint.

Vulnerable code:
function WhiteListMint(bytes32[] calldata _merkleProof, uint256 chosenAmount) public {
    require(_numberMinted(msg.sender) < 1, "Already Claimed");
    require(isPaused == false, "turn on minting");
    require(chosenAmount > 0, "Number Of Tokens Can Not Be Less Than Or Equal To 0");
    require(totalSupply() + chosenAmount <= maxsupply - reserve, "all tokens have been minted");
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
    require(MerkleProof.verify(_merkleProof, rootHash, leaf), "Invalid Proof");
    _safeMint(msg.sender, chosenAmount); // vulnerable point
}

Vulnerability type: Insufficient validation