stellar-baselib 0.5.7

A low level Rust library that offers a comprehensive set of functions for reading, writing, hashing, and signing primitive XDR constructs utilized in the Stellar network
Documentation
use crate::{
    operation::{self, Operation},
    xdr,
};

impl Operation {
    /// Withdraw assets from a liquidity pool, reducing the number of pool shares in exchange
    /// for reserves of a liquidity pool
    ///
    /// The `min_amount_a` and `min_amount_b` parameters can be used to control a percentage of slippage
    /// from the "spot price" on the pool.
    ///
    /// Threshold: Medium
    pub fn liquidity_pool_withdraw(
        &self,
        pool_id: &str,
        amount: i64,
        min_amount_a: i64,
        min_amount_b: i64,
    ) -> Result<xdr::Operation, operation::Error> {
        //
        let mut h = [0; 32];
        hex::decode_to_slice(pool_id, &mut h)
            .map_err(|_| operation::Error::InvalidField("pool_id".into()))?;
        let liquidity_pool_id = xdr::PoolId(xdr::Hash(h));

        if amount < 0 {
            return Err(operation::Error::InvalidAmount(amount));
        }
        if min_amount_a < 0 {
            return Err(operation::Error::InvalidAmount(min_amount_a));
        }
        if min_amount_b < 0 {
            return Err(operation::Error::InvalidAmount(min_amount_b));
        }

        let body = xdr::OperationBody::LiquidityPoolWithdraw(xdr::LiquidityPoolWithdrawOp {
            liquidity_pool_id,
            amount,
            min_amount_a,
            min_amount_b,
        });
        Ok(xdr::Operation {
            source_account: self.source.clone(),
            body,
        })
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        operation::{self, Operation},
        xdr,
    };

    #[test]
    fn test_lp_withdraw() {
        let pool_id = hex::encode([8; 32]);
        let amount = 50;
        let min_amount_a = 12 * operation::ONE;
        let min_amount_b = 40 * operation::ONE;

        let op = Operation::new()
            .liquidity_pool_withdraw(&pool_id, amount, min_amount_a, min_amount_b)
            .unwrap();

        if let xdr::OperationBody::LiquidityPoolWithdraw(xdr::LiquidityPoolWithdrawOp {
            liquidity_pool_id: xdr::PoolId(xdr::Hash(h)),
            amount,
            min_amount_a: min_a,
            min_amount_b: min_b,
        }) = op.body
        {
            assert_eq!(h, [8; 32]);
            assert_eq!(min_a, min_amount_a);
            assert_eq!(min_b, min_amount_b);
            //
        } else {
            panic!("Fail")
        }
    }
    #[test]
    fn test_lp_withdraw_bad_id() {
        let pool_id = hex::encode([8; 33]);
        let amount = 50;
        let min_amount_a = 12 * operation::ONE;
        let min_amount_b = 40 * operation::ONE;

        let op =
            Operation::new().liquidity_pool_withdraw(&pool_id, amount, min_amount_a, min_amount_b);

        assert_eq!(
            op.err(),
            Some(operation::Error::InvalidField("pool_id".into()))
        );
    }
    #[test]
    fn test_lp_withdraw_bad_id2() {
        let pool_id = hex::encode([8; 31]);
        let amount = 50;
        let min_amount_a = 12 * operation::ONE;
        let min_amount_b = 40 * operation::ONE;

        let op =
            Operation::new().liquidity_pool_withdraw(&pool_id, amount, min_amount_a, min_amount_b);

        assert_eq!(
            op.err(),
            Some(operation::Error::InvalidField("pool_id".into()))
        );
    }
    #[test]
    fn test_lp_withdraw_bad_amount() {
        let pool_id = hex::encode([8; 32]);
        let amount = -50;
        let min_amount_a = 12 * operation::ONE;
        let min_amount_b = 40 * operation::ONE;

        let op =
            Operation::new().liquidity_pool_withdraw(&pool_id, amount, min_amount_a, min_amount_b);

        assert_eq!(op.err(), Some(operation::Error::InvalidAmount(amount)));
    }
    #[test]
    fn test_lp_withdraw_bad_amount2() {
        let pool_id = hex::encode([8; 32]);
        let amount = 50;
        let min_amount_a = -12 * operation::ONE;
        let min_amount_b = 40 * operation::ONE;

        let op =
            Operation::new().liquidity_pool_withdraw(&pool_id, amount, min_amount_a, min_amount_b);

        assert_eq!(
            op.err(),
            Some(operation::Error::InvalidAmount(min_amount_a))
        );
    }
    #[test]
    fn test_lp_withdraw_bad_amount3() {
        let pool_id = hex::encode([8; 32]);
        let amount = 50;
        let min_amount_a = 12 * operation::ONE;
        let min_amount_b = -40 * operation::ONE;

        let op =
            Operation::new().liquidity_pool_withdraw(&pool_id, amount, min_amount_a, min_amount_b);

        assert_eq!(
            op.err(),
            Some(operation::Error::InvalidAmount(min_amount_b))
        );
    }
}