Repository: stellar/rs-soroban-env
Pull request #1275 (2023-12-01 19:55:21)

Initial SAC review 
I still have 3 large-ish files in the SAC to look at but need to take a pause to switch tasks, and this is a good stopping point. There's nothing too serious in here, but a bit of churn:

  - Removed a bunch of dead code
  - Made a lot of stuff pub(crate) -- and had to change macro to deal with that
  - Factored out some common patterns in balance.rs
  - Merged-and-sorted imports

I'll post another of these once I have the rest of the SAC done


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index bee3ab4c..c3eb6126 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -463,9 +463,9 @@ dependencies = [
 
 [[package]]
 name = "escape-bytes"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3871d161fec5b6fade5fe7afe2e196b86839c5526a8d256c7b1a04dbbe5241a4"
+checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2"
 
 [[package]]
 name = "ethnum"
@@ -1510,7 +1510,7 @@ dependencies = [
 [[package]]
 name = "stellar-xdr"
 version = "20.0.0-rc1"
-source = "git+https://github.com/stellar/rs-stellar-xdr?rev=889d433c6069c7cdd63a9e4f391de06f5d8018ac#889d433c6069c7cdd63a9e4f391de06f5d8018ac"
+source = "git+https://github.com/stellar/rs-stellar-xdr?rev=97e52f17501fb058ee28bbca3da0ae7897492746#97e52f17501fb058ee28bbca3da0ae7897492746"
 dependencies = [
  "arbitrary",
  "base64 0.13.1",
diff --git a/Cargo.toml b/Cargo.toml
index cc21b6d9..8d34a15c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,7 @@ soroban-builtin-sdk-macros = { version = "=20.0.0-rc2", path = "soroban-builtin-
 [workspace.dependencies.stellar-xdr]
 version = "=20.0.0-rc1"
 git = "https://github.com/stellar/rs-stellar-xdr"
-rev = "889d433c6069c7cdd63a9e4f391de06f5d8018ac"
+rev = "97e52f17501fb058ee28bbca3da0ae7897492746"
 default-features = false
 
 [workspace.dependencies.wasmi]
diff --git a/soroban-builtin-sdk-macros/src/derive_type.rs b/soroban-builtin-sdk-macros/src/derive_type.rs
index c7f4fcc3..cc7790a0 100644
--- a/soroban-builtin-sdk-macros/src/derive_type.rs
+++ b/soroban-builtin-sdk-macros/src/derive_type.rs
@@ -1,7 +1,7 @@
 use itertools::Itertools;
 use proc_macro2::{Literal, TokenStream as TokenStream2};
 use quote::{format_ident, quote};
-use syn::{spanned::Spanned, DataEnum, DataStruct, Error, Fields, Ident, Visibility};
+use syn::{spanned::Spanned, DataEnum, DataStruct, Error, Fields, Ident};
 
 pub fn derive_type_struct(ident: &Ident, data: &DataStruct) -> TokenStream2 {
     let len = Literal::usize_unsuffixed(data.fields.len());
@@ -11,7 +11,6 @@ pub fn derive_type_struct(ident: &Ident, data: &DataStruct) -> TokenStream2 {
             data.fields
                 .iter()
                 .sorted_by_key(|field| field.ident.as_ref().unwrap().to_string())
-                .filter(|f| matches!(f.vis, Visibility::Public(_)))
                 .enumerate()
                 .map(|(i, f)| {
                     let ident = f.ident.as_ref().unwrap().clone();
@@ -23,7 +22,6 @@ pub fn derive_type_struct(ident: &Ident, data: &DataStruct) -> TokenStream2 {
         } else {
             data.fields
                 .iter()
-                .filter(|f| matches!(f.vis, Visibility::Public(_)))
                 .enumerate()
                 .map(|(i, _)| {
                     let ident = format_ident!("{}", i);
diff --git a/soroban-builtin-sdk-macros/src/lib.rs b/soroban-builtin-sdk-macros/src/lib.rs
index 5de6087e..f9af25d6 100644
--- a/soroban-builtin-sdk-macros/src/lib.rs
+++ b/soroban-builtin-sdk-macros/src/lib.rs
@@ -9,7 +9,6 @@ use proc_macro::TokenStream;
 use quote::quote;
 use syn::{
     parse_macro_input, spanned::Spanned, DeriveInput, Error, ImplItem, ImplItemFn, ItemImpl,
-    Visibility,
 };
 
 #[proc_macro_attribute]
@@ -49,13 +48,10 @@ fn get_methods(imp: &ItemImpl) -> impl Iterator<Item = &ImplItemFn> {
 #[proc_macro_attribute]
 pub fn contractimpl(_metadata: TokenStream, input: TokenStream) -> TokenStream {
     let imp = parse_macro_input!(input as ItemImpl);
-    let is_trait = imp.trait_.is_some();
     let ty = &imp.self_ty;
-    let pub_methods: Vec<_> = get_methods(&imp)
-        .filter(|m| is_trait || matches!(m.vis, Visibility::Public(_)))
-        .collect();
+    let all_methods: Vec<_> = get_methods(&imp).collect();
 
-    let cfs = derive_contract_function_set(ty, pub_methods.into_iter());
+    let cfs = derive_contract_function_set(ty, all_methods.into_iter());
     quote! {
         #imp
         #cfs
diff --git a/soroban-env-host/Cargo.toml b/soroban-env-host/Cargo.toml
index 2b3399bc..4a2c5550 100644
--- a/soroban-env-host/Cargo.toml
+++ b/soroban-env-host/Cargo.toml
@@ -65,7 +65,7 @@ arbitrary = "=1.3.2"
 [dev-dependencies.stellar-xdr]
 version = "=20.0.0-rc1"
 git = "https://github.com/stellar/rs-stellar-xdr"
-rev = "889d433c6069c7cdd63a9e4f391de06f5d8018ac"
+rev = "97e52f17501fb058ee28bbca3da0ae7897492746"
 default-features = false
 features = ["arbitrary"]
 
diff --git a/soroban-env-host/src/builtin_contracts.rs b/soroban-env-host/src/builtin_contracts.rs
index 656d3660..9f855cce 100644
--- a/soroban-env-host/src/builtin_contracts.rs
+++ b/soroban-env-host/src/builtin_contracts.rs
@@ -8,11 +8,11 @@ pub(crate) mod storage_utils;
 use crate::host::{Host, HostError};
 use soroban_env_common::{Symbol, Val};
 
-pub trait BuiltinContract {
+pub(crate) trait BuiltinContract {
     fn call(&self, func: &Symbol, host: &Host, args: &[Val]) -> Result<Val, HostError>;
 }
 
-pub use stellar_asset_contract::StellarAssetContract;
+pub(crate) use stellar_asset_contract::StellarAssetContract;
 
 pub(crate) mod account_contract;
 
diff --git a/soroban-env-host/src/builtin_contracts/account_contract.rs b/soroban-env-host/src/builtin_contracts/account_contract.rs
index ee7432f9..1940e931 100644
--- a/soroban-env-host/src/builtin_contracts/account_contract.rs
+++ b/soroban-env-host/src/builtin_contracts/account_contract.rs
@@ -26,17 +26,17 @@ pub const ACCOUNT_CONTRACT_CHECK_AUTH_FN_NAME: &str = "__check_auth";
 
 #[derive(Clone)]
 #[contracttype]
-pub struct ContractAuthorizationContext {
-    pub contract: Address,
-    pub fn_name: Symbol,
-    pub args: HostVec,
+pub(crate) struct ContractAuthorizationContext {
+    pub(crate) contract: Address,
+    pub(crate) fn_name: Symbol,
+    pub(crate) args: HostVec,
 }
 
 #[derive(Clone)]
 #[contracttype]
-pub struct CreateContractHostFnContext {
-    pub executable: ContractExecutable,
-    pub salt: BytesN<32>,
+pub(crate) struct CreateContractHostFnContext {
+    pub(crate) executable: ContractExecutable,
+    pub(crate) salt: BytesN<32>,
 }
 
 #[derive(Clone)]
@@ -48,9 +48,9 @@ enum AuthorizationContext {
 
 #[derive(Clone)]
 #[contracttype]
-pub struct AccountEd25519Signature {
-    pub public_key: BytesN<32>,
-    pub signature: BytesN<64>,
+pub(crate) struct AccountEd25519Signature {
+    pub(crate) public_key: BytesN<32>,
+    pub(crate) signature: BytesN<64>,
 }
 
 impl AuthorizationContext {
diff --git a/soroban-env-host/src/builtin_contracts/base_types.rs b/soroban-env-host/src/builtin_contracts/base_types.rs
index 2240e614..c3bc2f84 100644
--- a/soroban-env-host/src/builtin_contracts/base_types.rs
+++ b/soroban-env-host/src/builtin_contracts/base_types.rs
@@ -1,15 +1,13 @@
-use crate::host::metered_clone::MeteredClone;
-use crate::host::{Host, HostError};
-
-use core::cmp::Ordering;
-use soroban_env_common::xdr::{AccountId, ScAddress, ScErrorCode, ScErrorType};
-use soroban_env_common::{
-    AddressObject, BytesObject, Compare, ConversionError, Env, EnvBase, MapObject, StringObject,
-    TryFromVal, Val, VecObject,
+use crate::{
+    host::{metered_clone::MeteredClone, Host, HostError},
+    xdr::{AccountId, ScAddress, ScErrorCode, ScErrorType},
+    AddressObject, BytesObject, Compare, Env, EnvBase, StringObject, TryFromVal, U32Val, Val,
+    VecObject,
 };
+use core::cmp::Ordering;
 
 #[derive(Clone)]
-pub struct String {
+pub(crate) struct String {
     host: Host,
     object: StringObject,
 }
@@ -58,7 +56,7 @@ impl From<String> for StringObject {
 }
 
 impl String {
-    pub fn to_array<const N: usize>(&self) -> Result<[u8; N], HostError> {
+    pub(crate) fn to_array<const N: usize>(&self) -> Result<[u8; N], HostError> {
         let mut slice = [0_u8; N];
         let len = self.host.string_len(self.object)?;
         if u32::from(len) as usize != N {
@@ -87,91 +85,7 @@ impl String {
 }
 
 #[derive(Clone)]
-pub struct Bytes {
-    host: Host,
-    object: BytesObject,
-}
-
-impl Compare<Bytes> for Host {
-    type Error = HostError;
-
-    fn compare(&self, a: &Bytes, b: &Bytes) -> Result<Ordering, Self::Error> {
-        self.compare(&a.object.to_val(), &b.object.to_val())
-    }
-}
-
-impl TryFromVal<Host, BytesObject> for Bytes {
-    type Error = HostError;
-
-    fn try_from_val(env: &Host, val: &BytesObject) -> Result<Self, Self::Error> {
-        Ok(Bytes {
-            host: env.clone(),
-            object: *val,
-        })
-    }
-}
-
-impl TryFromVal<Host, Val> for Bytes {
-    type Error = HostError;
-
-    fn try_from_val(env: &Host, val: &Val) -> Result<Self, Self::Error> {
-        let val = *val;
-        let obj: BytesObject = val.try_into()?;
-        Bytes::try_from_val(env, &obj)
-    }
-}
-
-impl TryFromVal<Host, Bytes> for Val {
-    type Error = HostError;
-
-    fn try_from_val(_env: &Host, val: &Bytes) -> Result<Val, Self::Error> {
-        Ok(val.object.into())
-    }
-}
-
-impl From<Bytes> for BytesObject {
-    fn from(b: Bytes) -> Self {
-        b.object
-    }
-}
-
-impl<const N: usize> From<BytesN<N>> for Bytes {
-    fn from(b: BytesN<N>) -> Self {
-        Self {
-            host: b.host.clone(),
-            object: b.object,
-        }
-    }
-}
-
-// TODO: check metering
-impl Bytes {
-    pub fn push(&mut self, x: u8) -> Result<(), HostError> {
-        let x32: u32 = x.into();
-        self.object = self.host.bytes_push(self.object, x32.into())?;
-        Ok(())
-    }
-
-    pub fn append(&mut self, other: Bytes) -> Result<(), HostError> {
-        self.object = self.host.bytes_append(self.object, other.object)?;
-        Ok(())
-    }
-
-    #[inline(always)]
-    pub fn from_slice(env: &Host, items: &[u8]) -> Result<Bytes, HostError> {
-        Ok(Bytes {
-            host: env.clone(),
-            object: env.bytes_new_from_slice(items)?,
-        })
-    }
-
-    pub fn as_object(&self) -> BytesObject {
-        self.object
-    }
-}
-
-#[derive(Clone)]
-pub struct BytesN<const N: usize> {
+pub(crate) struct BytesN<const N: usize> {
     host: Host,
     object: BytesObject,
 }
@@ -188,7 +102,12 @@ impl<const N: usize> TryFromVal<Host, BytesObject> for BytesN<N> {
                 object: val,
             })
         } else {
-            Err(ConversionError.into())
+            return Err(env.err(
+                ScErrorType::Value,
+                ScErrorCode::UnexpectedSize,
+                "Bytes had unexpected size",
+                &[U32Val::from(len).to_val()],
+            ));
         }
     }
 }
@@ -232,7 +151,7 @@ impl<const N: usize> From<BytesN<N>> for BytesObject {
 }
 
 impl<const N: usize> BytesN<N> {
-    pub fn compare(&self, other: &BytesN<N>) -> Result<Ordering, HostError> {
+    pub(crate) fn compare(&self, other: &BytesN<N>) -> Result<Ordering, HostError> {
         let res = self.host.obj_cmp(self.object.into(), other.object.into())?;
         Ok(res.cmp(&0))
     }
@@ -240,7 +159,7 @@ impl<const N: usize> BytesN<N> {
 
 impl<const N: usize> BytesN<N> {
     #[inline(always)]
-    pub fn to_array(&self) -> Result<[u8; N], HostError> {
+    pub(crate) fn to_array(&self) -> Result<[u8; N], HostError> {
         let mut slice = [0_u8; N];
         self.host
             .bytes_copy_to_slice(self.object, Val::U32_ZERO, &mut slice)?;
@@ -248,105 +167,20 @@ impl<const N: usize> BytesN<N> {
     }
 
     #[inline(always)]
-    pub fn from_slice(env: &Host, items: &[u8]) -> Result<BytesN<N>, HostError> {
+    pub(crate) fn from_slice(env: &Host, items: &[u8]) -> Result<BytesN<N>, HostError> {
         Ok(BytesN {
             host: env.clone(),
             object: env.bytes_new_from_slice(items)?,
         })
     }
 
-    pub fn as_object(&self) -> BytesObject {
+    pub(crate) fn as_object(&self) -> BytesObject {
         self.object
     }
 }
 
 #[derive(Clone)]
-pub struct Map {
-    host: Host,
-    object: MapObject,
-}
-
-impl TryFromVal<Host, MapObject> for Map {
-    type Error = HostError;
-
-    fn try_from_val(env: &Host, val: &MapObject) -> Result<Self, Self::Error> {
-        let val = *val;
-        Ok(Map {
-            host: env.clone(),
-            object: val,
-        })
-    }
-}
-
-impl Compare<Map> for Host {
-    type Error = HostError;
-
-    fn compare(&self, a: &Map, b: &Map) -> Result<Ordering, Self::Error> {
-        self.compare(&a.object.to_val(), &b.object.to_val())
-    }
-}
-
-impl TryFromVal<Host, Val> for Map {
-    type Error = HostError;
-
-    fn try_from_val(env: &Host, val: &Val) -> Result<Self, Self::Error> {
-        let val = *val;
-        let obj: MapObject = val.try_into()?;
-        Map::try_from_val(env, &obj)
-    }
-}
-
-impl TryFromVal<Host, Map> for Val {
-    type Error = HostError;
-
-    fn try_from_val(_env: &Host, val: &Map) -> Result<Val, Self::Error> {
-        Ok(val.object.into())
-    }
-}
-
-impl From<Map> for MapObject {
-    fn from(map: Map) -> Self {
-        map.object
-    }
-}
-
-impl Map {
-    pub fn new(env: &Host) -> Result<Self, HostError> {
-        let map = env.map_new()?;
-        Ok(Self {
-            host: env.clone(),
-            object: map,
-        })
-    }
-
-    pub fn get<K, V>(&self, k: &K) -> Result<V, HostError>
-    where
-        Val: TryFromVal<Host, K>,
-        V: TryFromVal<Host, Val>,
-        HostError: From<<Val as TryFromVal<Host, K>>::Error>,
-        HostError: From<<V as TryFromVal<Host, Val>>::Error>,
-    {
-        let k_rv = Val::try_from_val(&self.host, k)?;
-        let v_rv = self.host.map_get(self.object, k_rv)?;
-        Ok(V::try_from_val(&self.host, &v_rv)?)
-    }
-
-    pub fn set<K, V>(&mut self, k: &K, v: &V) -> Result<(), HostError>
-    where
-        Val: TryFromVal<Host, K>,
-        Val: TryFromVal<Host, V>,
-        HostError: From<<Val as TryFromVal<Host, K>>::Error>,
-        HostError: From<<Val as TryFromVal<Host, V>>::Error>,
-    {
-        let k_rv = Val::try_from_val(&self.host, k)?;
-        let v_rv = Val::try_from_val(&self.host, v)?;
-        self.object = self.host.map_put(self.object, k_rv, v_rv)?;
-        Ok(())
-    }
-}
-
-#[derive(Clone)]
-pub struct Vec {
+pub(crate) struct Vec {
     host: Host,
     object: VecObject,
 }
@@ -418,7 +252,7 @@ impl TryFromVal<Host, &std::vec::Vec<Val>> for Vec {
 }
 
 impl Vec {
-    pub fn new(env: &Host) -> Result<Self, HostError> {
+    pub(crate) fn new(env: &Host) -> Result<Self, HostError> {
         let vec = env.vec_new()?;
         Ok(Self {
             host: env.clone(),
@@ -426,7 +260,7 @@ impl Vec {
         })
     }
 
-    pub fn from_slice(env: &Host, slice: &[Val]) -> Result<Self, HostError> {
+    pub(crate) fn from_slice(env: &Host, slice: &[Val]) -> Result<Self, HostError> {
         let vec = env.vec_new_from_slice(slice)?;
         Ok(Self {
             host: env.clone(),
@@ -434,7 +268,7 @@ impl Vec {
         })
     }
 
-    pub fn get<T: TryFromVal<Host, Val>>(&self, i: u32) -> Result<T, HostError>
+    pub(crate) fn get<T: TryFromVal<Host, Val>>(&self, i: u32) -> Result<T, HostError>
     where
         HostError: From<<T as TryFromVal<Host, Val>>::Error>,
     {
@@ -442,11 +276,11 @@ impl Vec {
         Ok(T::try_from_val(&self.host, &rv)?)
     }
 
-    pub fn len(&self) -> Result<u32, HostError> {
+    pub(crate) fn len(&self) -> Result<u32, HostError> {
         Ok(self.host.vec_len(self.object)?.into())
     }
 
-    pub fn push<T>(&mut self, x: &T) -> Result<(), HostError>
+    pub(crate) fn push<T>(&mut self, x: &T) -> Result<(), HostError>
     where
         Val: TryFromVal<Host, T>,
         HostError: From<<Val as TryFromVal<Host, T>>::Error>,
@@ -455,18 +289,18 @@ impl Vec {
         self.push_val(rv)
     }
 
-    pub fn push_val(&mut self, x: Val) -> Result<(), HostError> {
+    pub(crate) fn push_val(&mut self, x: Val) -> Result<(), HostError> {
         self.object = self.host.vec_push_back(self.object, x)?;
         Ok(())
     }
 
-    pub fn as_object(&self) -> VecObject {
+    pub(crate) fn as_object(&self) -> VecObject {
         self.object
     }
 }
 
 #[derive(Clone)]
-pub struct Address {
+pub(crate) struct Address {
     host: Host,
     object: AddressObject,
 }
diff --git a/soroban-env-host/src/builtin_contracts/common_types.rs b/soroban-env-host/src/builtin_contracts/common_types.rs
index c0fb234b..a23343fc 100644
--- a/soroban-env-host/src/builtin_contracts/common_types.rs
+++ b/soroban-env-host/src/builtin_contracts/common_types.rs
@@ -1,18 +1,16 @@
-use crate::{xdr, Host, HostError};
-use soroban_builtin_sdk_macros::contracttype;
-use soroban_env_common::TryIntoVal;
-
 use super::base_types::BytesN;
+use crate::{xdr, Host, HostError, TryIntoVal};
+use soroban_builtin_sdk_macros::contracttype;
 
 #[derive(Clone)]
 #[contracttype]
-pub enum ContractExecutable {
+pub(crate) enum ContractExecutable {
     Wasm(BytesN<32>),
     StellarAsset,
 }
 
 impl ContractExecutable {
-    pub fn from_xdr(host: &Host, xdr: &xdr::ContractExecutable) -> Result<Self, HostError> {
+    pub(crate) fn from_xdr(host: &Host, xdr: &xdr::ContractExecutable) -> Result<Self, HostError> {
         match xdr {
             xdr::ContractExecutable::Wasm(wasm_hash) => Ok(ContractExecutable::Wasm(
                 BytesN::<32>::from_slice(host, &wasm_hash.0)?,
diff --git a/soroban-env-host/src/builtin_contracts/contract_error.rs b/soroban-env-host/src/builtin_contracts/contract_error.rs
index 6e6e4289..1f534593 100644
--- a/soroban-env-host/src/builtin_contracts/contract_error.rs
+++ b/soroban-env-host/src/builtin_contracts/contract_error.rs
@@ -1,11 +1,11 @@
 use num_derive::FromPrimitive;
 use soroban_env_common::Error;
 
-// Use the same error for all the built-in contract error.
+// Use the same error type for all the built-in contract errors.
 // In theory we could have a separate enum for each built-in contract, but it's
 // not clear how to distinguish them if multiple built-in contracts are involved.
 #[derive(Debug, FromPrimitive, PartialEq, Eq)]
-pub enum ContractError {
+pub(crate) enum ContractError {
     InternalError = 1,
     OperationNotSupportedError = 2,
     AlreadyInitializedError = 3,
diff --git a/soroban-env-host/src/builtin_contracts/invoker_contract_auth.rs b/soroban-env-host/src/builtin_contracts/invoker_contract_auth.rs
index 386eb10b..00fb0fb0 100644
--- a/soroban-env-host/src/builtin_contracts/invoker_contract_auth.rs
+++ b/soroban-env-host/src/builtin_contracts/invoker_contract_auth.rs
@@ -17,7 +17,7 @@ use soroban_env_common::{TryFromVal, TryIntoVal, Val};
 
 #[derive(Clone)]
 #[contracttype]
-pub struct SubContractInvocation {
+pub(crate) struct SubContractInvocation {
     pub context: ContractAuthorizationContext,
     pub sub_invocations: ContractTypeVec, // Vec of InvokerContractAuthEntry
 }
@@ -28,7 +28,7 @@ pub struct SubContractInvocation {
 /// contract.
 #[derive(Clone)]
 #[contracttype]
-pub enum InvokerContractAuthEntry {
+pub(crate) enum InvokerContractAuthEntry {
     Contract(SubContractInvocation),
     CreateContractHostFn(CreateContractHostFnContext),
 }
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract.rs
index 84dd2cf4..a2b77883 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract.rs
@@ -11,4 +11,4 @@ mod storage_types;
 #[cfg(test)]
 pub(crate) mod test_stellar_asset_contract;
 
-pub use contract::StellarAssetContract;
+pub(crate) use contract::StellarAssetContract;
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/admin.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/admin.rs
index b33c69d1..4ec521cf 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/admin.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/admin.rs
@@ -1,19 +1,17 @@
-use crate::builtin_contracts::base_types::Address;
-use crate::host::Host;
-use crate::HostError;
-use soroban_env_common::{Env, StorageType, TryIntoVal};
-
 use super::storage_types::InstanceDataKey;
+use crate::{
+    builtin_contracts::base_types::Address, host::Host, Env, HostError, StorageType, TryIntoVal,
+};
 
 // Metering: covered by components
-pub fn read_administrator(e: &Host) -> Result<Address, HostError> {
+pub(crate) fn read_administrator(e: &Host) -> Result<Address, HostError> {
     let key = InstanceDataKey::Admin;
     let rv = e.get_contract_data(key.try_into_val(e)?, StorageType::Instance)?;
     rv.try_into_val(e)
 }
 
 // Metering: covered by components
-pub fn write_administrator(e: &Host, id: Address) -> Result<(), HostError> {
+pub(crate) fn write_administrator(e: &Host, id: Address) -> Result<(), HostError> {
     let key = InstanceDataKey::Admin;
     e.put_contract_data(
         key.try_into_val(e)?,
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/allowance.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/allowance.rs
index 31f84bb4..ca43d720 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/allowance.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/allowance.rs
@@ -1,17 +1,21 @@
-use crate::builtin_contracts::base_types::Address;
-use crate::builtin_contracts::contract_error::ContractError;
-use crate::builtin_contracts::stellar_asset_contract::storage_types::{AllowanceDataKey, DataKey};
-use crate::builtin_contracts::storage_utils::StorageUtils;
-use crate::host::{metered_clone::MeteredClone, Host};
-use crate::{err, HostError};
-use soroban_env_common::{Env, StorageType, TryIntoVal};
+use crate::{
+    builtin_contracts::{
+        base_types::Address,
+        contract_error::ContractError,
+        stellar_asset_contract::storage_types::{AllowanceDataKey, DataKey},
+    },
+    err,
+    host::{metered_clone::MeteredClone, Host},
+    Env, HostError, StorageType, TryIntoVal,
+};
 
 use super::storage_types::AllowanceValue;
 
 // Metering: covered by components
-pub fn read_allowance(e: &Host, from: Address, spender: Address) -> Result<i128, HostError> {
+pub(crate) fn read_allowance(e: &Host, from: Address, spender: Address) -> Result<i128, HostError> {
     let key = DataKey::Allowance(AllowanceDataKey { from, spender });
-    if let Some(allowance) = StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Temporary)?
+    if let Some(allowance) =
+        e.try_get_contract_data(key.try_into_val(e)?, StorageType::Temporary)?
     {
         let val: AllowanceValue = allowance.try_into_val(e)?;
         if val.live_until_ledger < e.get_ledger_sequence()?.into() {
@@ -25,7 +29,7 @@ pub fn read_allowance(e: &Host, from: Address, spender: Address) -> Result<i128,
 }
 
 // Metering: covered by components
-pub fn write_allowance(
+pub(crate) fn write_allowance(
     e: &Host,
     from: Address,
     spender: Address,
@@ -62,7 +66,7 @@ pub fn write_allowance(
     // If an allowance didn't exist, then the previous live_until ledger will be None.
     let allowance_with_live_until_option: Option<(AllowanceValue, Option<u32>)> =
         if let Some(allowance) =
-            StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Temporary)?
+            e.try_get_contract_data(key.try_into_val(e)?, StorageType::Temporary)?
         {
             let mut updated_allowance: AllowanceValue = allowance.try_into_val(e)?;
             updated_allowance.amount = amount;
@@ -93,7 +97,7 @@ pub fn write_allowance(
             if allowance_with_live_until.0.amount > 0
                 && allowance_with_live_until.1.unwrap_or(0) < live_until
             {
-                let live_for = live_until - ledger_seq + 1;
+                let live_for = live_until.saturating_sub(ledger_seq).saturating_add(1);
                 e.extend_contract_data_ttl(
                     key.try_into_val(e)?,
                     StorageType::Temporary,
@@ -127,7 +131,7 @@ fn write_allowance_amount(
 }
 
 // Metering: covered by components
-pub fn spend_allowance(
+pub(crate) fn spend_allowance(
     e: &Host,
     from: Address,
     spender: Address,
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/asset_info.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/asset_info.rs
index f1f67273..02ab5037 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/asset_info.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/asset_info.rs
@@ -1,7 +1,11 @@
-use crate::builtin_contracts::stellar_asset_contract::public_types::AssetInfo;
-use crate::builtin_contracts::stellar_asset_contract::storage_types::InstanceDataKey;
-use crate::xdr::{Asset, ScErrorCode, ScErrorType};
-use crate::{host::Host, Env, HostError, StorageType, TryIntoVal, U32Val};
+use crate::{
+    builtin_contracts::stellar_asset_contract::{
+        public_types::AssetInfo, storage_types::InstanceDataKey,
+    },
+    host::Host,
+    xdr::{Asset, ScErrorCode, ScErrorType},
+    Env, HostError, StorageType, TryIntoVal, U32Val,
+};
 
 pub(crate) fn write_asset_info(e: &Host, asset_info: AssetInfo) -> Result<(), HostError> {
     let key = InstanceDataKey::AssetInfo;
@@ -19,6 +23,10 @@ pub(crate) fn read_asset_info(e: &Host) -> Result<AssetInfo, HostError> {
     rv.try_into_val(e)
 }
 
+pub(crate) fn read_asset(e: &Host) -> Result<Asset, HostError> {
+    read_asset_info(e)?.try_into_val(e)
+}
+
 pub(crate) fn has_asset_info(e: &Host) -> Result<bool, HostError> {
     let key = InstanceDataKey::AssetInfo;
     let rv = e.has_contract_data(key.try_into_val(e)?, StorageType::Instance)?;
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs
index 27ea43d6..9713d08b 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs
@@ -1,22 +1,26 @@
 use std::rc::Rc;
 
-use crate::budget::AsBudget;
-use crate::builtin_contracts::base_types::{Address, BytesN};
-use crate::builtin_contracts::contract_error::ContractError;
-use crate::builtin_contracts::stellar_asset_contract::asset_info::read_asset_info;
-use crate::builtin_contracts::stellar_asset_contract::public_types::AssetInfo;
-use crate::builtin_contracts::stellar_asset_contract::storage_types::DataKey;
-use crate::builtin_contracts::storage_utils::StorageUtils;
-use crate::host::metered_clone::MeteredClone;
-use crate::host::Host;
-use crate::storage::Storage;
-use crate::{err, HostError};
-use soroban_env_common::xdr::{
-    AccountEntry, AccountEntryExt, AccountEntryExtensionV1Ext, AccountFlags, AccountId,
-    LedgerEntry, LedgerEntryData, LedgerKey, ScAddress, TrustLineAsset, TrustLineEntry,
-    TrustLineEntryExt, TrustLineFlags,
+use crate::{
+    budget::AsBudget,
+    builtin_contracts::{
+        base_types::{Address, BytesN},
+        contract_error::ContractError,
+        stellar_asset_contract::{
+            asset_info::{read_asset, read_asset_info},
+            public_types::AssetInfo,
+            storage_types::DataKey,
+        },
+    },
+    err,
+    host::metered_clone::MeteredClone,
+    storage::Storage,
+    xdr::{
+        AccountEntry, AccountEntryExt, AccountEntryExtensionV1Ext, AccountFlags, AccountId, Asset,
+        LedgerEntry, LedgerEntryData, LedgerKey, ScAddress, TrustLineAsset, TrustLineEntry,
+        TrustLineEntryExt, TrustLineFlags,
+    },
+    Env, Host, HostError, StorageType, TryIntoVal,
 };
-use soroban_env_common::{Env, StorageType, TryIntoVal};
 
 use super::storage_types::{BalanceValue, BALANCE_EXTEND_AMOUNT, BALANCE_TTL_THRESHOLD};
 
@@ -30,14 +34,14 @@ use super::storage_types::{BalanceValue, BALANCE_EXTEND_AMOUNT, BALANCE_TTL_THRE
 /// the AUTH_REQUIRED flag set, then the non-account identifier must first be authorized
 /// by the issuer/admin before it's allowed to hold a balance.
 
-// Metering: *mostly* covered by components. Not sure about `try_into_val`.
-pub fn read_balance(e: &Host, addr: Address) -> Result<i128, HostError> {
+// Metering: covered by components.
+pub(crate) fn read_balance(e: &Host, addr: Address) -> Result<i128, HostError> {
     match addr.to_sc_address()? {
         ScAddress::Account(acc_id) => Ok(get_classic_balance(e, acc_id)?.into()),
         ScAddress::Contract(_) => {
             let key = DataKey::Balance(addr);
             if let Some(raw_balance) =
-                StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Persistent)?
+                e.try_get_contract_data(key.try_into_val(e)?, StorageType::Persistent)?
             {
                 e.extend_contract_data_ttl(
                     key.try_into_val(e)?,
@@ -54,8 +58,16 @@ pub fn read_balance(e: &Host, addr: Address) -> Result<i128, HostError> {
     }
 }
 
-// Metering: *mostly* covered by components.
-fn write_balance(e: &Host, addr: Address, balance: BalanceValue) -> Result<(), HostError> {
+// Metering: covered by components.
+fn write_contract_balance(
+    e: &Host,
+    addr: Address,
+    balance: BalanceValue,
+    // We take an unused reference to a "witness" contract-id Hash here, to help
+    // ensure this function is only called from a context where `addr` has been
+    // matched as an ScAddress::Contract(hash) rather than ScAddress::Account(_)
+    _witness_addr_contract_id: &crate::xdr::Hash,
+) -> Result<(), HostError> {
     let key = DataKey::Balance(addr);
     e.put_contract_data(
         key.try_into_val(e)?,
@@ -73,7 +85,7 @@ fn write_balance(e: &Host, addr: Address, balance: BalanceValue) -> Result<(), H
 }
 
 // Metering: covered by components.
-pub fn receive_balance(e: &Host, addr: Address, amount: i128) -> Result<(), HostError> {
+pub(crate) fn receive_balance(e: &Host, addr: Address, amount: i128) -> Result<(), HostError> {
     if !is_authorized(e, addr.metered_clone(e)?)? {
         return Err(e.error(
             ContractError::BalanceDeauthorizedError.into(),
@@ -93,10 +105,10 @@ pub fn receive_balance(e: &Host, addr: Address, amount: i128) -> Result<(), Host
             })?;
             Ok(transfer_classic_balance(e, acc_id, i64_amount)?)
         }
-        ScAddress::Contract(_) => {
+        ScAddress::Contract(id) => {
             let key = DataKey::Balance(addr.metered_clone(e)?);
             let mut balance = if let Some(raw_balance) =
-                StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Persistent)?
+                e.try_get_contract_data(key.try_into_val(e)?, StorageType::Persistent)?
             {
                 raw_balance.try_into_val(e)?
             } else {
@@ -117,13 +129,13 @@ pub fn receive_balance(e: &Host, addr: Address, amount: i128) -> Result<(), Host
             })?;
 
             balance.amount = new_balance;
-            write_balance(e, addr, balance)
+            write_contract_balance(e, addr, balance, &id)
         }
     }
 }
 
-// TODO: Metering analysis
-pub fn spend_balance_no_authorization_check(
+// Metering: covered by components.
+pub(crate) fn spend_balance_no_authorization_check(
     e: &Host,
     addr: Address,
     amount: i128,
@@ -139,12 +151,12 @@ pub fn spend_balance_no_authorization_check(
             })?;
             transfer_classic_balance(e, acc_id, -i64_amount)
         }
-        ScAddress::Contract(_) => {
+        ScAddress::Contract(id) => {
             // If a balance exists, calculate new amount and write the existing authorized state as is because
             // this can be used to clawback when deauthorized.
             let key = DataKey::Balance(addr.metered_clone(e)?);
             if let Some(raw_balance) =
-                StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Persistent)?
+                e.try_get_contract_data(key.try_into_val(e)?, StorageType::Persistent)?
             {
                 let mut balance: BalanceValue = raw_balance.try_into_val(e)?;
                 if balance.amount < amount {
@@ -165,7 +177,7 @@ pub fn spend_balance_no_authorization_check(
                     })?;
                     balance.amount = new_balance;
 
-                    write_balance(e, addr, balance)?
+                    write_contract_balance(e, addr, balance, &id)?
                 }
             } else if amount > 0 {
                 return Err(err!(
@@ -181,7 +193,7 @@ pub fn spend_balance_no_authorization_check(
 }
 
 // Metering: covered by components.
-pub fn spend_balance(e: &Host, addr: Address, amount: i128) -> Result<(), HostError> {
+pub(crate) fn spend_balance(e: &Host, addr: Address, amount: i128) -> Result<(), HostError> {
     if !is_authorized(e, addr.metered_clone(e)?)? {
         return Err(e.error(
             ContractError::BalanceDeauthorizedError.into(),
@@ -193,14 +205,14 @@ pub fn spend_balance(e: &Host, addr: Address, amount: i128) -> Result<(), HostEr
     spend_balance_no_authorization_check(e, addr, amount)
 }
 
-// Metering: *mostly* covered by components. Not sure about `try_into_val`.
-pub fn is_authorized(e: &Host, addr: Address) -> Result<bool, HostError> {
+// Metering: covered by components.
+pub(crate) fn is_authorized(e: &Host, addr: Address) -> Result<bool, HostError> {
     match addr.to_sc_address()? {
         ScAddress::Account(acc_id) => is_account_authorized(e, acc_id),
         ScAddress::Contract(_) => {
             let key = DataKey::Balance(addr);
             if let Some(raw_balance) =
-                StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Persistent)?
+                e.try_get_contract_data(key.try_into_val(e)?, StorageType::Persistent)?
             {
                 let balance: BalanceValue = raw_balance.try_into_val(e)?;
                 Ok(balance.authorized)
@@ -211,8 +223,12 @@ pub fn is_authorized(e: &Host, addr: Address) -> Result<bool, HostError> {
     }
 }
 
-// Metering: *mostly* covered by components. Not sure about `try_into_val`.
-pub fn write_authorization(e: &Host, addr: Address, authorize: bool) -> Result<(), HostError> {
+// Metering: covered by components.
+pub(crate) fn write_authorization(
+    e: &Host,
+    addr: Address,
+    authorize: bool,
+) -> Result<(), HostError> {
     if !authorize && !is_asset_auth_revocable(e)? {
         return Err(e.error(
             ContractError::OperationNotSupportedError.into(),
@@ -223,14 +239,14 @@ pub fn write_authorization(e: &Host, addr: Address, authorize: bool) -> Result<(
 
     match addr.to_sc_address()? {
         ScAddress::Account(acc_id) => set_authorization(e, acc_id, authorize),
-        ScAddress::Contract(_) => {
+        ScAddress::Contract(id) => {
             let key = DataKey::Balance(addr.metered_clone(e)?);
             if let Some(raw_balance) =
-                StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Persistent)?
+                e.try_get_contract_data(key.try_into_val(e)?, StorageType::Persistent)?
             {
                 let mut balance: BalanceValue = raw_balance.try_into_val(e)?;
                 balance.authorized = authorize;
-                write_balance(e, addr, balance)
+                write_contract_balance(e, addr, balance, &id)
             } else {
                 // Balance does not exist, so write a 0 amount along with the authorization flag.
                 // No need to check auth_required because this function can only be called by the admin.
@@ -239,14 +255,14 @@ pub fn write_authorization(e: &Host, addr: Address, authorize: bool) -> Result<(
                     authorized: authorize,
                     clawback: is_asset_clawback_enabled(e)?,
                 };
-                write_balance(e, addr, balance)
+                write_contract_balance(e, addr, balance, &id)
             }
         }
     }
 }
 
-// TODO: Metering analysis
-pub fn check_clawbackable(e: &Host, addr: Address) -> Result<(), HostError> {
+// Metering: covered by components.
+pub(crate) fn check_clawbackable(e: &Host, addr: Address) -> Result<(), HostError> {
     let validate_trustline =
         |asset: TrustLineAsset, issuer: AccountId, account: AccountId| -> Result<(), HostError> {
             if issuer == account {
@@ -268,39 +284,27 @@ pub fn check_clawbackable(e: &Host, addr: Address) -> Result<(), HostError> {
         };
 
     match addr.to_sc_address()? {
-        ScAddress::Account(acc_id) => match read_asset_info(e)? {
-            AssetInfo::Native => Err(e.error(
+        ScAddress::Account(acc_id) => match read_asset(e)? {
+            Asset::Native => Err(e.error(
                 ContractError::OperationNotSupportedError.into(),
                 "cannot clawback native asset",
                 &[],
             )),
-            AssetInfo::AlphaNum4(asset) => {
-                let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-                validate_trustline(
-                    e.create_asset_4(
-                        asset.asset_code.to_array()?,
-                        issuer_account_id.metered_clone(e)?,
-                    ),
-                    issuer_account_id,
-                    acc_id,
-                )
+            Asset::CreditAlphanum4(asset) => {
+                let issuer = asset.issuer.metered_clone(e)?;
+                let tlasset = TrustLineAsset::CreditAlphanum4(asset);
+                validate_trustline(tlasset, issuer, acc_id)
             }
-            AssetInfo::AlphaNum12(asset) => {
-                let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-                validate_trustline(
-                    e.create_asset_12(
-                        asset.asset_code.to_array()?,
-                        issuer_account_id.metered_clone(e)?,
-                    ),
-                    issuer_account_id,
-                    acc_id,
-                )
+            Asset::CreditAlphanum12(asset) => {
+                let issuer = asset.issuer.metered_clone(e)?;
+                let tlasset = TrustLineAsset::CreditAlphanum12(asset);
+                validate_trustline(tlasset, issuer, acc_id)
             }
         },
         ScAddress::Contract(_) => {
             let key = DataKey::Balance(addr);
             if let Some(raw_balance) =
-                StorageUtils::try_get(e, key.try_into_val(e)?, StorageType::Persistent)?
+                e.try_get_contract_data(key.try_into_val(e)?, StorageType::Persistent)?
             {
                 let balance: BalanceValue = raw_balance.try_into_val(e)?;
                 if !balance.clawback {
@@ -327,8 +331,12 @@ pub fn check_clawbackable(e: &Host, addr: Address) -> Result<(), HostError> {
 }
 
 // Metering: covered by components
-pub fn transfer_classic_balance(e: &Host, to_key: AccountId, amount: i64) -> Result<(), HostError> {
-    let transfer_trustline_balance_safe =
+pub(crate) fn transfer_classic_balance(
+    e: &Host,
+    to_key: AccountId,
+    amount: i64,
+) -> Result<(), HostError> {
+    let transfer_trustline_balance_unless_issuer =
         |asset: TrustLineAsset, issuer: AccountId, to: AccountId| -> Result<(), HostError> {
             if issuer == to {
                 return Ok(());
@@ -337,75 +345,48 @@ pub fn transfer_classic_balance(e: &Host, to_key: AccountId, amount: i64) -> Res
             transfer_trustline_balance(e, to, asset, amount)
         };
 
-    match read_asset_info(e)? {
-        AssetInfo::Native => transfer_account_balance(e, to_key, amount)?,
-        AssetInfo::AlphaNum4(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            transfer_trustline_balance_safe(
-                e.create_asset_4(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                to_key,
-            )?
+    match read_asset(e)? {
+        Asset::Native => transfer_account_balance(e, to_key, amount),
+        Asset::CreditAlphanum4(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum4(asset);
+            transfer_trustline_balance_unless_issuer(tlasset, issuer, to_key)
         }
-        AssetInfo::AlphaNum12(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            transfer_trustline_balance_safe(
-                e.create_asset_12(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                to_key,
-            )?
+        Asset::CreditAlphanum12(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum12(asset);
+            transfer_trustline_balance_unless_issuer(tlasset, issuer, to_key)
         }
-    };
-    Ok(())
+    }
 }
 
-// TODO: Metering analysis
-//returns (total balance, spendable balance)
-fn get_classic_balance(e: &Host, to_key: AccountId) -> Result<i64, HostError> {
-    let get_trustline_balance_safe =
-        |asset: TrustLineAsset, issuer: AccountId, to: AccountId| -> Result<i64, HostError> {
-            if issuer == to {
+// Metering: covered by components.
+fn get_classic_balance(e: &Host, acct: AccountId) -> Result<i64, HostError> {
+    let get_trustline_balance_or_max_if_issuer =
+        |asset: TrustLineAsset, issuer: AccountId, acct: AccountId| -> Result<i64, HostError> {
+            if issuer == acct {
                 return Ok(i64::MAX);
             }
 
-            get_trustline_balance(e, to, asset)
+            get_trustline_balance(e, acct, asset)
         };
 
-    match read_asset_info(e)? {
-        AssetInfo::Native => get_account_balance(e, to_key),
-        AssetInfo::AlphaNum4(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            get_trustline_balance_safe(
-                e.create_asset_4(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                to_key,
-            )
+    match read_asset(e)? {
+        Asset::Native => get_account_balance(e, acct),
+        Asset::CreditAlphanum4(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum4(asset);
+            get_trustline_balance_or_max_if_issuer(tlasset, issuer, acct)
         }
-
-        AssetInfo::AlphaNum12(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            get_trustline_balance_safe(
-                e.create_asset_12(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                to_key,
-            )
+        Asset::CreditAlphanum12(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum12(asset);
+            get_trustline_balance_or_max_if_issuer(tlasset, issuer, acct)
         }
     }
 }
 
-// Metering: *mostly* covered by components. The arithmetics are free.
+// Metering: covered by components.
 fn transfer_account_balance(
     host: &Host,
     account_id: AccountId,
@@ -505,7 +486,7 @@ fn read_trustline_entry(
         })
 }
 
-// Metering: *mostly* covered by components. The arithmatics are free.
+// Metering: covered by components.
 fn transfer_trustline_balance(
     host: &Host,
     account_id: AccountId,
@@ -552,7 +533,6 @@ fn transfer_trustline_balance(
 }
 
 // Metering: covered by components
-//returns (total balance, spendable balance)
 fn get_account_balance(host: &Host, account_id: AccountId) -> Result<i64, HostError> {
     let lk = host.to_account_key(account_id)?;
 
@@ -568,11 +548,18 @@ fn get_account_balance(host: &Host, account_id: AccountId) -> Result<i64, HostEr
             )),
         }?;
 
-        let min = get_min_max_account_balance(host, ae)?.0;
+        let (min, max) = get_min_max_account_balance(host, ae)?;
         if ae.balance < min {
             return Err(host.error(
                 ContractError::InternalError.into(),
-                "account has balance < spendable_balance",
+                "account has balance < minimum",
+                &[],
+            ));
+        }
+        if ae.balance > max {
+            return Err(host.error(
+                ContractError::InternalError.into(),
+                "account has balance > maximum",
                 &[],
             ));
         }
@@ -580,7 +567,7 @@ fn get_account_balance(host: &Host, account_id: AccountId) -> Result<i64, HostEr
     })
 }
 
-// TODO: Metering analysis
+// Metering: covered by components.
 fn get_min_max_account_balance(e: &Host, ae: &AccountEntry) -> Result<(i64, i64), HostError> {
     if ae.balance < 0 {
         return Err(e.error(
@@ -609,8 +596,7 @@ fn get_min_max_account_balance(e: &Host, ae: &AccountEntry) -> Result<(i64, i64)
     }
 }
 
-// Metering: *mostly* covered by components. The arithmatics are free.
-// returns (total balance, spendable balance)
+// Metering: covered by components.
 fn get_trustline_balance(
     host: &Host,
     account_id: AccountId,
@@ -629,11 +615,18 @@ fn get_trustline_balance(
             )),
         }?;
 
-        let min = get_min_max_trustline_balance(host, &tl)?.0;
+        let (min, max) = get_min_max_trustline_balance(host, &tl)?;
         if tl.balance < min {
             return Err(host.error(
                 ContractError::InternalError.into(),
-                "trustline has balance < spendable_balance",
+                "trustline has balance < minimum",
+                &[],
+            ));
+        }
+        if tl.balance > max {
+            return Err(host.error(
+                ContractError::InternalError.into(),
+                "trustline has balance > maximum",
                 &[],
             ));
         }
@@ -641,7 +634,7 @@ fn get_trustline_balance(
     })
 }
 
-// TODO: Metering analysis
+// Metering: covered by components.
 fn get_min_max_trustline_balance(e: &Host, tl: &TrustLineEntry) -> Result<(i64, i64), HostError> {
     if tl.balance < 0 {
         return Err(e.error(
@@ -669,9 +662,9 @@ fn get_min_max_trustline_balance(e: &Host, tl: &TrustLineEntry) -> Result<(i64,
     }
 }
 
-// TODO: Metering analysis
+// Metering: covered by components.
 fn is_account_authorized(e: &Host, account_id: AccountId) -> Result<bool, HostError> {
-    let is_trustline_authorized_safe =
+    let is_trustline_authorized_or_issuer =
         |asset: TrustLineAsset, issuer: AccountId, to: AccountId| -> Result<bool, HostError> {
             if issuer == to {
                 return Ok(true);
@@ -679,34 +672,22 @@ fn is_account_authorized(e: &Host, account_id: AccountId) -> Result<bool, HostEr
             is_trustline_authorized(e, to, asset)
         };
 
-    match read_asset_info(e)? {
-        AssetInfo::Native => Ok(true),
-        AssetInfo::AlphaNum4(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            is_trustline_authorized_safe(
-                e.create_asset_4(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                account_id,
-            )
+    match read_asset(e)? {
+        Asset::Native => Ok(true),
+        Asset::CreditAlphanum4(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum4(asset);
+            is_trustline_authorized_or_issuer(tlasset, issuer, account_id)
         }
-        AssetInfo::AlphaNum12(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            is_trustline_authorized_safe(
-                e.create_asset_12(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                account_id,
-            )
+        Asset::CreditAlphanum12(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum12(asset);
+            is_trustline_authorized_or_issuer(tlasset, issuer, account_id)
         }
     }
 }
 
-// TODO: Metering analysis
+// Metering: covered by components.
 fn get_trustline_flags(
     host: &Host,
     account_id: AccountId,
@@ -729,7 +710,7 @@ fn get_trustline_flags(
     })
 }
 
-// Metering: *mostly* covered by components. The arithmatics are free.
+// Metering: covered by components.
 fn is_trustline_authorized(
     e: &Host,
     account_id: AccountId,
@@ -739,10 +720,10 @@ fn is_trustline_authorized(
     Ok(tl_flags & (TrustLineFlags::AuthorizedFlag as u32) != 0)
 }
 
-fn set_authorization(e: &Host, to_key: AccountId, authorize: bool) -> Result<(), HostError> {
-    let set_trustline_authorization_safe =
-        |asset: TrustLineAsset, issuer: AccountId, to: AccountId| -> Result<(), HostError> {
-            if issuer == to {
+fn set_authorization(e: &Host, acct: AccountId, authorize: bool) -> Result<(), HostError> {
+    let set_trustline_authorization_unless_issuer =
+        |asset: TrustLineAsset, issuer: AccountId, acct: AccountId| -> Result<(), HostError> {
+            if issuer == acct {
                 return Err(e.error(
                     ContractError::OperationNotSupportedError.into(),
                     "issuer doesn't have a trustline",
@@ -750,36 +731,24 @@ fn set_authorization(e: &Host, to_key: AccountId, authorize: bool) -> Result<(),
                 ));
             }
 
-            set_trustline_authorization(e, to, asset, authorize)
+            set_trustline_authorization(e, acct, asset, authorize)
         };
 
-    match read_asset_info(e)? {
-        AssetInfo::Native => Err(e.error(
+    match read_asset(e)? {
+        Asset::Native => Err(e.error(
             ContractError::OperationNotSupportedError.into(),
             "expected trustline asset",
             &[],
         )),
-        AssetInfo::AlphaNum4(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            set_trustline_authorization_safe(
-                e.create_asset_4(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                to_key,
-            )
+        Asset::CreditAlphanum4(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum4(asset);
+            set_trustline_authorization_unless_issuer(tlasset, issuer, acct)
         }
-        AssetInfo::AlphaNum12(asset) => {
-            let issuer_account_id = e.account_id_from_bytesobj(asset.issuer.into())?;
-            set_trustline_authorization_safe(
-                e.create_asset_12(
-                    asset.asset_code.to_array()?,
-                    issuer_account_id.metered_clone(e)?,
-                ),
-                issuer_account_id,
-                to_key,
-            )
+        Asset::CreditAlphanum12(asset) => {
+            let issuer = asset.issuer.metered_clone(e)?;
+            let tlasset = TrustLineAsset::CreditAlphanum12(asset);
+            set_trustline_authorization_unless_issuer(tlasset, issuer, acct)
         }
     }
 }
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/contract.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/contract.rs
index 5a49c9c0..0cea5579 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/contract.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/contract.rs
@@ -1,6 +1,6 @@
 use core::cmp::Ordering;
 
-use crate::builtin_contracts::base_types::{Address, Bytes, BytesN, String};
+use crate::builtin_contracts::base_types::{Address, BytesN, String};
 use crate::builtin_contracts::contract_error::ContractError;
 use crate::builtin_contracts::stellar_asset_contract::allowance::{
     read_allowance, spend_allowance, write_allowance,
@@ -14,7 +14,7 @@ use crate::builtin_contracts::stellar_asset_contract::balance::{
 use crate::builtin_contracts::stellar_asset_contract::event;
 use crate::builtin_contracts::stellar_asset_contract::public_types::AssetInfo;
 use crate::host::{metered_clone::MeteredClone, Host};
-use crate::{err, HostError};
+use crate::{err, BytesObject, HostError};
 
 use soroban_builtin_sdk_macros::contractimpl;
 use soroban_env_common::xdr::Asset;
@@ -27,7 +27,7 @@ use super::metadata::{read_name, read_symbol, set_metadata, DECIMAL};
 use super::public_types::{AlphaNum12AssetInfo, AlphaNum4AssetInfo};
 use super::storage_types::{INSTANCE_EXTEND_AMOUNT, INSTANCE_TTL_THRESHOLD};
 
-pub struct StellarAssetContract;
+pub(crate) struct StellarAssetContract;
 
 fn check_nonnegative_amount(e: &Host, amount: i128) -> Result<(), HostError> {
     if amount < 0 {
@@ -78,7 +78,7 @@ fn check_not_issuer(e: &Host, addr: &Address) -> Result<(), HostError> {
 #[contractimpl]
 // Metering: *mostly* covered by components.
 impl StellarAssetContract {
-    pub fn init_asset(e: &Host, asset_bytes: Bytes) -> Result<(), HostError> {
+    pub(crate) fn init_asset(e: &Host, asset_bytes: BytesObject) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract init_asset");
         if has_asset_info(e)? {
             return Err(e.error(
@@ -88,7 +88,7 @@ impl StellarAssetContract {
             ));
         }
 
-        let asset: Asset = e.metered_from_xdr_obj(asset_bytes.into())?;
+        let asset: Asset = e.metered_from_xdr_obj(asset_bytes)?;
         validate_asset(e, &asset)?;
 
         let curr_contract_id = e.get_current_contract_id_internal()?;
@@ -144,7 +144,7 @@ impl StellarAssetContract {
         Ok(())
     }
 
-    pub fn allowance(e: &Host, from: Address, spender: Address) -> Result<i128, HostError> {
+    pub(crate) fn allowance(e: &Host, from: Address, spender: Address) -> Result<i128, HostError> {
         let _span = tracy_span!("stellar asset contract allowance");
         e.extend_current_contract_instance_and_code_ttl(
             INSTANCE_TTL_THRESHOLD.into(),
@@ -154,7 +154,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn approve(
+    pub(crate) fn approve(
         e: &Host,
         from: Address,
         spender: Address,
@@ -182,7 +182,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn balance(e: &Host, addr: Address) -> Result<i128, HostError> {
+    pub(crate) fn balance(e: &Host, addr: Address) -> Result<i128, HostError> {
         let _span = tracy_span!("stellar asset contract balance");
         e.extend_current_contract_instance_and_code_ttl(
             INSTANCE_TTL_THRESHOLD.into(),
@@ -192,7 +192,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn authorized(e: &Host, addr: Address) -> Result<bool, HostError> {
+    pub(crate) fn authorized(e: &Host, addr: Address) -> Result<bool, HostError> {
         let _span = tracy_span!("stellar asset contract authorized");
         e.extend_current_contract_instance_and_code_ttl(
             INSTANCE_TTL_THRESHOLD.into(),
@@ -202,7 +202,12 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn transfer(e: &Host, from: Address, to: Address, amount: i128) -> Result<(), HostError> {
+    pub(crate) fn transfer(
+        e: &Host,
+        from: Address,
+        to: Address,
+        amount: i128,
+    ) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract transfer");
         check_nonnegative_amount(e, amount)?;
         from.require_auth()?;
@@ -219,7 +224,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn transfer_from(
+    pub(crate) fn transfer_from(
         e: &Host,
         spender: Address,
         from: Address,
@@ -243,7 +248,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn burn(e: &Host, from: Address, amount: i128) -> Result<(), HostError> {
+    pub(crate) fn burn(e: &Host, from: Address, amount: i128) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract burn");
         check_nonnegative_amount(e, amount)?;
         check_non_native(e)?;
@@ -262,7 +267,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn burn_from(
+    pub(crate) fn burn_from(
         e: &Host,
         spender: Address,
         from: Address,
@@ -287,7 +292,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn clawback(e: &Host, from: Address, amount: i128) -> Result<(), HostError> {
+    pub(crate) fn clawback(e: &Host, from: Address, amount: i128) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract clawback");
         check_nonnegative_amount(e, amount)?;
         check_clawbackable(e, from.metered_clone(e)?)?;
@@ -307,7 +312,11 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn set_authorized(e: &Host, addr: Address, authorize: bool) -> Result<(), HostError> {
+    pub(crate) fn set_authorized(
+        e: &Host,
+        addr: Address,
+        authorize: bool,
+    ) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract set_authorized");
         let admin = read_administrator(e)?;
         admin.require_auth()?;
@@ -323,7 +332,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn mint(e: &Host, to: Address, amount: i128) -> Result<(), HostError> {
+    pub(crate) fn mint(e: &Host, to: Address, amount: i128) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract mint");
         check_nonnegative_amount(e, amount)?;
         check_not_issuer(e, &to)?;
@@ -342,7 +351,7 @@ impl StellarAssetContract {
     }
 
     // Metering: covered by components
-    pub fn set_admin(e: &Host, new_admin: Address) -> Result<(), HostError> {
+    pub(crate) fn set_admin(e: &Host, new_admin: Address) -> Result<(), HostError> {
         let _span = tracy_span!("stellar asset contract set_admin");
         let admin = read_administrator(e)?;
         admin.require_auth()?;
@@ -357,23 +366,23 @@ impl StellarAssetContract {
         Ok(())
     }
 
-    pub fn admin(e: &Host) -> Result<Address, HostError> {
+    pub(crate) fn admin(e: &Host) -> Result<Address, HostError> {
         let _span = tracy_span!("stellar asset contract admin");
         read_administrator(e)
     }
 
-    pub fn decimals(_e: &Host) -> Result<u32, HostError> {
+    pub(crate) fn decimals(_e: &Host) -> Result<u32, HostError> {
         let _span = tracy_span!("stellar asset contract decimals");
         // no need to load metadata since this is fixed for all SAC tokens
         Ok(DECIMAL)
     }
 
-    pub fn name(e: &Host) -> Result<String, HostError> {
+    pub(crate) fn name(e: &Host) -> Result<String, HostError> {
         let _span = tracy_span!("stellar asset contract name");
         read_name(e)
     }
 
-    pub fn symbol(e: &Host) -> Result<String, HostError> {
+    pub(crate) fn symbol(e: &Host) -> Result<String, HostError> {
         let _span = tracy_span!("stellar asset contract symbol");
         read_symbol(e)
     }
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/event.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/event.rs
index a8d7e5ab..c4c33c32 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/event.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/event.rs
@@ -1,6 +1,7 @@
-use crate::HostError;
-use crate::{builtin_contracts::base_types::Address, host::Host};
-use soroban_env_common::{Env, Symbol, TryFromVal, TryIntoVal};
+use crate::{
+    builtin_contracts::base_types::Address, host::Host, Env, HostError, Symbol, TryFromVal,
+    TryIntoVal,
+};
 
 use super::metadata::read_name;
 
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/metadata.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/metadata.rs
index 569daf9e..81a00531 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/metadata.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/metadata.rs
@@ -16,7 +16,7 @@ const METADATA_KEY: &str = "METADATA";
 
 #[derive(Clone)]
 #[contracttype]
-pub struct StellarAssetContractMetadata {
+pub(crate) struct StellarAssetContractMetadata {
     pub decimal: u32,
     pub name: String,
     pub symbol: String,
@@ -153,7 +153,7 @@ fn render_sep0011_asset<const N: usize>(
     ))
 }
 
-pub fn set_metadata(e: &Host) -> Result<(), HostError> {
+pub(crate) fn set_metadata(e: &Host) -> Result<(), HostError> {
     let name_and_symbol: (String, String) = match read_asset_info(e)? {
         AssetInfo::Native => {
             let n = String::try_from_val(e, &e.string_new_from_slice(b"native")?)?;
@@ -182,7 +182,7 @@ pub fn set_metadata(e: &Host) -> Result<(), HostError> {
     Ok(())
 }
 
-pub fn read_name(e: &Host) -> Result<String, HostError> {
+pub(crate) fn read_name(e: &Host) -> Result<String, HostError> {
     let key = SymbolSmall::try_from_str(METADATA_KEY)?;
     let metadata: StellarAssetContractMetadata = e
         .get_contract_data(key.try_into_val(e)?, StorageType::Instance)?
@@ -190,7 +190,7 @@ pub fn read_name(e: &Host) -> Result<String, HostError> {
     Ok(metadata.name)
 }
 
-pub fn read_symbol(e: &Host) -> Result<String, HostError> {
+pub(crate) fn read_symbol(e: &Host) -> Result<String, HostError> {
     let key = SymbolSmall::try_from_str(METADATA_KEY)?;
     let metadata: StellarAssetContractMetadata = e
         .get_contract_data(key.try_into_val(e)?, StorageType::Instance)?
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/public_types.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/public_types.rs
index 5d71d593..ccd7296c 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/public_types.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/public_types.rs
@@ -1,25 +1,46 @@
-use crate::builtin_contracts::base_types::{BytesN, String};
+use crate::{
+    builtin_contracts::base_types::{BytesN, String},
+    xdr::Asset,
+    Host, HostError, TryFromVal, TryIntoVal,
+};
 use soroban_builtin_sdk_macros::contracttype;
-use soroban_env_common::TryIntoVal;
 
 #[derive(Clone)]
 #[contracttype]
-pub struct AlphaNum4AssetInfo {
+pub(crate) struct AlphaNum4AssetInfo {
     pub asset_code: String,
     pub issuer: BytesN<32>,
 }
 
 #[derive(Clone)]
 #[contracttype]
-pub struct AlphaNum12AssetInfo {
+pub(crate) struct AlphaNum12AssetInfo {
     pub asset_code: String,
     pub issuer: BytesN<32>,
 }
 
 #[derive(Clone)]
 #[contracttype]
-pub enum AssetInfo {
+pub(crate) enum AssetInfo {
     Native,
     AlphaNum4(AlphaNum4AssetInfo),
     AlphaNum12(AlphaNum12AssetInfo),
 }
+
+impl TryFromVal<Host, AssetInfo> for Asset {
+    type Error = HostError;
+
+    fn try_from_val(env: &Host, v: &AssetInfo) -> Result<Self, Self::Error> {
+        match v {
+            AssetInfo::Native => Ok(Asset::Native),
+            AssetInfo::AlphaNum4(asset) => {
+                let issuer_account_id = env.account_id_from_bytesobj(asset.issuer.as_object())?;
+                Ok(env.create_asset_4(asset.asset_code.to_array()?, issuer_account_id))
+            }
+            AssetInfo::AlphaNum12(asset) => {
+                let issuer_account_id = env.account_id_from_bytesobj(asset.issuer.as_object())?;
+                Ok(env.create_asset_12(asset.asset_code.to_array()?, issuer_account_id))
+            }
+        }
+    }
+}
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/storage_types.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/storage_types.rs
index 4497904f..d271873c 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/storage_types.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/storage_types.rs
@@ -1,6 +1,5 @@
-use crate::builtin_contracts::base_types::Address;
+use crate::{builtin_contracts::base_types::Address, TryIntoVal};
 use soroban_builtin_sdk_macros::contracttype;
-use soroban_env_common::TryIntoVal;
 
 pub(crate) const DAY_IN_LEDGERS: u32 = 17280;
 pub(crate) const INSTANCE_EXTEND_AMOUNT: u32 = 7 * DAY_IN_LEDGERS;
@@ -10,19 +9,19 @@ pub(crate) const BALANCE_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS;
 pub(crate) const BALANCE_TTL_THRESHOLD: u32 = BALANCE_EXTEND_AMOUNT - DAY_IN_LEDGERS;
 
 #[contracttype]
-pub struct AllowanceDataKey {
+pub(crate) struct AllowanceDataKey {
     pub from: Address,
     pub spender: Address,
 }
 
 #[contracttype]
-pub struct AllowanceValue {
+pub(crate) struct AllowanceValue {
     pub amount: i128,
     pub live_until_ledger: u32,
 }
 
 #[contracttype]
-pub struct BalanceValue {
+pub(crate) struct BalanceValue {
     pub amount: i128,
     pub authorized: bool,
     pub clawback: bool,
@@ -30,14 +29,14 @@ pub struct BalanceValue {
 
 /// Keys for the persistent data associated with stellar asset contract users.
 #[contracttype]
-pub enum DataKey {
+pub(crate) enum DataKey {
     Allowance(AllowanceDataKey),
     Balance(Address),
 }
 
 /// Keys for stellar asset contract instance data.
 #[contracttype]
-pub enum InstanceDataKey {
+pub(crate) enum InstanceDataKey {
     Admin,
     AssetInfo,
 }
diff --git a/soroban-env-host/src/builtin_contracts/storage_utils.rs b/soroban-env-host/src/builtin_contracts/storage_utils.rs
index 02f40a6b..b99283f8 100644
--- a/soroban-env-host/src/builtin_contracts/storage_utils.rs
+++ b/soroban-env-host/src/builtin_contracts/storage_utils.rs
@@ -1,13 +1,13 @@
-use soroban_env_common::{Env, StorageType, Val};
+use crate::{Env, Host, HostError, StorageType, Val};
 
-use crate::{Host, HostError};
-
-pub(crate) struct StorageUtils {}
-
-impl StorageUtils {
-    pub(crate) fn try_get(e: &Host, k: Val, t: StorageType) -> Result<Option<Val>, HostError> {
-        if e.has_contract_data(k, t)?.into() {
-            Ok(Some(e.get_contract_data(k, t)?))
+impl Host {
+    pub(crate) fn try_get_contract_data(
+        &self,
+        k: Val,
+        t: StorageType,
+    ) -> Result<Option<Val>, HostError> {
+        if self.has_contract_data(k, t)?.into() {
+            Ok(Some(self.get_contract_data(k, t)?))
         } else {
             Ok(None)
         }
diff --git a/soroban-env-host/src/host/data_helper.rs b/soroban-env-host/src/host/data_helper.rs
index 62830f60..0e42401c 100644
--- a/soroban-env-host/src/host/data_helper.rs
+++ b/soroban-env-host/src/host/data_helper.rs
@@ -11,10 +11,10 @@ use soroban_env_common::{AddressObject, Env, StorageType, U32Val, Val};
 use crate::budget::AsBudget;
 use crate::storage::{InstanceStorageMap, Storage};
 use crate::xdr::{
-    AccountEntry, AccountId, ContractDataEntry, Hash, HashIdPreimage, LedgerEntry, LedgerEntryData,
-    LedgerEntryExt, LedgerKey, LedgerKeyAccount, LedgerKeyContractCode, LedgerKeyContractData,
-    LedgerKeyTrustLine, PublicKey, ScVal, Signer, SignerKey, ThresholdIndexes, TrustLineAsset,
-    Uint256,
+    AccountEntry, AccountId, Asset, ContractDataEntry, Hash, HashIdPreimage, LedgerEntry,
+    LedgerEntryData, LedgerEntryExt, LedgerKey, LedgerKeyAccount, LedgerKeyContractCode,
+    LedgerKeyContractData, LedgerKeyTrustLine, PublicKey, ScVal, Signer, SignerKey,
+    ThresholdIndexes, TrustLineAsset, Uint256,
 };
 use crate::{err, Host, HostError};
 
@@ -303,21 +303,17 @@ impl Host {
         Rc::metered_new(LedgerKey::Account(LedgerKeyAccount { account_id }), self)
     }
 
-    pub(crate) fn create_asset_4(&self, asset_code: [u8; 4], issuer: AccountId) -> TrustLineAsset {
+    pub(crate) fn create_asset_4(&self, asset_code: [u8; 4], issuer: AccountId) -> Asset {
         use crate::xdr::{AlphaNum4, AssetCode4};
-        TrustLineAsset::CreditAlphanum4(AlphaNum4 {
+        Asset::CreditAlphanum4(AlphaNum4 {
             asset_code: AssetCode4(asset_code),
             issuer,
         })
     }
 
-    pub(crate) fn create_asset_12(
-        &self,
-        asset_code: [u8; 12],
-        issuer: AccountId,
-    ) -> TrustLineAsset {
+    pub(crate) fn create_asset_12(&self, asset_code: [u8; 12], issuer: AccountId) -> Asset {
         use crate::xdr::{AlphaNum12, AssetCode12};
-        TrustLineAsset::CreditAlphanum12(AlphaNum12 {
+        Asset::CreditAlphanum12(AlphaNum12 {
             asset_code: AssetCode12(asset_code),
             issuer,
         })
@@ -576,4 +572,30 @@ impl Host {
         );
         Ok(test_contract_executable == instance.executable)
     }
+
+    #[cfg(test)]
+    pub(crate) fn create_tl_asset_4(
+        &self,
+        asset_code: [u8; 4],
+        issuer: AccountId,
+    ) -> TrustLineAsset {
+        use crate::xdr::{AlphaNum4, AssetCode4};
+        TrustLineAsset::CreditAlphanum4(AlphaNum4 {
+            asset_code: AssetCode4(asset_code),
+            issuer,
+        })
+    }
+
+    #[cfg(test)]
+    pub(crate) fn create_tl_asset_12(
+        &self,
+        asset_code: [u8; 12],
+        issuer: AccountId,
+    ) -> TrustLineAsset {
+        use crate::xdr::{AlphaNum12, AssetCode12};
+        TrustLineAsset::CreditAlphanum12(AlphaNum12 {
+            asset_code: AssetCode12(asset_code),
+            issuer,
+        })
+    }
 }


Test patch:
diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/test_stellar_asset_contract.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/test_stellar_asset_contract.rs
index 0a9d0857..33522354 100644
--- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/test_stellar_asset_contract.rs
+++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/test_stellar_asset_contract.rs
@@ -1,6 +1,6 @@
 use crate::{
     builtin_contracts::{
-        base_types::{Address, Bytes, String},
+        base_types::{Address, String},
         testutils::{authorize_single_invocation, ContractTypeVec, TestSigner},
     },
     xdr::{Asset, Limited, WriteXdr},
@@ -14,16 +14,14 @@ pub(crate) struct TestStellarAssetContract<'a> {
 
 impl<'a> TestStellarAssetContract<'a> {
     pub(crate) fn new_from_asset(host: &'a Host, asset: Asset) -> Result<Self, HostError> {
+        use crate::EnvBase;
         let mut asset_bytes_vec = Limited::new(vec![], DEFAULT_XDR_RW_LIMITS);
         // Note: only asset creation should be return error, otherwise
         // `unwrap`s are part of test setup and thus shouldn't be confused with
         // contract creation errors we're interested in.
         asset.write_xdr(&mut asset_bytes_vec).unwrap();
-        let address_obj = host.create_asset_contract(
-            Bytes::from_slice(host, &asset_bytes_vec.inner.as_slice())
-                .unwrap()
-                .into(),
-        )?;
+        let address_obj = host
+            .create_asset_contract(host.bytes_new_from_slice(&asset_bytes_vec.inner.as_slice())?)?;
         Ok(Self {
             address: Address::try_from_val(host, &address_obj).unwrap(),
             host,
diff --git a/soroban-env-host/src/test/auth.rs b/soroban-env-host/src/test/auth.rs
index 79442a88..a69c36e5 100644
--- a/soroban-env-host/src/test/auth.rs
+++ b/soroban-env-host/src/test/auth.rs
@@ -27,10 +27,10 @@ use pretty_assertions::assert_eq;
 #[derive(Clone)]
 #[contracttype]
 pub struct ContractTreeNode {
-    pub contract: Address,
-    pub need_auth: HostVec,
-    pub children: HostVec,
-    pub try_call: bool,
+    pub(crate) contract: Address,
+    pub(crate) need_auth: HostVec,
+    pub(crate) children: HostVec,
+    pub(crate) try_call: bool,
 }
 
 struct AuthTest {
diff --git a/soroban-env-host/src/test/hostile_opt.rs b/soroban-env-host/src/test/hostile_opt.rs
index e4067513..39e5bf1e 100644
--- a/soroban-env-host/src/test/hostile_opt.rs
+++ b/soroban-env-host/src/test/hostile_opt.rs
@@ -1,9 +1,9 @@
-use crate::budget::AsBudget;
-use crate::builtin_contracts::base_types::{Address, Bytes};
-use crate::test::observe::ObservedHost;
-use crate::{Host, HostError, DEFAULT_HOST_DEPTH_LIMIT, DEFAULT_XDR_RW_LIMITS};
+use crate::{
+    budget::AsBudget, builtin_contracts::base_types::Address, test::observe::ObservedHost,
+    BytesObject, Env, EnvBase, Host, HostError, Symbol, TryFromVal, TryIntoVal, Val,
+    DEFAULT_HOST_DEPTH_LIMIT, DEFAULT_XDR_RW_LIMITS,
+};
 use soroban_builtin_sdk_macros::contracttype;
-use soroban_env_common::{Env, Symbol, TryFromVal, TryIntoVal, Val};
 use soroban_test_wasms::RECURSIVE_ACCOUNT_CONTRACT;
 
 use crate::xdr::{
@@ -12,10 +12,10 @@ use crate::xdr::{
 };
 
 #[contracttype]
-pub enum RecursiveAccountSignature {
+enum RecursiveAccountSignature {
     RedirectAddress(Address),
     SerializeValue,
-    DeserializeValue(Bytes),
+    DeserializeValue(BytesObject),
 }
 
 fn create_recursive_serialized_scval(depth: u32) -> Vec<u8> {
@@ -70,8 +70,7 @@ fn run_deep_host_stack_test(
             if deserialization_depth > 0 {
                 assert_eq!(serialization_depth, 0);
                 RecursiveAccountSignature::DeserializeValue(
-                    Bytes::from_slice(
-                        &host,
+                    host.bytes_new_from_slice(
                         create_recursive_serialized_scval(deserialization_depth).as_slice(),
                     )
                     .unwrap(),
diff --git a/soroban-env-host/src/test/stellar_asset_contract.rs b/soroban-env-host/src/test/stellar_asset_contract.rs
index d36d969f..f6e1918a 100644
--- a/soroban-env-host/src/test/stellar_asset_contract.rs
+++ b/soroban-env-host/src/test/stellar_asset_contract.rs
@@ -214,12 +214,12 @@ impl StellarAssetContractTest {
             4 => {
                 let mut code = [0_u8; 4];
                 code.copy_from_slice(asset_code);
-                self.host.create_asset_4(code, issuer.clone())
+                self.host.create_tl_asset_4(code, issuer.clone())
             }
             12 => {
                 let mut code = [0_u8; 12];
                 code.copy_from_slice(asset_code);
-                self.host.create_asset_12(code, issuer.clone())
+                self.host.create_tl_asset_12(code, issuer.clone())
             }
             _ => unreachable!(),
         };