Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Latest commit

 

History

History
167 lines (133 loc) · 5.41 KB

009.md

File metadata and controls

167 lines (133 loc) · 5.41 KB

Bnke0x0

medium

sellPrincipalToken, buyPrincipalToken, sellUnderlying, buyUnderlying uses pool funds but pays msg.sender

Summary

Vulnerability Detail

sellPrincipalToken, buyPrincipalToken, sellUnderlying, buyUnderlying are all unpermissioned and use marketplace funds to complete the action but send the resulting tokens to msg.sender. This means that any address can call these functions and steal the resulting funds.

Impact

Fund loss from the marketplace

Code Snippet

https://github.com/sherlock-audit/2022-10-illuminate/blob/main/src/Marketplace.sol#L285-L425

       'function sellPrincipalToken(
    address u,
    uint256 m,
    uint128 a,
    uint128 s
) external returns (uint128) {
    // Get the pool for the market
    IPool pool = IPool(pools[u][m]);

    // Preview amount of underlying received by selling `a` PTs
    uint256 expected = pool.sellFYTokenPreview(a);

    if (expected < s) {
        revert Exception(16, expected, s, address(0), address(0));
    }

    // Transfer the principal tokens to the pool
    Safe.transferFrom(
        IERC20(address(pool.fyToken())),
        msg.sender,
        address(pool),
        a
    );

    // Execute the swap
    uint128 received = pool.sellFYToken(msg.sender, uint128(expected));
    emit Swap(u, m, address(pool.fyToken()), u, received, a, msg.sender);

    return received;
}

/// @notice buys the PT for the underlying via the pool
/// @notice determines how many underlying to sell by using the preview
/// @param u address of an underlying asset
/// @param m maturity (timestamp) of the market
/// @param a amount of PTs to be purchased
/// @param s slippage cap, maximum number of underlying that can be sold
/// @return uint128 amount of underlying sold
function buyPrincipalToken(
    address u,
    uint256 m,
    uint128 a,
    uint128 s
) external returns (uint128) {
    // Get the pool for the market
    IPool pool = IPool(pools[u][m]);

    // Get the amount of base hypothetically required to purchase `a` PTs
    uint128 expected = pool.buyFYTokenPreview(a);

    // Verify that the amount needed does not exceed the slippage parameter
    if (expected > s) {
        revert Exception(16, expected, 0, address(0), address(0));
    }

    // Transfer the underlying tokens to the pool
    Safe.transferFrom(
        IERC20(pool.base()),
        msg.sender,
        address(pool),
        expected
    );

    // Execute the swap to purchase `a` base tokens
    uint128 spent = pool.buyFYToken(msg.sender, a, 0);
    emit Swap(u, m, u, address(pool.fyToken()), a, spent, msg.sender);

    return spent;
}

/// @notice sells the underlying for the PT via the pool
/// @param u address of an underlying asset
/// @param m maturity (timestamp) of the market
/// @param a amount of underlying to sell
/// @param s slippage cap, minimum number of PTs that must be received
/// @return uint128 amount of PT purchased
function sellUnderlying(
    address u,
    uint256 m,
    uint128 a,
    uint128 s
) external returns (uint128) {
    // Get the pool for the market
    IPool pool = IPool(pools[u][m]);

    // Get the number of PTs received for selling `a` underlying tokens
    uint128 expected = pool.sellBasePreview(a);

    // Verify slippage does not exceed the one set by the user
    if (expected < s) {
        revert Exception(16, expected, 0, address(0), address(0));
    }

    // Transfer the underlying tokens to the pool
    Safe.transferFrom(IERC20(pool.base()), msg.sender, address(pool), a);

    // Execute the swap
    uint128 received = pool.sellBase(msg.sender, expected);

    emit Swap(u, m, u, address(pool.fyToken()), received, a, msg.sender);
    return received;
}

/// @notice buys the underlying for the PT via the pool
/// @notice determines how many PTs to sell by using the preview
/// @param u address of an underlying asset
/// @param m maturity (timestamp) of the market
/// @param a amount of underlying to be purchased
/// @param s slippage cap, maximum number of PTs that can be sold
/// @return uint128 amount of PTs sold
function buyUnderlying(
    address u,
    uint256 m,
    uint128 a,
    uint128 s
) external returns (uint128) {
    // Get the pool for the market
    IPool pool = IPool(pools[u][m]);

    // Get the amount of PTs hypothetically required to purchase `a` underlying
    uint256 expected = pool.buyBasePreview(a);

    // Verify that the amount needed does not exceed the slippage parameter
    if (expected > s) {
        revert Exception(16, expected, 0, address(0), address(0));
    }

    // Transfer the principal tokens to the pool
    Safe.transferFrom(
        IERC20(address(pool.fyToken())),
        msg.sender,
        address(pool),
        expected
    );

    // Execute the swap to purchase `a` underlying tokens
    uint128 spent = pool.buyBase(msg.sender, a, 0);

    emit Swap(u, m, address(pool.fyToken()), u, a, spent, msg.sender);
    return spent;
}

'

Tool used

Manual Review

Recommendation

All functions should use safetransfer to get funds from msg.sender not from marketplace