#MissingValue error

13 messages · Page 1 of 1 (latest)

autumn vale
#

Hi all!

After moving some of the storage handling logic to Env extension, I am now getting missing value errors that I can't solve. There is no errors and everything builds, but it doesn't work. The error comes after calling function deposit() and the error states that the key accessed that doesn't have a value is Positions, Address.

fn deposit(e: Env, user: Address, amount: i128) -> Positions {
        user.require_auth(); // Depositor needs to authorize the deposit
        assert!(amount > 0, "Amount must be positive!");

        e.extend_instance_rent();

        let client = token::Client::new(&e, &e.get_currency().token_address);
        client.transfer(&user, &e.current_contract_address(), &amount);

        // TODO: these need to be replaced with increase rather than write so that it wont overwrite the values.
        e.set_total_balance(amount);
        e.set_total_shares(amount);
        e.set_total_balance(amount);

        // Increase users position in pool as they deposit
        // as this is deposit amount is added to receivables and
        // liabilities & collateral stays intact
        let input = PositionsInput {
            receivables: Some(amount),
            liabilities: None,
            collateral: None,
        };

        positions::update_positions(&e, &user, input)
    }

^this is the deposit function it calls update_positions() that looks like this:

#
pub fn update_positions(e: &Env, user: &Address, input: PositionsInput) -> Positions {
    let Positions {
        receivables,
        liabilities,
        collateral,
    } = e.get_positions(user);

    // Calculate the new positions.
    let receivables = input.receivables.map_or(receivables, |r| receivables + r);
    let liabilities = input.liabilities.map_or(liabilities, |l| liabilities + l);
    let collateral = input.collateral.map_or(collateral, |c| collateral + c);

    if receivables < 0 {
        panic!("Insufficient receivables");
    }
    if liabilities < 0 {
        panic!("insufficient liabilities");
    }
    if collateral < 0 {
        panic!("insufficient collateral");
    }

    let new_positions = Positions {
        receivables,
        liabilities,
        collateral,
    };

    e.set_positions(user, &new_positions);

    new_positions
}```
#

And the get_positions() and set_positions() are implemented as extensions to Env as such:

#
pub trait LoanPoolEnvExtensions {
  fn get_positions(&self, user: &Address) -> Positions;

    fn set_positions(&self, user: &Address, positions: &Positions);
}

impl LoanPoolEnvExtensions for Env {
  fn get_positions(&self, user: &Address) -> Positions {
        let key = PoolDataKey::Positions(user.clone());

        self.storage().persistent().extend_ttl(
            &key,
            POSITIONS_LIFETIME_THRESHOLD,
            POSITIONS_BUMP_AMOUNT,
        );

        self.storage().persistent().get(&key).unwrap_or(Positions {
            receivables: 0,
            liabilities: 0,
            collateral: 0,
        })
    }

    fn set_positions(&self, user: &Address, positions: &Positions) {
        let key: PoolDataKey = PoolDataKey::Positions(user.clone());
        
        self.storage().persistent().set(&key, positions);

        self.storage().persistent().extend_ttl(
            &key,
            POSITIONS_LIFETIME_THRESHOLD,
            POSITIONS_BUMP_AMOUNT,
        );
    }
}

#
``` Here's the diagnostic event
autumn vale
twilit glen
#

Does it have an initialize call?

#

What is that cA....2km address btw? I think u need to call set positions first however since u have unwrap or it should return the empty object

#

Oh i see why. It tries to bump without seeing if it exists first

#

Check to see if the position exists, and if not create it with the empty initializer or just return the empty initislizer rather and then only bump if it already exists then return the actual value

#
pub trait LoanPoolEnvExtensions {
    fn get_positions(&self, user: &Address) -> Positions;
    fn set_positions(&self, user: &Address, positions: &Positions);
    fn extend_positions_ttl(&self, user: &Address);
}

impl LoanPoolEnvExtensions for Env {
    fn get_positions(&self, user: &Address) -> Positions {
        let key = PoolDataKey::Positions(user.clone());

        // Check if the position exists in storage
        if let Some(positions) = self.storage().persistent().get::<Positions>(&key) {
            // Extend the TTL if the position exists and return the positions
            self.extend_positions_ttl(user);
            return positions;
        }

        // If the position doesn't exist, return a default empty value
        Positions {
            receivables: 0,
            liabilities: 0,
            collateral: 0,
        }
    }

    fn set_positions(&self, user: &Address, positions: &Positions) {
        let key: PoolDataKey = PoolDataKey::Positions(user.clone());

        self.storage().persistent().set(&key, positions);

        // Extend TTL after setting the positions
        self.extend_positions_ttl(user);
    }

    fn extend_positions_ttl(&self, user: &Address) {
        let key: PoolDataKey = PoolDataKey::Positions(user.clone());

        // Extend the TTL for the key
        self.storage().persistent().extend_ttl(
            &key,
            POSITIONS_LIFETIME_THRESHOLD,
            POSITIONS_BUMP_AMOUNT,
        );
    }
}

Heres an example to try to explain what i mean. Untested @autumn vale

autumn vale
autumn vale