ve3-shared 0.9.1

ve(3,3) msgs in cosmwasm
Documentation
use std::convert::TryInto;

use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coins, CosmosMsg, Uint128};
use cw_asset::{Asset, AssetInfo};

use crate::{error::SharedError, extensions::asset_info_ext::AssetInfoExt};

#[cw_serde]
#[derive(Default)]
pub struct Assets(pub Vec<Asset>);

impl IntoIterator for Assets {
  type Item = Asset;
  type IntoIter = std::vec::IntoIter<Asset>;

  fn into_iter(self) -> Self::IntoIter {
    self.0.into_iter()
  }
}

impl From<Vec<Asset>> for Assets {
  fn from(value: Vec<Asset>) -> Self {
    Assets(value)
  }
}

impl Assets {
  pub fn is_empty(&self) -> bool {
    self.0.len() == 0
  }

  pub fn remove(&mut self, asset: &Asset) -> Result<(), SharedError> {
    let existing = self.0.iter_mut().find(|a| a.info == asset.info);

    match existing {
      Some(existing) if existing.amount < asset.amount => Err(SharedError::InsufficientBalance(
        format!("existing: {0} withdrawing: {1}", existing, asset),
      )),
      Some(existing) => {
        existing.amount -= asset.amount;

        if existing.amount.is_zero() {
          self.0.retain(|a| !a.amount.is_zero())
        }
        Ok(())
      },
      None => Err(SharedError::NotFound(format!("asset {0}", asset.info))),
    }
  }

  pub fn get(&mut self, info: &AssetInfo) -> Option<Asset> {
    self.0.iter().find(|a| a.info == *info).cloned()
  }

  pub fn remove_multi(&mut self, assets: &Vec<Asset>) -> Result<(), SharedError> {
    for asset in assets {
      self.remove(asset)?;
    }

    Ok(())
  }

  pub fn add(&mut self, asset: &Asset) {
    if asset.amount.is_zero() {
      return;
    }

    let existing = self.0.iter_mut().find(|a| a.info == asset.info);

    match existing {
      Some(in_bucket) => {
        in_bucket.amount += asset.amount;
      },
      None => {
        self.0.push(asset.clone());
      },
    }
  }

  pub fn get_coins(&self) -> Result<Coins, SharedError> {
    let mut coins = Coins::default();
    for native in self.0.iter().filter(|a| a.info.is_native()) {
      coins.add(native.try_into()?)?;
    }
    Ok(coins)
  }

  pub fn add_multi(&mut self, assets: &Vec<Asset>) {
    for asset in assets {
      self.add(asset);
    }
  }

  pub fn calc_share_amounts(
    &self,
    vp: Uint128,
    total_vp: Uint128,
  ) -> Result<Vec<Asset>, SharedError> {
    let mut results = vec![];
    for a in &self.0 {
      let share_amount = a.amount.checked_multiply_ratio(vp, total_vp)?;

      if share_amount.is_zero() {
        continue;
      }

      results.push(a.info.with_balance(share_amount))
    }

    Ok(results)
  }

  pub fn transfer_msgs(&self, to: &Addr) -> Result<Vec<CosmosMsg>, SharedError> {
    let mut results = vec![];
    for asset in self.0.iter() {
      results.push(asset.transfer_msg(to)?);
    }
    Ok(results)
  }
}