Repository: paritytech/substrate
File: frame/asset-conversion/src/lib.rs (Rust)

Code before:
		///
		/// This actually does computation. If you need to keep using it, then make sure you cache
		/// the value and only call this once.
		pub fn get_pool_account(pool_id: &PoolIdOf<T>) -> T::AccountId {
			let encoded_pool_id = sp_io::hashing::blake2_256(&Encode::encode(pool_id)[..]);

			Decode::decode(&mut TrailingZeroInput::new(encoded_pool_id.as_ref()))
				.expect("infinite length input; no invalid inputs for type; qed")
		}

		fn get_balance(
			owner: &T::AccountId,
			asset: &T::MultiAssetId,
		) -> Result<T::AssetBalance, Error<T>> {
			if T::MultiAssetIdConverter::is_native(asset) {
				Self::native_to_asset(<<T as Config>::Currency>::reducible_balance(
					owner, Expendable, Polite,
				))
			} else {
				Ok(<<T as Config>::Assets>::reducible_balance(
					T::MultiAssetIdConverter::try_convert(asset)
						.map_err(|_| Error::<T>::Overflow)?,
					owner,
					Expendable,
					Polite,
				))
			}
		}

		/// Returns a pool id constructed from 2 sorted assets.
		/// Native asset should be lower than the other asset ids.
		pub fn get_pool_id(asset1: T::MultiAssetId, asset2: T::MultiAssetId) -> PoolIdOf<T> {
			if asset1 <= asset2 {
				(asset1, asset2)
			} else {
				(asset2, asset1)
			}
		}

		/// Returns the balance of each asset in the pool.
		/// The tuple result is in the order requested (not necessarily the same as pool order).
		pub fn get_reserves(
			asset1: &T::MultiAssetId,
			asset2: &T::MultiAssetId,
		) -> Result<(T::AssetBalance, T::AssetBalance), Error<T>> {
			let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone());
			let pool_account = Self::get_pool_account(&pool_id);

			let balance1 = Self::get_balance(&pool_account, asset1)?;
			let balance2 = Self::get_balance(&pool_account, asset2)?;


Review comment (suggestion):
We don't ensure this anywhere, we're just assuming it will be used this way. I think it's probably better to emit an error, same for `first_amount`.
```rust
let first_amount = amounts.first().ok_or(Error::<T>::PathError)?;
let amount_out = amounts.last().ok_or(Error::<T>::PathError)?;
```

Code after:

						let to = if i < path_len - 2 {
							let asset3 = path.get((i + 2) as usize).ok_or(Error::<T>::PathError)?;
							Self::get_pool_account(&Self::get_pool_id(
								asset2.clone(),
								asset3.clone(),
							))
						} else {
							send_to.clone()
						};

						let reserve = Self::get_balance(&pool_account, asset2)?;
						let reserve_left = reserve.saturating_sub(*amount_out);
						Self::validate_minimal_amount(reserve_left, asset2)
							.map_err(|_| Error::<T>::ReserveLeftLessThanMinimal)?;

						Self::transfer(asset2, &pool_account, &to, *amount_out, true)?;
					}
					i.saturating_inc();
				}
				Self::deposit_event(Event::SwapExecuted {
					who: sender,
					send_to,
					path,
					amount_in: *first_amount,
					amount_out: *amounts.last().expect("Always has more than 1 element"),
				});
			} else {
				return Err(Error::<T>::InvalidPath.into())
			}
			Ok(())
		}

		/// The account ID of the pool.
		///
		/// This actually does computation. If you need to keep using it, then make sure you cache
		/// the value and only call this once.
		pub fn get_pool_account(pool_id: &PoolIdOf<T>) -> T::AccountId {
			let encoded_pool_id = sp_io::hashing::blake2_256(&Encode::encode(pool_id)[..]);

			Decode::decode(&mut TrailingZeroInput::new(encoded_pool_id.as_ref()))
				.expect("infinite length input; no invalid inputs for type; qed")
		}

		/// Get the `owner`'s balance of `asset`, which could be the chain's native asset or another
		/// fungible. Returns a value in the form of an `AssetBalance`.
		fn get_balance(
			owner: &T::AccountId,
			asset: &T::MultiAssetId,
		) -> Result<T::AssetBalance, Error<T>> {
			if T::MultiAssetIdConverter::is_native(asset) {