# Attackathon \_ Fuel Network 33170 - \[Smart Contract - Medium] UFP Exp In Sway-lib Logic Vulnerability

Submitted on Sat Jul 13 2024 10:02:26 GMT-0400 (Atlantic Standard Time) by @Minato7namikazi for [Attackathon | Fuel Network](https://immunefi.com/bounty/fuel-network-attackathon/)

Report ID: #33170

Report type: Smart Contract

Report severity: Medium

Target: <https://github.com/FuelLabs/sway-libs/tree/0f47d33d6e5da25f782fc117d4be15b7b12d291b>

Impacts:

* Permanent freezing of funds

## Description

## Brief/Intro

During my audit of the UFP (unsigned fixed-point number) implementations in the sway-libs , this logic vulnerability were identified. This could lead to incorrect calculations in any smart contracts or scripts relying on this function and cause massive losses.

## Vulnerability Details

```
impl Exponent for UFP128 {
    fn exp(exponent: Self) -> Self {
        let one = UFP128::from((1, 0));
        let p2 = one / UFP128::from((2, 0));
        let p3 = one / UFP128::from((6, 0));
        let p4 = one / UFP128::from((24, 0));
        let p5 = one / UFP128::from((120, 0));
        let p6 = one / UFP128::from((720, 0));
        let p7 = one / UFP128::from((5040, 0));

        // common technique to counter losing sugnifucant numbers in usual approximation
        let _res_minus_1 = exponent + exponent * exponent * (p2 + exponent * (p3 + exponent * (p4 + exponent * (p5 + exponent * (p6 + exponent * p7)))));
        let res = one;
        res
    }
}
```

### The function calculates `_res_minus_1` correctly .. but then it ignores this calculation and simply returns `one`. This means the exponential function will always return 1, regardless of the input.

### The impact is Loss of funds because of

* Incorrect Financial Calculations : using the vulnerable exponential function for compound interest, option pricing, or yield calculations. With this bug, all such calculations would return 1, regardless of the input.
* Some token distribution models or staking rewards systems use exponential decay or growth. This bug would make such systems non-functional, potentially: Distributing incorrect amounts of tokens

### Recommendation

we should use the calculated result like

```rust

impl Exponent for UFP128 {
    fn exp(exponent: Self) -> Self {
        let one = UFP128::from((1, 0));
        let p2 = one / UFP128::from((2, 0));
        let p3 = one / UFP128::from((6, 0));
        let p4 = one / UFP128::from((24, 0));
        let p5 = one / UFP128::from((120, 0));
        let p6 = one / UFP128::from((720, 0));
        let p7 = one / UFP128::from((5040, 0));

        // Common technique to counter losing significant numbers in usual approximation
        let res_minus_1 = exponent + exponent * exponent * (p2 + 
                         exponent * (p3 + exponent * (p4 + 
                         exponent * (p5 + exponent * (p6 + 
                         exponent * p7)))));

        one + res_minus_1
    }
}

```

* Now it's calculates the exponential function using a Taylor series approximation and should return the correct result. the function now adds 1 to the calculated `res_minus_1` to get the final result, as the original calculation was for (e^x - 1).

## Proof of concept

## Add this PoC test in the end of the ufp128.sw

```

#[test]
fn PoC_exp() {


    let one = UFP128::from_uint(1);
    let res = UFP128::exp(one);
    assert(res == UFP128::from((1, 0)));


    let two = UFP128::from_uint(2);
    let res = UFP128::exp(two);
    assert(res == UFP128::from((1, 0)));


    let three = UFP128::from_uint(3);
    let res = UFP128::exp(three);
    assert(res == UFP128::from((1, 0)));


    let four = UFP128::from_uint(4);
    let res = UFP128::exp(four);
    assert(res == UFP128::from((1, 0)));


    let five = UFP128::from_uint(5);
    let res = UFP128::exp(five);
    assert(res == UFP128::from((1, 0)));


    let six = UFP128::from_uint(6);
    let res = UFP128::exp(six);
    assert(res == UFP128::from((1, 0)));


    let seven = UFP128::from_uint(7);
    let res = UFP128::exp(seven);
    assert(res == UFP128::from((1, 0)));


    let eight = UFP128::from_uint(8);
    let res = UFP128::exp(eight);
    assert(res == UFP128::from((1, 0)));


    let nine = UFP128::from_uint(9);
    let res = UFP128::exp(nine);
    assert(res == UFP128::from((1, 0)));


}
```
