Repository: stellar/rs-soroban-env
Pull request #1015 (2023-08-23 18:17:13)

Refactor host to support the new expiration ledger approach.
### What

Refactor host to support the new expiration ledger approach.

- Pass expiration ledgers as side input to the ledger entries (temporarily set `expiration_ledger_seq` to 0 until it's removed from XDR)
- Get rid of the autobump support.

### Why

Supporting the new way for specifying entry expiration

### Known limitations

N/A



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 71db15cc..9c04bd48 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1506,7 +1506,7 @@ dependencies = [
 [[package]]
 name = "stellar-xdr"
 version = "0.0.17"
-source = "git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567#e2a9cbf72d94941de1bde6ba34a38e1f49328567"
+source = "git+https://github.com/stellar/rs-stellar-xdr?rev=936273b737b99d79eee7a28dd4823436d0bd0abb#936273b737b99d79eee7a28dd4823436d0bd0abb"
 dependencies = [
  "arbitrary",
  "base64 0.13.1",
diff --git a/Cargo.toml b/Cargo.toml
index 92e3a77f..56f4c7d3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,7 +28,7 @@ soroban-native-sdk-macros = { version = "0.0.17", path = "soroban-native-sdk-mac
 [workspace.dependencies.stellar-xdr]
 version = "0.0.17"
 git = "https://github.com/stellar/rs-stellar-xdr"
-rev = "e2a9cbf72d94941de1bde6ba34a38e1f49328567"
+rev = "936273b737b99d79eee7a28dd4823436d0bd0abb"
 default-features = false
 
 [workspace.dependencies.wasmi]
diff --git a/soroban-env-common/env.json b/soroban-env-common/env.json
index bf016720..287ba778 100644
--- a/soroban-env-common/env.json
+++ b/soroban-env-common/env.json
@@ -1237,14 +1237,9 @@
                         {
                             "name": "t",
                             "type": "StorageType"
-                        },
-                        {
-                            "name": "f",
-                            "type": "Val"
                         }
                     ],
-                    "return": "Void",
-                    "docs": "If `f` is `Void`, then there will be no changes to flags for an existing entry, and none will be set if this is a new entry. Otherwise, `f` is parsed as a `u32`. If the value is 0, then all flags are cleared. If it's not 0, then flags will be set to the passed in value."
+                    "return": "Void"
                 },
                 {
                     "export": "0",
diff --git a/soroban-env-common/src/meta.rs b/soroban-env-common/src/meta.rs
index 00d924fa..081dea21 100644
--- a/soroban-env-common/src/meta.rs
+++ b/soroban-env-common/src/meta.rs
@@ -42,7 +42,7 @@ pub const ENV_META_V0_SECTION_NAME: &str = "contractenvmetav0";
 
 soroban_env_macros::generate_env_meta_consts!(
     ledger_protocol_version: 20,
-    pre_release_version: 55,
+    pre_release_version: 56,
 );
 
 pub fn get_ledger_protocol_version(interface_version: u64) -> u32 {
diff --git a/soroban-env-common/src/symbol.rs b/soroban-env-common/src/symbol.rs
index 2aa68067..fb5e73a0 100644
--- a/soroban-env-common/src/symbol.rs
+++ b/soroban-env-common/src/symbol.rs
@@ -157,7 +157,7 @@ impl Symbol {
 
 impl Ord for SymbolSmall {
     fn cmp(&self, other: &Self) -> Ordering {
-        Iterator::cmp(self.into_iter(), other.into_iter())
+        Iterator::cmp(self.into_iter(), *other)
     }
 }
 
diff --git a/soroban-env-host/src/auth.rs b/soroban-env-host/src/auth.rs
index fcb69101..af0698a3 100644
--- a/soroban-env-host/src/auth.rs
+++ b/soroban-env-host/src/auth.rs
@@ -4,10 +4,10 @@ use std::rc::Rc;
 
 use rand::Rng;
 use soroban_env_common::xdr::{
-    ContractDataEntry, ContractDataEntryBody, ContractDataEntryData, CreateContractArgs,
-    HashIdPreimage, HashIdPreimageSorobanAuthorization, InvokeContractArgs, LedgerEntry,
-    LedgerEntryData, LedgerEntryExt, ScAddress, ScErrorCode, ScErrorType, ScNonceKey, ScVal,
-    SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanCredentials,
+    ContractDataEntry, CreateContractArgs, HashIdPreimage, HashIdPreimageSorobanAuthorization,
+    InvokeContractArgs, LedgerEntry, LedgerEntryData, LedgerEntryExt, ScAddress, ScErrorCode,
+    ScErrorType, ScNonceKey, ScVal, SorobanAuthorizationEntry, SorobanAuthorizedFunction,
+    SorobanCredentials,
 };
 use soroban_env_common::{AddressObject, Compare, Symbol, TryFromVal, TryIntoVal, Val, VecObject};
 
@@ -1776,16 +1776,12 @@ impl Host {
                     &[address.into()],
                 ));
             }
-            let body = ContractDataEntryBody::DataEntry(ContractDataEntryData {
-                val: ScVal::Void,
-                flags: 0,
-            });
             let data = LedgerEntryData::ContractData(ContractDataEntry {
                 contract: sc_address,
                 key: nonce_key_scval,
-                body,
-                expiration_ledger_seq: expiration_ledger,
+                val: ScVal::Void,
                 durability: xdr::ContractDataDurability::Temporary,
+                ext: xdr::ExtensionPoint::V0,
             });
             let entry = LedgerEntry {
                 last_modified_ledger_seq: 0,
@@ -1795,6 +1791,7 @@ impl Host {
             storage.put(
                 &nonce_key,
                 &Rc::metered_new(entry, self)?,
+                Some(expiration_ledger),
                 self.budget_ref(),
             )
         })
diff --git a/soroban-env-host/src/host.rs b/soroban-env-host/src/host.rs
index 4d44ecf9..46a2a539 100644
--- a/soroban-env-host/src/host.rs
+++ b/soroban-env-host/src/host.rs
@@ -47,9 +47,8 @@ pub use prng::{Seed, SEED_BYTES};
 mod validity;
 pub use error::HostError;
 use soroban_env_common::xdr::{
-    ContractCodeEntryBody, ContractDataDurability, ContractDataEntryBody, ContractDataEntryData,
-    ContractEntryBodyType, ContractIdPreimage, ContractIdPreimageFromAddress, ScContractInstance,
-    ScErrorCode, MASK_CONTRACT_DATA_FLAGS_V20,
+    ContractDataDurability, ContractIdPreimage, ContractIdPreimageFromAddress, ScContractInstance,
+    ScErrorCode,
 };
 
 use self::{
@@ -106,7 +105,6 @@ pub struct LedgerInfo {
     pub min_temp_entry_expiration: u32,
     pub min_persistent_entry_expiration: u32,
     pub max_entry_expiration: u32,
-    pub autobump_ledgers: u32,
 }
 
 #[derive(Clone, Default)]
@@ -680,9 +678,12 @@ impl Host {
         &self,
         key: &Rc<LedgerKey>,
         val: &Rc<soroban_env_common::xdr::LedgerEntry>,
+        expiration_ledger: Option<u32>,
     ) -> Result<(), HostError> {
         self.as_budget().with_free_budget(|| {
-            self.with_mut_storage(|storage| storage.put(key, val, self.as_budget()))
+            self.with_mut_storage(|storage| {
+                storage.put(key, val, expiration_ledger, self.as_budget())
+            })
         })
     }
 
@@ -693,7 +694,7 @@ impl Host {
     pub fn setup_storage_entry(
         &self,
         key: Rc<LedgerKey>,
-        val: Option<Rc<soroban_env_common::xdr::LedgerEntry>>,
+        val: Option<(Rc<soroban_env_common::xdr::LedgerEntry>, Option<u32>)>,
         access_type: AccessType,
     ) -> Result<(), HostError> {
         self.as_budget().with_free_budget(|| {
@@ -759,7 +760,6 @@ impl Host {
         let code_key = Rc::metered_new(
             LedgerKey::ContractCode(LedgerKeyContractCode {
                 hash: Hash(hash_bytes.metered_clone(self)?),
-                body_type: ContractEntryBodyType::DataEntry,
             }),
             self,
         )?;
@@ -768,26 +768,23 @@ impl Host {
             .has(&code_key, self.as_budget())
             .map_err(|e| self.decorate_contract_code_storage_error(e, &Hash(hash_bytes)))?
         {
-            let body = ContractCodeEntryBody::DataEntry(wasm.try_into().map_err(|_| {
-                self.err(
-                    ScErrorType::Value,
-                    ScErrorCode::ExceededLimit,
-                    "Wasm code is too large",
-                    &[],
-                )
-            })?);
-
             self.with_mut_storage(|storage| {
                 let data = LedgerEntryData::ContractCode(ContractCodeEntry {
                     hash: Hash(hash_bytes),
-                    body,
                     ext: ExtensionPoint::V0,
-                    expiration_ledger_seq: self
-                        .get_min_expiration_ledger(ContractDataDurability::Persistent)?,
+                    code: wasm.try_into().map_err(|_| {
+                        self.err(
+                            ScErrorType::Value,
+                            ScErrorCode::ExceededLimit,
+                            "Wasm code is too large",
+                            &[],
+                        )
+                    })?,
                 });
                 storage.put(
                     &code_key,
                     &Host::ledger_entry_from_data(self, data)?,
+                    Some(self.get_min_expiration_ledger(ContractDataDurability::Persistent)?),
                     self.as_budget(),
                 )
             })?;
@@ -856,23 +853,7 @@ impl Host {
         k: Val,
         v: Val,
         t: StorageType,
-        f: Val,
     ) -> Result<(), HostError> {
-        let flags: Option<u32> = if f.is_void() {
-            None
-        } else {
-            let val = self.u32_from_rawval_input("f", f)?;
-            if ((val as u64) & !MASK_CONTRACT_DATA_FLAGS_V20) != 0 {
-                return Err(self.err(
-                    ScErrorType::Value,
-                    ScErrorCode::InvalidInput,
-                    "invalid flags",
-                    &[],
-                ));
-            }
-            Some(val)
-        };
-
         let durability: ContractDataDurability = t.try_into()?;
         let key = self.contract_data_key_from_rawval(k, durability)?;
         // Currently the storage stores the whole ledger entries, while this
@@ -884,29 +865,15 @@ impl Host {
             .has(&key, self.as_budget())
             .map_err(|e| self.decorate_contract_data_storage_error(e, k))?
         {
-            let mut current = (*self
+            let (current, expiration_ledger) = self
                 .try_borrow_storage_mut()?
-                .get(&key, self.as_budget())
-                .map_err(|e| self.decorate_contract_data_storage_error(e, k))?)
-            .metered_clone(self)?;
-
+                .get_with_expiration(&key, self.as_budget())
+                .map_err(|e| self.decorate_contract_data_storage_error(e, k))?;
+            let mut current = (*current).metered_clone(self)?;
             match current.data {
-                LedgerEntryData::ContractData(ref mut entry) => match entry.body {
-                    ContractDataEntryBody::DataEntry(ref mut data) => {
-                        data.val = self.from_host_val(v)?;
-                        if let Some(new_flags) = flags {
-                            data.flags = new_flags;
-                        }
-                    }
-                    _ => {
-                        return Err(self.err(
-                            ScErrorType::Storage,
-                            ScErrorCode::InternalError,
-                            "expected DataEntry",
-                            &[],
-                        ));
-                    }
-                },
+                LedgerEntryData::ContractData(ref mut entry) => {
+                    entry.val = self.from_host_val(v)?;
+                }
                 _ => {
                     return Err(self.err(
                         ScErrorType::Storage,
@@ -917,24 +884,26 @@ impl Host {
                 }
             }
             self.try_borrow_storage_mut()?
-                .put(&key, &Rc::metered_new(current, self)?, self.as_budget())
+                .put(
+                    &key,
+                    &Rc::metered_new(current, self)?,
+                    expiration_ledger,
+                    self.as_budget(),
+                )
                 .map_err(|e| self.decorate_contract_data_storage_error(e, k))?;
         } else {
-            let body = ContractDataEntryBody::DataEntry(ContractDataEntryData {
-                val: self.from_host_val(v)?,
-                flags: flags.unwrap_or(0),
-            });
             let data = LedgerEntryData::ContractData(ContractDataEntry {
                 contract: ScAddress::Contract(self.get_current_contract_id_internal()?),
                 key: self.from_host_val(k)?,
-                body,
-                expiration_ledger_seq: self.get_min_expiration_ledger(durability)?,
+                val: self.from_host_val(v)?,
                 durability,
+                ext: ExtensionPoint::V0,
             });
             self.try_borrow_storage_mut()?
                 .put(
                     &key,
                     &Host::ledger_entry_from_data(self, data)?,
+                    Some(self.get_min_expiration_ledger(durability)?),
                     self.as_budget(),
                 )
                 .map_err(|e| self.decorate_contract_data_storage_error(e, k))?;
@@ -943,38 +912,6 @@ impl Host {
         Ok(())
     }
 
-    // If autobump enabled, autobumps all the entries in the footprint.
-    fn maybe_autobump_expiration_of_footprint_entries(&self) -> Result<(), HostError> {
-        let Some(autobump_ledgers) = self.with_ledger_info(|li| {
-            if li.autobump_ledgers > 0 {
-                Ok(Some(li.autobump_ledgers))
-            } else {
-                Ok(None)
-            }
-        })? else {
-            return Ok(());
-        };
-        // Need to copy the footprint out of the storage to allow mut borrow of
-        // storage.
-        let footprint_map = self.try_borrow_storage()?.footprint.0.metered_clone(self)?;
-        for (key, _) in footprint_map.iter(self.budget_ref())? {
-            match key.as_ref() {
-                LedgerKey::ContractData(_) | LedgerKey::ContractCode(_) => {
-                    if self.try_borrow_storage_mut()?.has(key, self.budget_ref())? {
-                        self.try_borrow_storage_mut()?
-                            .bump_relative_to_entry_expiration(
-                                self,
-                                key.metered_clone(self)?,
-                                autobump_ledgers,
-                            )?;
-                    }
-                }
-                _ => (),
-            }
-        }
-        Ok(())
-    }
-
     fn decorate_contract_data_storage_error(&self, err: HostError, key: Val) -> HostError {
         if !err.error.is_type(ScErrorType::Storage) {
             return err;
@@ -2129,13 +2066,12 @@ impl VmCallerEnv for Host {
         k: Val,
         v: Val,
         t: StorageType,
-        f: Val,
     ) -> Result<Void, HostError> {
         self.check_val_integrity(k)?;
         self.check_val_integrity(v)?;
         match t {
             StorageType::Temporary | StorageType::Persistent => {
-                self.put_contract_data_into_ledger(k, v, t, f)?
+                self.put_contract_data_into_ledger(k, v, t)?
             }
             StorageType::Instance => self.with_mut_instance_storage(|s| {
                 s.map = s.map.insert(k, v, self)?;
@@ -2183,15 +2119,7 @@ impl VmCallerEnv for Host {
                     .get(&key, self.as_budget())
                     .map_err(|e| self.decorate_contract_data_storage_error(e, k))?;
                 match &entry.data {
-                    LedgerEntryData::ContractData(ContractDataEntry { body, .. }) => match body {
-                        ContractDataEntryBody::DataEntry(data) => Ok(self.to_host_val(&data.val)?),
-                        _ => Err(self.err(
-                            ScErrorType::Storage,
-                            ScErrorCode::InternalError,
-                            "expected DataEntry",
-                            &[],
-                        )),
-                    },
+                    LedgerEntryData::ContractData(e) => Ok(self.to_host_val(&e.val)?),
                     _ => Err(self.err(
                         ScErrorType::Storage,
                         ScErrorCode::InternalError,
diff --git a/soroban-env-host/src/host/comparison.rs b/soroban-env-host/src/host/comparison.rs
index 28f664f2..5bea9b03 100644
--- a/soroban-env-host/src/host/comparison.rs
+++ b/soroban-env-host/src/host/comparison.rs
@@ -2,9 +2,8 @@ use core::cmp::{min, Ordering};
 
 use soroban_env_common::{
     xdr::{
-        AccountEntry, AccountId, ClaimableBalanceEntry, ConfigSettingEntry, ContractCodeEntryBody,
-        ContractCostType, ContractDataDurability, ContractDataEntryBody, ContractDataEntryData,
-        ContractEntryBodyType, ContractExecutable, CreateContractArgs, DataEntry, DepthLimiter,
+        AccountEntry, AccountId, ClaimableBalanceEntry, ConfigSettingEntry, ContractCostType,
+        ContractDataDurability, ContractExecutable, CreateContractArgs, DataEntry, DepthLimiter,
         Duration, ExtensionPoint, Hash, LedgerEntry, LedgerEntryData, LedgerEntryExt, LedgerKey,
         LedgerKeyAccount, LedgerKeyClaimableBalance, LedgerKeyConfigSetting, LedgerKeyContractCode,
         LedgerKeyData, LedgerKeyLiquidityPool, LedgerKeyOffer, LedgerKeyTrustLine,
@@ -192,7 +191,6 @@ impl_compare_fixed_size_ord_type!(ScNonceKey);
 impl_compare_fixed_size_ord_type!(PublicKey);
 impl_compare_fixed_size_ord_type!(TrustLineAsset);
 impl_compare_fixed_size_ord_type!(ContractDataDurability);
-impl_compare_fixed_size_ord_type!(ContractEntryBodyType);
 
 impl_compare_fixed_size_ord_type!(LedgerKeyAccount);
 impl_compare_fixed_size_ord_type!(LedgerKeyTrustLine);
@@ -331,8 +329,8 @@ impl Compare<LedgerKey> for Budget {
             (ClaimableBalance(a), ClaimableBalance(b)) => self.compare(&a, &b),
             (LiquidityPool(a), LiquidityPool(b)) => self.compare(&a, &b),
             (ContractData(a), ContractData(b)) => self.compare(
-                &(&a.contract, &a.key, &a.durability, &a.body_type),
-                &(&b.contract, &b.key, &b.durability, &b.body_type),
+                &(&a.contract, &a.key, &a.durability),
+                &(&b.contract, &b.key, &b.durability),
             ),
             (ContractCode(a), ContractCode(b)) => self.compare(&a, &b),
             (ConfigSetting(a), ConfigSetting(b)) => self.compare(&a, &b),
@@ -348,7 +346,8 @@ impl Compare<LedgerKey> for Budget {
             | (LiquidityPool(_), _)
             | (ContractData(_), _)
             | (ContractCode(_), _)
-            | (ConfigSetting(_), _) => Ok(a.cmp(b)),
+            | (ConfigSetting(_), _)
+            | (Expiration(_), _) => Ok(a.cmp(b)),
         }
     }
 }
@@ -377,25 +376,12 @@ impl Compare<LedgerEntryData> for Budget {
             (ClaimableBalance(a), ClaimableBalance(b)) => self.compare(&a, &b),
             (LiquidityPool(a), LiquidityPool(b)) => self.compare(&a, &b),
             (ContractData(a), ContractData(b)) => self.compare(
-                &(
-                    &a.contract,
-                    &a.key,
-                    &a.durability,
-                    &a.body,
-                    &a.expiration_ledger_seq,
-                ),
-                &(
-                    &b.contract,
-                    &b.key,
-                    &b.durability,
-                    &b.body,
-                    &b.expiration_ledger_seq,
-                ),
-            ),
-            (ContractCode(a), ContractCode(b)) => self.compare(
-                &(&a.ext, &a.hash, &a.body, &a.expiration_ledger_seq),
-                &(&b.ext, &b.hash, &b.body, &b.expiration_ledger_seq),
+                &(&a.contract, &a.key, &a.durability, &a.val),
+                &(&b.contract, &b.key, &b.durability, &b.val),
             ),
+            (ContractCode(a), ContractCode(b)) => {
+                self.compare(&(&a.ext, &a.hash), &(&b.ext, &b.hash))
+            }
             (ConfigSetting(a), ConfigSetting(b)) => self.compare(&a, &b),
 
             (Account(_), _)
@@ -406,55 +392,8 @@ impl Compare<LedgerEntryData> for Budget {
             | (LiquidityPool(_), _)
             | (ContractData(_), _)
             | (ContractCode(_), _)
-            | (ConfigSetting(_), _) => Ok(a.cmp(b)),
-        }
-    }
-}
-
-impl Compare<ContractDataEntryData> for Budget {
-    type Error = HostError;
-
-    fn compare(
-        &self,
-        a: &ContractDataEntryData,
-        b: &ContractDataEntryData,
-    ) -> Result<Ordering, Self::Error> {
-        self.compare(&(a.flags, &a.val), &(b.flags, &b.val))
-    }
-}
-
-impl Compare<ContractDataEntryBody> for Budget {
-    type Error = HostError;
-
-    fn compare(
-        &self,
-        a: &ContractDataEntryBody,
-        b: &ContractDataEntryBody,
-    ) -> Result<Ordering, Self::Error> {
-        match (a, b) {
-            (ContractDataEntryBody::DataEntry(a), ContractDataEntryBody::DataEntry(b)) => {
-                self.compare(&(a), &(b))
-            }
-            (ContractDataEntryBody::DataEntry(_), _)
-            | (ContractDataEntryBody::ExpirationExtension, _) => Ok(a.cmp(b)),
-        }
-    }
-}
-
-impl Compare<ContractCodeEntryBody> for Budget {
-    type Error = HostError;
-
-    fn compare(
-        &self,
-        a: &ContractCodeEntryBody,
-        b: &ContractCodeEntryBody,
-    ) -> Result<Ordering, Self::Error> {
-        match (a, b) {
-            (ContractCodeEntryBody::DataEntry(a), ContractCodeEntryBody::DataEntry(b)) => {
-                <Self as Compare<&[u8]>>::compare(self, &a.as_ref(), &b.as_ref())
-            }
-            (ContractCodeEntryBody::DataEntry(_), _)
-            | (ContractCodeEntryBody::ExpirationExtension, _) => Ok(a.cmp(b)),
+            | (ConfigSetting(_), _)
+            | (Expiration(_), _) => Ok(a.cmp(b)),
         }
     }
 }
diff --git a/soroban-env-host/src/host/conversion.rs b/soroban-env-host/src/host/conversion.rs
index 6e62741e..6d1935ad 100644
--- a/soroban-env-host/src/host/conversion.rs
+++ b/soroban-env-host/src/host/conversion.rs
@@ -12,9 +12,9 @@ use soroban_env_common::num::{
     i256_from_pieces, i256_into_pieces, u256_from_pieces, u256_into_pieces,
 };
 use soroban_env_common::xdr::{
-    self, int128_helpers, AccountId, ContractDataDurability, ContractEntryBodyType, DepthLimiter,
-    Int128Parts, Int256Parts, ScAddress, ScBytes, ScErrorCode, ScErrorType, ScMap, ScMapEntry,
-    UInt128Parts, UInt256Parts, VecM,
+    self, int128_helpers, AccountId, ContractDataDurability, DepthLimiter, Int128Parts,
+    Int256Parts, ScAddress, ScBytes, ScErrorCode, ScErrorType, ScMap, ScMapEntry, UInt128Parts,
+    UInt256Parts, VecM,
 };
 use soroban_env_common::{
     AddressObject, BytesObject, Convert, Object, ScValObjRef, ScValObject, TryFromVal, TryIntoVal,
@@ -172,8 +172,7 @@ impl Host {
             LedgerKey::ContractData(LedgerKeyContractData {
                 contract: contract_address,
                 key,
-                durability: durability,
-                body_type: ContractEntryBodyType::DataEntry,
+                durability,
             }),
             self,
         )
diff --git a/soroban-env-host/src/host/data_helper.rs b/soroban-env-host/src/host/data_helper.rs
index 955a2980..ef68865e 100644
--- a/soroban-env-host/src/host/data_helper.rs
+++ b/soroban-env-host/src/host/data_helper.rs
@@ -2,8 +2,7 @@ use core::cmp::min;
 use std::rc::Rc;
 
 use soroban_env_common::xdr::{
-    BytesM, ContractCodeEntryBody, ContractDataDurability, ContractDataEntryBody,
-    ContractDataEntryData, ContractEntryBodyType, ContractIdPreimage, HashIdPreimageContractId,
+    BytesM, ContractDataDurability, ContractIdPreimage, ExtensionPoint, HashIdPreimageContractId,
     ScAddress, ScContractInstance, ScErrorCode, ScErrorType,
 };
 use soroban_env_common::{AddressObject, Env, U32Val};
@@ -29,7 +28,6 @@ impl Host {
             LedgerKey::ContractData(LedgerKeyContractData {
                 key: ScVal::LedgerKeyContractInstance,
                 durability: ContractDataDurability::Persistent,
-                body_type: ContractEntryBodyType::DataEntry,
                 contract: ScAddress::Contract(contract_id),
             }),
             self,
@@ -43,20 +41,13 @@ impl Host {
     ) -> Result<ScContractInstance, HostError> {
         let entry = self.try_borrow_storage_mut()?.get(key, self.as_budget())?;
         match &entry.data {
-            LedgerEntryData::ContractData(ContractDataEntry { body, .. }) => match body {
-                ContractDataEntryBody::DataEntry(data) => match &data.val {
-                    ScVal::ContractInstance(instance) => instance.metered_clone(self),
-                    other => Err(err!(
-                        self,
-                        (ScErrorType::Storage, ScErrorCode::InternalError),
-                        "ledger entry for contract instance does not contain contract instance",
-                        *other
-                    )),
-                },
-                _ => Err(err!(
+            LedgerEntryData::ContractData(e) => match &e.val {
+                ScVal::ContractInstance(instance) => instance.metered_clone(self),
+                other => Err(err!(
                     self,
                     (ScErrorType::Storage, ScErrorCode::InternalError),
-                    "expected DataEntry",
+                    "ledger entry for contract instance does not contain contract instance",
+                    *other
                 )),
             },
             _ => Err(self.err(
@@ -74,10 +65,7 @@ impl Host {
     ) -> Result<Rc<LedgerKey>, HostError> {
         let wasm_hash = wasm_hash.metered_clone(self)?;
         Rc::metered_new(
-            LedgerKey::ContractCode(LedgerKeyContractCode {
-                hash: wasm_hash,
-                body_type: ContractEntryBodyType::DataEntry,
-            }),
+            LedgerKey::ContractCode(LedgerKeyContractCode { hash: wasm_hash }),
             self,
         )
     }
@@ -90,14 +78,7 @@ impl Host {
             .map_err(|e| self.decorate_contract_code_storage_error(e, wasm_hash))?
             .data
         {
-            LedgerEntryData::ContractCode(e) => match &e.body {
-                ContractCodeEntryBody::DataEntry(code) => code.metered_clone(self),
-                _ => Err(err!(
-                    self,
-                    (ScErrorType::Storage, ScErrorCode::InternalError),
-                    "expected DataEntry",
-                )),
-            },
+            LedgerEntryData::ContractCode(e) => e.code.metered_clone(self),
             _ => Err(err!(
                 self,
                 (ScErrorType::Storage, ScErrorCode::InternalError),
@@ -121,22 +102,19 @@ impl Host {
         contract_id: Hash,
         key: &Rc<LedgerKey>,
     ) -> Result<(), HostError> {
-        let body = ContractDataEntryBody::DataEntry(ContractDataEntryData {
-            val: ScVal::ContractInstance(instance),
-            flags: 0,
-        });
-
         if self
             .try_borrow_storage_mut()?
-            .has(&key, self.as_budget())
+            .has(key, self.as_budget())
             .map_err(|e| self.decorate_contract_instance_storage_error(e, &contract_id))?
         {
-            let mut current = (*self.try_borrow_storage_mut()?.get(&key, self.as_budget())?)
-                .metered_clone(self)?;
+            let (current, expiration_ledger) = self
+                .try_borrow_storage_mut()?
+                .get_with_expiration(key, self.as_budget())?;
+            let mut current = (*current).metered_clone(self.as_budget())?;
 
             match current.data {
                 LedgerEntryData::ContractData(ref mut entry) => {
-                    entry.body = body;
+                    entry.val = ScVal::ContractInstance(instance);
                 }
                 _ => {
                     return Err(self.err(
@@ -148,21 +126,26 @@ impl Host {
                 }
             }
             self.try_borrow_storage_mut()?
-                .put(&key, &Rc::metered_new(current, self)?, self.as_budget())
+                .put(
+                    &key,
+                    &Rc::metered_new(current, self)?,
+                    expiration_ledger,
+                    self.as_budget(),
+                )
                 .map_err(|e| self.decorate_contract_instance_storage_error(e, &contract_id))?;
         } else {
             let data = LedgerEntryData::ContractData(ContractDataEntry {
                 contract: ScAddress::Contract(contract_id.metered_clone(self)?),
                 key: ScVal::LedgerKeyContractInstance,
-                body,
+                val: ScVal::ContractInstance(instance),
                 durability: ContractDataDurability::Persistent,
-                expiration_ledger_seq: self
-                    .get_min_expiration_ledger(ContractDataDurability::Persistent)?,
+                ext: ExtensionPoint::V0,
             });
             self.try_borrow_storage_mut()?
                 .put(
                     key,
                     &Host::ledger_entry_from_data(self, data)?,
+                    Some(self.get_min_expiration_ledger(ContractDataDurability::Persistent)?),
                     self.as_budget(),
                 )
                 .map_err(|e| self.decorate_contract_instance_storage_error(e, &contract_id))?;
diff --git a/soroban-env-host/src/host/declared_size.rs b/soroban-env-host/src/host/declared_size.rs
index 662b7608..8069e32a 100644
--- a/soroban-env-host/src/host/declared_size.rs
+++ b/soroban-env-host/src/host/declared_size.rs
@@ -10,14 +10,14 @@ use crate::{
     storage::AccessType,
     xdr::{
         AccountEntry, AccountId, Asset, BytesM, ClaimableBalanceEntry, ConfigSettingEntry,
-        ContractCodeEntry, ContractDataDurability, ContractEntryBodyType, ContractEvent,
-        ContractExecutable, ContractIdPreimage, CreateContractArgs, DataEntry, Duration,
-        ExtensionPoint, Hash, LedgerEntry, LedgerEntryExt, LedgerKey, LedgerKeyAccount,
-        LedgerKeyClaimableBalance, LedgerKeyConfigSetting, LedgerKeyContractCode, LedgerKeyData,
-        LedgerKeyLiquidityPool, LedgerKeyOffer, LedgerKeyTrustLine, LiquidityPoolEntry, OfferEntry,
-        PublicKey, ScAddress, ScBytes, ScContractInstance, ScMap, ScMapEntry, ScNonceKey, ScString,
-        ScSymbol, ScVal, ScVec, SorobanAuthorizationEntry, SorobanAuthorizedInvocation, StringM,
-        TimePoint, TrustLineAsset, TrustLineEntry, Uint256, SCSYMBOL_LIMIT,
+        ContractCodeEntry, ContractDataDurability, ContractEvent, ContractExecutable,
+        ContractIdPreimage, CreateContractArgs, DataEntry, Duration, ExtensionPoint, Hash,
+        LedgerEntry, LedgerEntryExt, LedgerKey, LedgerKeyAccount, LedgerKeyClaimableBalance,
+        LedgerKeyConfigSetting, LedgerKeyContractCode, LedgerKeyData, LedgerKeyLiquidityPool,
+        LedgerKeyOffer, LedgerKeyTrustLine, LiquidityPoolEntry, OfferEntry, PublicKey, ScAddress,
+        ScBytes, ScContractInstance, ScMap, ScMapEntry, ScNonceKey, ScString, ScSymbol, ScVal,
+        ScVec, SorobanAuthorizationEntry, SorobanAuthorizedInvocation, StringM, TimePoint,
+        TrustLineAsset, TrustLineEntry, Uint256, SCSYMBOL_LIMIT,
     },
     AddressObject, Bool, BytesObject, DurationObject, DurationSmall, DurationVal, Error, HostError,
     I128Object, I128Small, I128Val, I256Object, I256Small, I256Val, I32Val, I64Object, I64Small,
@@ -153,7 +153,6 @@ impl_declared_size_type!(ScSymbol, 24);
 impl_declared_size_type!(CreateContractArgs, 98);
 impl_declared_size_type!(ContractIdPreimage, 65);
 impl_declared_size_type!(ContractDataDurability, 4);
-impl_declared_size_type!(ContractEntryBodyType, 4);
 impl_declared_size_type!(ExtensionPoint, 0);
 impl_declared_size_type!(ScContractInstance, 64);
 impl_declared_size_type!(SorobanAuthorizationEntry, 240);
@@ -325,7 +324,7 @@ mod test {
         expect!["56"].assert_eq(size_of::<LedgerKeyData>().to_string().as_str());
         expect!["32"].assert_eq(size_of::<LedgerKeyClaimableBalance>().to_string().as_str());
         expect!["32"].assert_eq(size_of::<LedgerKeyLiquidityPool>().to_string().as_str());
-        expect!["36"].assert_eq(size_of::<LedgerKeyContractCode>().to_string().as_str());
+        expect!["32"].assert_eq(size_of::<LedgerKeyContractCode>().to_string().as_str());
         expect!["4"].assert_eq(size_of::<LedgerKeyConfigSetting>().to_string().as_str());
         expect!["33"].assert_eq(size_of::<LedgerEntryExt>().to_string().as_str());
         expect!["216"].assert_eq(size_of::<AccountEntry>().to_string().as_str());
@@ -334,9 +333,9 @@ mod test {
         expect!["80"].assert_eq(size_of::<DataEntry>().to_string().as_str());
         expect!["120"].assert_eq(size_of::<ClaimableBalanceEntry>().to_string().as_str());
         expect!["160"].assert_eq(size_of::<LiquidityPoolEntry>().to_string().as_str());
-        expect!["64"].assert_eq(size_of::<ContractCodeEntry>().to_string().as_str());
+        expect!["56"].assert_eq(size_of::<ContractCodeEntry>().to_string().as_str());
         expect!["96"].assert_eq(size_of::<ConfigSettingEntry>().to_string().as_str());
-        expect!["120"].assert_eq(size_of::<LedgerKey>().to_string().as_str());
+        expect!["112"].assert_eq(size_of::<LedgerKey>().to_string().as_str());
         expect!["256"].assert_eq(size_of::<LedgerEntry>().to_string().as_str());
         expect!["1"].assert_eq(size_of::<AccessType>().to_string().as_str());
         expect!["40"].assert_eq(size_of::<InternalContractEvent>().to_string().as_str());
@@ -351,7 +350,6 @@ mod test {
         expect!["98"].assert_eq(size_of::<CreateContractArgs>().to_string().as_str());
         expect!["65"].assert_eq(size_of::<ContractIdPreimage>().to_string().as_str());
         expect!["4"].assert_eq(size_of::<ContractDataDurability>().to_string().as_str());
-        expect!["4"].assert_eq(size_of::<ContractEntryBodyType>().to_string().as_str());
         expect!["0"].assert_eq(size_of::<ExtensionPoint>().to_string().as_str());
         expect!["128"].assert_eq(
             size_of::<SorobanAuthorizedInvocation>()
@@ -516,7 +514,6 @@ mod test {
         assert_mem_size_le_declared_size!(ScSymbol);
         assert_mem_size_le_declared_size!(CreateContractArgs);
         assert_mem_size_le_declared_size!(ContractDataDurability);
-        assert_mem_size_le_declared_size!(ContractEntryBodyType);
         assert_mem_size_le_declared_size!(ExtensionPoint);
         assert_mem_size_le_declared_size!(SorobanAuthorizedInvocation);
         assert_mem_size_le_declared_size!(SorobanAuthorizationEntry);
diff --git a/soroban-env-host/src/host/frame.rs b/soroban-env-host/src/host/frame.rs
index 95185e3e..28de225f 100644
--- a/soroban-env-host/src/host/frame.rs
+++ b/soroban-env-host/src/host/frame.rs
@@ -194,7 +194,12 @@ impl Host {
         F: FnOnce(&Frame) -> Result<U, HostError>,
     {
         let Ok(context_guard) = self.0.context.try_borrow() else {
-            return Err(self.err(ScErrorType::Context, ScErrorCode::InternalError, "context is already borrowed", &[]));
+            return Err(self.err(
+                ScErrorType::Context,
+                ScErrorCode::InternalError,
+                "context is already borrowed",
+                &[],
+            ));
         };
 
         if let Some(context) = context_guard.last() {
@@ -221,7 +226,12 @@ impl Host {
         F: FnOnce(&mut Context) -> Result<U, HostError>,
     {
         let Ok(mut context_guard) = self.0.context.try_borrow_mut() else {
-            return Err(self.err(ScErrorType::Context, ScErrorCode::InternalError, "context is already borrowed", &[]));
+            return Err(self.err(
+                ScErrorType::Context,
+                ScErrorCode::InternalError,
+                "context is already borrowed",
+                &[],
+            ));
         };
         if let Some(context) = context_guard.last_mut() {
             f(context)
@@ -243,7 +253,12 @@ impl Host {
         F: FnOnce(Option<&Frame>) -> Result<U, HostError>,
     {
         let Ok(context_guard) = self.0.context.try_borrow() else {
-            return Err(self.err(ScErrorType::Context, ScErrorCode::InternalError, "context is already borrowed", &[]));
+            return Err(self.err(
+                ScErrorType::Context,
+                ScErrorCode::InternalError,
+                "context is already borrowed",
+                &[],
+            ));
         };
         if let Some(context) = context_guard.last() {
             f(Some(&context.frame))
@@ -686,14 +701,18 @@ impl Host {
 
     // Notes on metering: covered by the called components.
     fn invoke_function_raw(&self, hf: HostFunction) -> Result<Val, HostError> {
-        self.maybe_autobump_expiration_of_footprint_entries()?;
         let hf_type = hf.discriminant();
         match hf {
             HostFunction::InvokeContract(invoke_args) => {
                 self.with_frame(Frame::HostFunction(hf_type), || {
                     // Metering: conversions to host objects are covered.
                     let ScAddress::Contract(ref contract_id) = invoke_args.contract_address else {
-                        return Err(self.err(ScErrorType::Value, ScErrorCode::UnexpectedType, "invoked address doesn't belong to a contract", &[]));
+                        return Err(self.err(
+                            ScErrorType::Value,
+                            ScErrorCode::UnexpectedType,
+                            "invoked address doesn't belong to a contract",
+                            &[],
+                        ));
                     };
                     let function_name: Symbol = invoke_args.function_name.try_into_val(self)?;
                     let args = self.scvals_to_rawvals(invoke_args.args.as_slice())?;
diff --git a/soroban-env-host/src/host/ledger_info_helper.rs b/soroban-env-host/src/host/ledger_info_helper.rs
index e19c1479..c4440d61 100644
--- a/soroban-env-host/src/host/ledger_info_helper.rs
+++ b/soroban-env-host/src/host/ledger_info_helper.rs
@@ -1,4 +1,4 @@
-use soroban_env_common::xdr::{ContractDataDurability, LedgerEntry, LedgerEntryData, LedgerKey};
+use soroban_env_common::xdr::{ContractDataDurability, LedgerKey};
 
 use crate::{Host, HostError, LedgerInfo};
 
@@ -30,26 +30,6 @@ impl Host {
     }
 }
 
-pub fn get_entry_expiration(entry: &LedgerEntry) -> Option<u32> {
-    match &entry.data {
-        LedgerEntryData::ContractData(d) => Some(d.expiration_ledger_seq),
-        LedgerEntryData::ContractCode(c) => Some(c.expiration_ledger_seq),
-        _ => None,
-    }
-}
-
-pub fn set_entry_expiration(entry: &mut LedgerEntry, new_expiration: u32) {
-    match &mut entry.data {
-        LedgerEntryData::ContractData(data) => {
-            data.expiration_ledger_seq = new_expiration;
-        }
-        LedgerEntryData::ContractCode(code) => {
-            code.expiration_ledger_seq = new_expiration;
-        }
-        _ => (),
-    }
-}
-
 pub fn get_key_durability(key: &LedgerKey) -> Option<ContractDataDurability> {
     match &key {
         LedgerKey::ContractData(d) => Some(d.durability),
diff --git a/soroban-env-host/src/host/metered_clone.rs b/soroban-env-host/src/host/metered_clone.rs
index ae95b98f..10154b5b 100644
--- a/soroban-env-host/src/host/metered_clone.rs
+++ b/soroban-env-host/src/host/metered_clone.rs
@@ -9,10 +9,9 @@ use crate::{
     storage::AccessType,
     xdr::{
         AccountEntry, AccountId, Asset, BytesM, ClaimableBalanceEntry, ConfigSettingEntry,
-        ContractCodeEntry, ContractCodeEntryBody, ContractCostType, ContractDataEntryBody,
-        ContractEvent, ContractEventBody, ContractEventType, ContractExecutable,
-        ContractIdPreimage, CreateContractArgs, DataEntry, DepthLimiter, Duration, Hash,
-        LedgerEntry, LedgerEntryData, LedgerEntryExt, LedgerKey, LedgerKeyAccount,
+        ContractCodeEntry, ContractCostType, ContractEvent, ContractEventBody, ContractEventType,
+        ContractExecutable, ContractIdPreimage, CreateContractArgs, DataEntry, DepthLimiter,
+        Duration, Hash, LedgerEntry, LedgerEntryData, LedgerEntryExt, LedgerKey, LedgerKeyAccount,
         LedgerKeyClaimableBalance, LedgerKeyConfigSetting, LedgerKeyContractCode, LedgerKeyData,
         LedgerKeyLiquidityPool, LedgerKeyOffer, LedgerKeyTrustLine, LiquidityPoolEntry, OfferEntry,
         PublicKey, ScAddress, ScBytes, ScContractInstance, ScErrorCode, ScErrorType, ScMap,
@@ -547,7 +546,8 @@ impl MeteredClone for LedgerKey {
             | LedgerKey::ClaimableBalance(_)
             | LedgerKey::LiquidityPool(_)
             | LedgerKey::ContractCode(_)
-            | LedgerKey::ConfigSetting(_) => Ok(()),
+            | LedgerKey::ConfigSetting(_)
+            | LedgerKey::Expiration(_) => Ok(()),
         }
     }
 }
@@ -559,19 +559,15 @@ impl MeteredClone for LedgerEntry {
         use LedgerEntryData::*;
         match &self.data {
             ContractData(d) => {
-                if let ContractDataEntryBody::DataEntry(e) = &d.body {
-                    e.val.charge_for_substructure(budget.clone())?;
-                }
+                d.val.charge_for_substructure(budget.clone())?;
                 d.key.charge_for_substructure(budget)
             }
             ContractCode(c) => {
-                if let ContractCodeEntryBody::DataEntry(d) = &c.body {
-                    d.charge_for_substructure(budget)?;
-                }
+                c.charge_for_substructure(budget)?;
                 Ok(())
             }
             Account(_) | Trustline(_) | Offer(_) | Data(_) | ClaimableBalance(_)
-            | LiquidityPool(_) | ConfigSetting(_) => Ok(()),
+            | LiquidityPool(_) | ConfigSetting(_) | Expiration(_) => Ok(()),
         }
     }
 }
diff --git a/soroban-env-host/src/host/metered_map.rs b/soroban-env-host/src/host/metered_map.rs
index 5a0cd67b..b819b15e 100644
--- a/soroban-env-host/src/host/metered_map.rs
+++ b/soroban-env-host/src/host/metered_map.rs
@@ -173,7 +173,7 @@ where
                 }
                 let init = self.map.iter().take(replace_pos).cloned();
                 let fini = self.map.iter().skip(replace_pos + 1).cloned();
-                let iter = init.chain([(key, value)].into_iter()).chain(fini);
+                let iter = init.chain([(key, value)]).chain(fini);
                 Self::from_exact_iter(iter, ctx)
             }
             Err(insert_pos) => {
@@ -185,7 +185,7 @@ where
                 } else {
                     let init = self.map.iter().take(insert_pos).cloned();
                     let fini = self.map.iter().skip(insert_pos).cloned();
-                    let iter = init.chain([(key, value)].into_iter()).chain(fini);
+                    let iter = init.chain([(key, value)]).chain(fini);
                     Self::from_exact_iter(iter, ctx)
                 }
             }
diff --git a/soroban-env-host/src/host/metered_vector.rs b/soroban-env-host/src/host/metered_vector.rs
index edb95de8..3a10659b 100644
--- a/soroban-env-host/src/host/metered_vector.rs
+++ b/soroban-env-host/src/host/metered_vector.rs
@@ -157,7 +157,7 @@ where
         if self.len() == u32::MAX as usize {
             Err(VEC_OOB.into())
         } else {
-            let iter = self.vec.iter().cloned().chain([value].into_iter());
+            let iter = self.vec.iter().cloned().chain([value]);
             Self::from_exact_iter(iter, budget)
         }
     }
@@ -226,7 +226,7 @@ where
         } else {
             let init = self.vec.iter().take(index).cloned();
             let fini = self.vec.iter().skip(index).cloned();
-            let iter = init.chain([value].into_iter()).chain(fini);
+            let iter = init.chain([value]).chain(fini);
             Self::from_exact_iter(iter, budget)
         }
     }
diff --git a/soroban-env-host/src/host_object.rs b/soroban-env-host/src/host_object.rs
index 77a40f3f..cbaf6c1d 100644
--- a/soroban-env-host/src/host_object.rs
+++ b/soroban-env-host/src/host_object.rs
@@ -53,47 +53,65 @@ impl HostObject {
     ) -> Result<Option<core::cmp::Ordering>, HostError> {
         let res = match self {
             HostObject::U64(u) => {
-                let Ok(small) = U64Small::try_from(rv) else { return Ok(None) };
+                let Ok(small) = U64Small::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: u64 = small.into();
                 Some(budget.compare(u, &small)?)
             }
             HostObject::I64(i) => {
-                let Ok(small) = I64Small::try_from(rv) else { return Ok(None) };
+                let Ok(small) = I64Small::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: i64 = small.into();
                 Some(budget.compare(i, &small)?)
             }
             HostObject::TimePoint(tp) => {
-                let Ok(small) = TimepointSmall::try_from(rv) else { return Ok(None) };
+                let Ok(small) = TimepointSmall::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: u64 = small.into();
                 Some(budget.compare(&tp.0, &small)?)
             }
             HostObject::Duration(d) => {
-                let Ok(small) = DurationSmall::try_from(rv) else { return Ok(None) };
+                let Ok(small) = DurationSmall::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: u64 = small.into();
                 Some(budget.compare(&d.0, &small)?)
             }
             HostObject::U128(u) => {
-                let Ok(small) = U128Small::try_from(rv) else { return Ok(None) };
+                let Ok(small) = U128Small::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: u128 = small.into();
                 Some(budget.compare(u, &small)?)
             }
             HostObject::I128(i) => {
-                let Ok(small) = I128Small::try_from(rv) else { return Ok(None) };
+                let Ok(small) = I128Small::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: i128 = small.into();
                 Some(budget.compare(i, &small)?)
             }
             HostObject::U256(u) => {
-                let Ok(small) = U256Small::try_from(rv) else { return Ok(None) };
+                let Ok(small) = U256Small::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: U256 = small.into();
                 Some(budget.compare(u, &small)?)
             }
             HostObject::I256(i) => {
-                let Ok(small) = I256Small::try_from(rv) else { return Ok(None) };
+                let Ok(small) = I256Small::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: I256 = small.into();
                 Some(budget.compare(i, &small)?)
             }
             HostObject::Symbol(s) => {
-                let Ok(small) = SymbolSmall::try_from(rv) else { return Ok(None) };
+                let Ok(small) = SymbolSmall::try_from(rv) else {
+                    return Ok(None);
+                };
                 let small: SymbolStr = small.into();
                 let rhs: &[u8] = small.as_ref();
                 Some(budget.compare(&s.as_vec().as_slice(), &rhs)?)
diff --git a/soroban-env-host/src/native_contract/token/admin.rs b/soroban-env-host/src/native_contract/token/admin.rs
index 162362d3..9f0e0be8 100644
--- a/soroban-env-host/src/native_contract/token/admin.rs
+++ b/soroban-env-host/src/native_contract/token/admin.rs
@@ -19,7 +19,6 @@ pub fn write_administrator(e: &Host, id: Address) -> Result<(), HostError> {
         key.try_into_val(e)?,
         id.try_into_val(e)?,
         StorageType::Instance,
-        ().into(),
     )?;
     Ok(())
 }
diff --git a/soroban-env-host/src/native_contract/token/allowance.rs b/soroban-env-host/src/native_contract/token/allowance.rs
index bfbdd72b..e4cfc1bb 100644
--- a/soroban-env-host/src/native_contract/token/allowance.rs
+++ b/soroban-env-host/src/native_contract/token/allowance.rs
@@ -88,7 +88,6 @@ pub fn write_allowance(
                 key.try_into_val(e)?,
                 allowance_with_old_expiration.0.try_into_val(e)?,
                 StorageType::Temporary,
-                ().into(),
             )?;
 
             if allowance_with_old_expiration.0.amount > 0
diff --git a/soroban-env-host/src/native_contract/token/asset_info.rs b/soroban-env-host/src/native_contract/token/asset_info.rs
index 4c835f67..90d0a1f0 100644
--- a/soroban-env-host/src/native_contract/token/asset_info.rs
+++ b/soroban-env-host/src/native_contract/token/asset_info.rs
@@ -9,7 +9,6 @@ pub fn write_asset_info(e: &Host, asset_info: AssetInfo) -> Result<(), HostError
         key.try_into_val(e)?,
         asset_info.try_into_val(e)?,
         StorageType::Instance,
-        ().into(),
     )?;
     Ok(())
 }
diff --git a/soroban-env-host/src/native_contract/token/balance.rs b/soroban-env-host/src/native_contract/token/balance.rs
index 70857cc2..3845e584 100644
--- a/soroban-env-host/src/native_contract/token/balance.rs
+++ b/soroban-env-host/src/native_contract/token/balance.rs
@@ -63,7 +63,6 @@ fn write_balance(e: &Host, addr: Address, balance: BalanceValue) -> Result<(), H
         key.try_into_val(e)?,
         balance.try_into_val(e)?,
         StorageType::Persistent,
-        ().into(),
     )?;
 
     e.bump_contract_data(
@@ -414,24 +413,36 @@ fn transfer_account_balance(e: &Host, account_id: AccountId, amount: i64) -> Res
     let lk = e.to_account_key(account_id)?;
 
     e.with_mut_storage(|storage| {
-        let mut le = storage
-            .get(&lk, e.as_budget())
-            .map_err(|_| e.error(ContractError::AccountMissingError.into(), "account missing", &[]))?;
+        let mut le = storage.get(&lk, e.as_budget()).map_err(|_| {
+            e.error(
+                ContractError::AccountMissingError.into(),
+                "account missing",
+                &[],
+            )
+        })?;
 
         let mut ae = match &le.data {
             LedgerEntryData::Account(ae) => Ok(ae.metered_clone(e)?),
-            _ => Err(e.error(ContractError::InternalError.into(), "unexpected entry found", &[])),
+            _ => Err(e.error(
+                ContractError::InternalError.into(),
+                "unexpected entry found",
+                &[],
+            )),
         }?;
 
         let (min_balance, max_balance) = get_min_max_account_balance(e, &ae)?;
 
         let Some(new_balance) = ae.balance.checked_add(amount) else {
-            return Err(e.error(ContractError::BalanceError.into(), "resulting balance overflow", &[]));
+            return Err(e.error(
+                ContractError::BalanceError.into(),
+                "resulting balance overflow",
+                &[],
+            ));
         };
         if new_balance >= min_balance && new_balance <= max_balance {
             ae.balance = new_balance;
             le = Host::ledger_entry_from_data(e, LedgerEntryData::Account(ae))?;
-            storage.put(&lk, &le, e.as_budget())
+            storage.put(&lk, &le, None, e.as_budget())
         } else {
             Err(err!(
                 e,
@@ -455,23 +466,35 @@ fn transfer_trustline_balance(
     let lk = e.to_trustline_key(account_id, asset)?;
     e.with_mut_storage(|storage| {
         let mut le = storage.get(&lk, e.as_budget()).map_err(|_| {
-            e.error(ContractError::TrustlineMissingError.into(), "trustline missing", &[])
+            e.error(
+                ContractError::TrustlineMissingError.into(),
+                "trustline missing",
+                &[],
+            )
         })?;
 
         let mut tl = match &le.data {
             LedgerEntryData::Trustline(tl) => Ok(tl.metered_clone(e)?),
-            _ => Err(e.error(ContractError::InternalError.into(), "unexpected entry found", &[])),
+            _ => Err(e.error(
+                ContractError::InternalError.into(),
+                "unexpected entry found",
+                &[],
+            )),
         }?;
 
         let (min_balance, max_balance) = get_min_max_trustline_balance(e, &tl)?;
 
         let Some(new_balance) = tl.balance.checked_add(amount) else {
-            return Err(e.error(ContractError::BalanceError.into(), "resulting balance overflow", &[]));
+            return Err(e.error(
+                ContractError::BalanceError.into(),
+                "resulting balance overflow",
+                &[],
+            ));
         };
         if new_balance >= min_balance && new_balance <= max_balance {
             tl.balance = new_balance;
             le = Host::ledger_entry_from_data(e, LedgerEntryData::Trustline(tl))?;
-            storage.put(&lk, &le, e.as_budget())
+            storage.put(&lk, &le, None, e.as_budget())
         } else {
             Err(err!(
                 e,
@@ -772,7 +795,7 @@ fn set_trustline_authorization(
             tl.flags |= TrustLineFlags::AuthorizedToMaintainLiabilitiesFlag as u32;
         }
         le = Host::ledger_entry_from_data(e, LedgerEntryData::Trustline(tl))?;
-        storage.put(&lk, &le, e.as_budget())
+        storage.put(&lk, &le, None, e.as_budget())
     })
 }
 
diff --git a/soroban-env-host/src/native_contract/token/metadata.rs b/soroban-env-host/src/native_contract/token/metadata.rs
index ef450141..00d37815 100644
--- a/soroban-env-host/src/native_contract/token/metadata.rs
+++ b/soroban-env-host/src/native_contract/token/metadata.rs
@@ -61,7 +61,6 @@ pub fn set_metadata(e: &Host) -> Result<(), HostError> {
         key.try_into_val(e)?,
         metadata.try_into_val(e)?,
         StorageType::Instance,
-        ().into(),
     )?;
     Ok(())
 }
diff --git a/soroban-env-host/src/storage.rs b/soroban-env-host/src/storage.rs
index 6c0ffebc..0cfb2356 100644
--- a/soroban-env-host/src/storage.rs
+++ b/soroban-env-host/src/storage.rs
@@ -7,21 +7,18 @@
 //!   - [Env::put_contract_data](crate::Env::put_contract_data)
 //!   - [Env::del_contract_data](crate::Env::del_contract_data)
 
-use std::cmp::min;
 use std::rc::Rc;
 
 use soroban_env_common::xdr::{ScErrorCode, ScErrorType};
 use soroban_env_common::{Compare, Val};
 
 use crate::budget::Budget;
-use crate::host::ledger_info_helper::{get_entry_expiration, set_entry_expiration};
-use crate::host::metered_clone::{MeteredAlloc, MeteredClone};
 use crate::xdr::{LedgerEntry, LedgerKey};
 use crate::Host;
 use crate::{host::metered_map::MeteredOrdMap, HostError};
 
 pub type FootprintMap = MeteredOrdMap<Rc<LedgerKey>, AccessType, Budget>;
-pub type StorageMap = MeteredOrdMap<Rc<LedgerKey>, Option<Rc<LedgerEntry>>, Budget>;
+pub type StorageMap = MeteredOrdMap<Rc<LedgerKey>, Option<(Rc<LedgerEntry>, Option<u32>)>, Budget>;
 #[derive(Clone)]
 pub(crate) struct InstanceStorageMap {
     pub(crate) map: MeteredOrdMap<Val, Val, Host>,
@@ -69,7 +66,8 @@ impl Compare<AccessType> for Budget {
 /// A helper type used by [FootprintMode::Recording] to provide access
 /// to a stable read-snapshot of a ledger.
 pub trait SnapshotSource {
-    fn get(&self, key: &Rc<LedgerKey>) -> Result<Rc<LedgerEntry>, HostError>;
+    // Returns the ledger entry for the key and its expiration.
+    fn get(&self, key: &Rc<LedgerKey>) -> Result<(Rc<LedgerEntry>, Option<u32>), HostError>;
     fn has(&self, key: &Rc<LedgerKey>) -> Result<bool, HostError>;
 }
 
@@ -208,14 +206,41 @@ impl Storage {
         self.prepare_read_only_access(key, budget)?;
         match self.map.get::<Rc<LedgerKey>>(key, budget)? {
             None | Some(None) => Err((ScErrorType::Storage, ScErrorCode::MissingValue).into()),
-            Some(Some(val)) => Ok(Rc::clone(val)),
+            Some(Some((val, _))) => Ok(Rc::clone(val)),
+        }
+    }
+
+    /// Attempts to retrieve the [LedgerEntry] associated with a given
+    /// [LedgerKey] and its expiration ledger (if applicable) in the [Storage],
+    /// returning an error if the key is not found.
+    ///
+    /// Expiration ledgers only exist for `ContractData` and `ContractCode`
+    /// ledger entries and are `None` for all the other entry kinds.
+    ///
+    /// In [FootprintMode::Recording] mode, records the read [LedgerKey] in the
+    /// [Footprint] as [AccessType::ReadOnly] (unless already recorded as
+    /// [AccessType::ReadWrite]) and reads through to the underlying
+    /// [SnapshotSource], if the [LedgerKey] has not yet been loaded.
+    ///
+    /// In [FootprintMode::Enforcing] mode, succeeds only if the read
+    /// [LedgerKey] has been declared in the [Footprint].
+    pub fn get_with_expiration(
+        &mut self,
+        key: &Rc<LedgerKey>,
+        budget: &Budget,
+    ) -> Result<(Rc<LedgerEntry>, Option<u32>), HostError> {
+        let _span = tracy_span!("storage get");
+        self.prepare_read_only_access(key, budget)?;
+        match self.map.get::<Rc<LedgerKey>>(key, budget)? {
+            None | Some(None) => Err((ScErrorType::Storage, ScErrorCode::MissingValue).into()),
+            Some(Some((val, expiration))) => Ok((Rc::clone(val), *expiration)),
         }
     }
 
     fn put_opt(
         &mut self,
         key: &Rc<LedgerKey>,
-        val: Option<&Rc<LedgerEntry>>,
+        val: Option<(&Rc<LedgerEntry>, Option<u32>)>,
         budget: &Budget,
     ) -> Result<(), HostError> {
         let ty = AccessType::ReadWrite;
@@ -227,9 +252,11 @@ impl Storage {
                 self.footprint.enforce_access(key, ty, budget)?;
             }
         };
-        self.map = self
-            .map
-            .insert(Rc::clone(key), val.map(Rc::clone), budget)?;
+        self.map = self.map.insert(
+            Rc::clone(key),
+            val.map(|(e, expiration)| (Rc::clone(e), expiration)),
+            budget,
+        )?;
         Ok(())
     }
 
@@ -246,10 +273,11 @@ impl Storage {
         &mut self,
         key: &Rc<LedgerKey>,
         val: &Rc<LedgerEntry>,
+        expiration_ledger: Option<u32>,
         budget: &Budget,
     ) -> Result<(), HostError> {
         let _span = tracy_span!("storage put");
-        self.put_opt(key, Some(val), budget)
+        self.put_opt(key, Some((val, expiration_ledger)), budget)
     }
 
     /// Attempts to delete the [LedgerEntry] associated with a given [LedgerKey]
@@ -293,13 +321,8 @@ impl Storage {
     /// This operation is only defined within a host as it relies on ledger
     /// state.
     ///
-    /// This is always considered a 'read-only' operation, even though it might
-    /// modify the internal storage state. The only fields of the 'read-only'
-    /// entries it modifies are their expiry ledgers, and the higher level logic
-    /// that processes the side effects of a transaction is supposed to
-    /// separately extract and write back to stable storage just the changed
-    /// expiry times of "read-only" entries, not even considering the
-    /// possibility of anything else about them changing.
+    /// This operation does not modify any ledger entries, but does change the
+    /// internal storage
     pub fn bump(
         &mut self,
         host: &Host,
@@ -322,8 +345,8 @@ impl Storage {
 
         // Bumping deleted/non-existing/out-of-footprint entries will result in
         // an error.
-        let old_entry = self.get(&key, host.budget_ref())?;
-        let old_expiration = get_entry_expiration(old_entry.as_ref()).ok_or_else(|| {
+        let (entry, old_expiration) = self.get_with_expiration(&key, host.budget_ref())?;
+        let old_expiration = old_expiration.ok_or_else(|| {
             host.err(
                 ScErrorType::Storage,
                 ScErrorCode::InternalError,
@@ -333,56 +356,9 @@ impl Storage {
         })?;
 
         if new_expiration > old_expiration {
-            let mut new_entry = (*old_entry).metered_clone(host)?;
-            set_entry_expiration(&mut new_entry, new_expiration);
             self.map = self.map.insert(
                 key,
-                Some(Rc::metered_new(new_entry, host)?),
-                host.budget_ref(),
-            )?;
-        }
-        Ok(())
-    }
-
-    /// Bumps `key` to live for at least `bump_by_ledgers` from the current
-    /// expiration of the entry.
-    ///
-    /// This should only be used for internal autobumps.
-    ///  
-    /// This operation is only defined within a host as it relies on ledger
-    /// state.
-    ///
-    /// This is always considered a 'read-only' operation, even though it might
-    /// modify the internal storage state.
-    pub(crate) fn bump_relative_to_entry_expiration(
-        &mut self,
-        host: &Host,
-        key: Rc<LedgerKey>,
-        bump_by_ledgers: u32,
-    ) -> Result<(), HostError> {
-        let _span = tracy_span!("bump key relative");
-        // Bumping deleted/non-existing/out-of-footprint entries will result in
-        // an error.
-        let old_entry = self.get(&key, host.budget_ref())?;
-        let old_expiration = get_entry_expiration(old_entry.as_ref()).ok_or_else(|| {
-            host.err(
-                ScErrorType::Storage,
-                ScErrorCode::InternalError,
-                "trying to bump non-expirable entry",
-                &[],
-            )
-        })?;
-        let new_expiration = min(
-            old_expiration.saturating_add(bump_by_ledgers),
-            host.max_expiration_ledger()?,
-        );
-
-        if new_expiration > old_expiration {
-            let mut new_entry = (*old_entry).metered_clone(host)?;
-            set_entry_expiration(&mut new_entry, new_expiration);
-            self.map = self.map.insert(
-                key,
-                Some(Rc::metered_new(new_entry, host)?),
+                Some((entry.clone(), Some(new_expiration))),
                 host.budget_ref(),
             )?;
         }
@@ -406,7 +382,7 @@ impl Storage {
                     } else {
                         None
                     };
-                    self.map = self.map.insert(Rc::clone(key), value, budget)?;
+                    self.map = self.map.insert(key.clone(), value, budget)?;
                 }
             }
             FootprintMode::Enforcing => {
@@ -424,7 +400,7 @@ mod test_footprint {
 
     use super::*;
     use crate::budget::Budget;
-    use crate::xdr::{ContractDataDurability, ContractEntryBodyType, LedgerKeyContractData, ScVal};
+    use crate::xdr::{ContractDataDurability, LedgerKeyContractData, ScVal};
 
     #[test]
     fn footprint_record_access() -> Result<(), HostError> {
@@ -432,15 +408,11 @@ mod test_footprint {
         budget.reset_unlimited()?;
         let mut fp = Footprint::default();
         // record when key not exist
-        let key = Rc::metered_new(
-            LedgerKey::ContractData(LedgerKeyContractData {
-                contract: ScAddress::Contract([0; 32].into()),
-                key: ScVal::I32(0),
-                durability: ContractDataDurability::Persistent,
-                body_type: ContractEntryBodyType::DataEntry,
-            }),
-            &budget,
-        )?;
+        let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
+            contract: ScAddress::Contract([0; 32].into()),
+            key: ScVal::I32(0),
+            durability: ContractDataDurability::Persistent,
+        }));
         fp.record_access(&key, AccessType::ReadOnly, &budget)?;
         assert_eq!(fp.0.contains_key::<LedgerKey>(&key, &budget)?, true);
         assert_eq!(
@@ -464,37 +436,18 @@ mod test_footprint {
     #[test]
     fn footprint_enforce_access() -> Result<(), HostError> {
         let budget = Budget::default();
-        let key = Rc::metered_new(
-            LedgerKey::ContractData(LedgerKeyContractData {
-                contract: ScAddress::Contract([0; 32].into()),
-                key: ScVal::I32(0),
-                durability: ContractDataDurability::Persistent,
-                body_type: ContractEntryBodyType::DataEntry,
-            }),
-            &budget,
-        )?;
+        let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
+            contract: ScAddress::Contract([0; 32].into()),
+            key: ScVal::I32(0),
+            durability: ContractDataDurability::Persistent,
+        }));
 
         // Key not in footprint. Only difference is type_
-        let key2 = Rc::metered_new(
-            LedgerKey::ContractData(LedgerKeyContractData {
-                contract: ScAddress::Contract([0; 32].into()),
-                key: ScVal::I32(0),
-                durability: ContractDataDurability::Temporary,
-                body_type: ContractEntryBodyType::DataEntry,
-            }),
-            &budget,
-        )?;
-
-        // Key not in footprint. Only difference is body_type
-        let key3 = Rc::metered_new(
-            LedgerKey::ContractData(LedgerKeyContractData {
-                contract: ScAddress::Contract([0; 32].into()),
-                key: ScVal::I32(0),
-                durability: ContractDataDurability::Persistent,
-                body_type: ContractEntryBodyType::ExpirationExtension,
-            }),
-            &budget,
-        )?;
+        let key2 = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
+            contract: ScAddress::Contract([0; 32].into()),
+            key: ScVal::I32(0),
+            durability: ContractDataDurability::Temporary,
+        }));
 
         let om = [(Rc::clone(&key), AccessType::ReadOnly)].into();
         let mom = MeteredOrdMap::from_map(om, &budget)?;
@@ -502,10 +455,6 @@ mod test_footprint {
         assert!(fp
             .enforce_access(&key2, AccessType::ReadOnly, &budget)
             .is_err());
-        assert!(fp
-            .enforce_access(&key3, AccessType::ReadOnly, &budget)
-            .is_err());
-
         fp.enforce_access(&key, AccessType::ReadOnly, &budget)?;
         fp.0 =
             fp.0.insert(Rc::clone(&key), AccessType::ReadWrite, &budget)?;
@@ -518,15 +467,11 @@ mod test_footprint {
     fn footprint_enforce_access_not_exist() -> Result<(), HostError> {
         let budget = Budget::default();
         let mut fp = Footprint::default();
-        let key = Rc::metered_new(
-            LedgerKey::ContractData(LedgerKeyContractData {
-                contract: ScAddress::Contract([0; 32].into()),
-                key: ScVal::I32(0),
-                durability: ContractDataDurability::Persistent,
-                body_type: ContractEntryBodyType::DataEntry,
-            }),
-            &budget,
-        )?;
+        let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
+            contract: ScAddress::Contract([0; 32].into()),
+            key: ScVal::I32(0),
+            durability: ContractDataDurability::Persistent,
+        }));
         let res = fp.enforce_access(&key, AccessType::ReadOnly, &budget);
         assert!(HostError::result_matches_err(
             res,
@@ -538,15 +483,11 @@ mod test_footprint {
     #[test]
     fn footprint_attempt_to_write_readonly_entry() -> Result<(), HostError> {
         let budget = Budget::default();
-        let key = Rc::metered_new(
-            LedgerKey::ContractData(LedgerKeyContractData {
-                contract: ScAddress::Contract([0; 32].into()),
-                key: ScVal::I32(0),
-                durability: ContractDataDurability::Persistent,
-                body_type: ContractEntryBodyType::DataEntry,
-            }),
-            &budget,
-        )?;
+        let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
+            contract: ScAddress::Contract([0; 32].into()),
+            key: ScVal::I32(0),
+            durability: ContractDataDurability::Persistent,
+        }));
         let om = [(Rc::clone(&key), AccessType::ReadOnly)].into();
         let mom = MeteredOrdMap::from_map(om, &budget)?;
         let mut fp = Footprint(mom);
@@ -567,17 +508,17 @@ pub(crate) mod test_storage {
 
     use super::*;
     #[allow(dead_code)]
-    pub(crate) struct MockSnapshotSource(BTreeMap<Rc<LedgerKey>, Rc<LedgerEntry>>);
+    pub(crate) struct MockSnapshotSource(BTreeMap<Rc<LedgerKey>, (Rc<LedgerEntry>, Option<u32>)>);
     #[allow(dead_code)]
     impl MockSnapshotSource {
         pub(crate) fn new() -> Self {
-            Self(BTreeMap::<Rc<LedgerKey>, Rc<LedgerEntry>>::new())
+            Self(BTreeMap::<Rc<LedgerKey>, (Rc<LedgerEntry>, Option<u32>)>::new())
         }
     }
     impl SnapshotSource for MockSnapshotSource {
-        fn get(&self, key: &Rc<LedgerKey>) -> Result<Rc<LedgerEntry>, HostError> {
+        fn get(&self, key: &Rc<LedgerKey>) -> Result<(Rc<LedgerEntry>, Option<u32>), HostError> {
             if let Some(val) = self.0.get(key) {
-                Ok(Rc::clone(&val))
+                Ok((Rc::clone(&val.0), val.1))
             } else {
                 Err(
                     Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::MissingValue)


Test patch:
diff --git a/soroban-env-host/src/e2e_invoke.rs b/soroban-env-host/src/e2e_invoke.rs
index 3b2d2462..847ca2dd 100644
--- a/soroban-env-host/src/e2e_invoke.rs
+++ b/soroban-env-host/src/e2e_invoke.rs
@@ -6,10 +6,9 @@ use std::{cmp::max, rc::Rc};
 
 use soroban_env_common::{
     xdr::{
-        AccountId, ContractCodeEntryBody, ContractDataDurability, ContractDataEntryBody,
-        ContractEntryBodyType, ContractEventType, DiagnosticEvent, HostFunction, LedgerEntry,
-        LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount, LedgerKeyContractCode,
-        LedgerKeyContractData, LedgerKeyTrustLine, ScErrorCode, ScErrorType,
+        AccountId, ContractDataDurability, ContractEventType, DiagnosticEvent, HostFunction,
+        LedgerEntry, LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount,
+        LedgerKeyContractCode, LedgerKeyContractData, LedgerKeyTrustLine, ScErrorCode, ScErrorType,
         SorobanAuthorizationEntry, SorobanResources,
     },
     Error,
@@ -20,7 +19,7 @@ use crate::{
     events::Events,
     fees::LedgerEntryRentChange,
     host::{
-        ledger_info_helper::{get_entry_expiration, get_key_durability, set_entry_expiration},
+        ledger_info_helper::get_key_durability,
         metered_clone::{MeteredAlloc, MeteredClone, MeteredIterator},
         metered_xdr::{metered_from_xdr_with_budget, metered_write_xdr},
     },
@@ -99,7 +98,7 @@ pub fn get_ledger_changes<T: SnapshotSource>(
     // happen in embedder environments, or simply fundamental invariant bugs.
     let internal_error: HostError =
         Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::InternalError).into();
-    for (key, entry) in storage.map.iter(budget)? {
+    for (key, entry_with_expiration) in storage.map.iter(budget)? {
         let mut entry_change = LedgerEntryChange::default();
         metered_write_xdr(budget, key.as_ref(), &mut entry_change.encoded_key)?;
         let durability = get_key_durability(key);
@@ -111,22 +110,21 @@ pub fn get_ledger_changes<T: SnapshotSource>(
             });
         }
         if init_storage_snapshot.has(key)? {
-            let old_entry = init_storage_snapshot.get(key)?;
+            let (old_entry, old_expiration) = init_storage_snapshot.get(key)?;
             let mut buf = vec![];
             metered_write_xdr(budget, old_entry.as_ref(), &mut buf)?;
             entry_change.old_entry_size_bytes = buf.len() as u32;
 
             if let Some(ref mut expiration_change) = &mut entry_change.expiration_change {
-                expiration_change.old_expiration_ledger = get_entry_expiration(old_entry.as_ref())
-                    .ok_or_else(|| internal_error.clone())?;
+                expiration_change.old_expiration_ledger =
+                    old_expiration.ok_or_else(|| internal_error.clone())?;
             }
         }
-        if let Some(entry) = entry {
+        if let Some((_, new_expiration_ledger)) = entry_with_expiration {
             if let Some(ref mut expiration_change) = &mut entry_change.expiration_change {
-                // Never reduce the expiration ledger. This is also handled when
-                // processing RW entries.
+                // Never reduce the final expiration ledger.
                 expiration_change.new_expiration_ledger = max(
-                    get_entry_expiration(entry.as_ref()).ok_or_else(|| internal_error.clone())?,
+                    new_expiration_ledger.ok_or_else(|| internal_error.clone())?,
                     expiration_change.old_expiration_ledger,
                 );
             }
@@ -138,30 +136,10 @@ pub fn get_ledger_changes<T: SnapshotSource>(
                 entry_change.read_only = true;
             }
             Some(AccessType::ReadWrite) => {
-                if let Some(entry) = entry {
-                    // Handle the edge case where due to combinations of
-                    // deletions/creations the entry expiration has been
-                    // reduced.
-                    let mut entry_written = false;
-                    if let (Some(expiration_change), Some(new_expiration)) = (
-                        &entry_change.expiration_change,
-                        get_entry_expiration(entry.as_ref()),
-                    ) {
-                        if expiration_change.old_expiration_ledger > new_expiration {
-                            let mut new_entry: LedgerEntry =
-                                entry.as_ref().metered_clone(budget)?;
-                            set_entry_expiration(&mut new_entry, new_expiration);
-                            let mut entry_buf = vec![];
-                            metered_write_xdr(budget, &new_entry, &mut entry_buf)?;
-                            entry_change.encoded_new_value = Some(entry_buf);
-                            entry_written = true;
-                        }
-                    }
-                    if !entry_written {
-                        let mut entry_buf = vec![];
-                        metered_write_xdr(budget, entry.as_ref(), &mut entry_buf)?;
-                        entry_change.encoded_new_value = Some(entry_buf);
-                    }
+                if let Some((entry, _)) = entry_with_expiration {
+                    let mut entry_buf = vec![];
+                    metered_write_xdr(budget, entry.as_ref(), &mut entry_buf)?;
+                    entry_change.encoded_new_value = Some(entry_buf);
                 }
             }
             None => {
@@ -236,7 +214,11 @@ pub fn extract_rent_changes(ledger_changes: &Vec<LedgerEntryChange>) -> Vec<Ledg
 /// When diagnostics are enabled, we try to populate `diagnostic_events`
 /// even if the `InvokeHostFunctionResult` fails for any reason.
 #[allow(clippy::too_many_arguments)]
-pub fn invoke_host_function<T: AsRef<[u8]>, I: ExactSizeIterator<Item = T>>(
+pub fn invoke_host_function<
+    T: AsRef<[u8]>,
+    I: ExactSizeIterator<Item = T>,
+    EntryIter: ExactSizeIterator<Item = (T, Option<u32>)>,
+>(
     budget: &Budget,
     enable_diagnostics: bool,
     encoded_host_fn: T,
@@ -244,7 +226,7 @@ pub fn invoke_host_function<T: AsRef<[u8]>, I: ExactSizeIterator<Item = T>>(
     encoded_source_account: T,
     encoded_auth_entries: I,
     ledger_info: LedgerInfo,
-    encoded_ledger_entries: I,
+    encoded_ledger_entries: EntryIter,
     base_prng_seed: T,
     diagnostic_events: &mut Vec<DiagnosticEvent>,
 ) -> Result<InvokeHostFunctionResult, HostError> {
@@ -366,25 +348,9 @@ fn ledger_entry_to_ledger_key(le: &LedgerEntry, budget: &Budget) -> Result<Ledge
             contract: cd.contract.metered_clone(budget)?,
             key: cd.key.metered_clone(budget)?,
             durability: cd.durability,
-            body_type: match &cd.body {
-                ContractDataEntryBody::DataEntry(_data) => ContractEntryBodyType::DataEntry,
-                ContractDataEntryBody::ExpirationExtension => {
-                    ContractEntryBodyType::ExpirationExtension
-                }
-            },
         })),
         LedgerEntryData::ContractCode(code) => Ok(LedgerKey::ContractCode(LedgerKeyContractCode {
             hash: code.hash.metered_clone(budget)?,
-            body_type: match &code.body {
-                ContractCodeEntryBody::DataEntry(_) => ContractEntryBodyType::DataEntry,
-                ContractCodeEntryBody::ExpirationExtension => {
-                    return Err(Error::from_type_and_code(
-                        ScErrorType::Storage,
-                        ScErrorCode::InternalError,
-                    )
-                    .into());
-                }
-            },
         })),
         _ => {
             return Err(Error::from_type_and_code(
@@ -422,13 +388,16 @@ fn build_storage_footprint_from_xdr(
     Ok(Footprint(footprint_map))
 }
 
-fn build_storage_map_from_xdr_ledger_entries<T: AsRef<[u8]>, I: ExactSizeIterator<Item = T>>(
+fn build_storage_map_from_xdr_ledger_entries<
+    T: AsRef<[u8]>,
+    I: ExactSizeIterator<Item = (T, Option<u32>)>,
+>(
     budget: &Budget,
     footprint: &Footprint,
     encoded_ledger_entries: I,
 ) -> Result<StorageMap, HostError> {
     let mut map = StorageMap::new();
-    for buf in encoded_ledger_entries {
+    for (buf, expiration_ledger) in encoded_ledger_entries {
         let le = Rc::metered_new(
             metered_from_xdr_with_budget::<LedgerEntry>(buf.as_ref(), budget)?,
             budget,
@@ -441,7 +410,7 @@ fn build_storage_map_from_xdr_ledger_entries<T: AsRef<[u8]>, I: ExactSizeIterato
             )
             .into());
         }
-        map = map.insert(key, Some(le), budget)?;
+        map = map.insert(key, Some((le, expiration_ledger)), budget)?;
     }
 
     // Add non-existing entries from the footprint to the storage.
@@ -472,9 +441,9 @@ struct StorageMapSnapshotSource<'a> {
 }
 
 impl<'a> SnapshotSource for StorageMapSnapshotSource<'a> {
-    fn get(&self, key: &Rc<LedgerKey>) -> Result<Rc<LedgerEntry>, HostError> {
-        if let Some(Some(value)) = self.map.get::<Rc<LedgerKey>>(key, self.budget)? {
-            Ok(Rc::clone(value))
+    fn get(&self, key: &Rc<LedgerKey>) -> Result<(Rc<LedgerEntry>, Option<u32>), HostError> {
+        if let Some(Some((entry, expiration))) = self.map.get::<Rc<LedgerKey>>(key, self.budget)? {
+            Ok((Rc::clone(entry), *expiration))
         } else {
             Err(Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::InternalError).into())
         }
diff --git a/soroban-env-host/src/native_contract/testutils.rs b/soroban-env-host/src/native_contract/testutils.rs
index 79ba1dd7..363cdb44 100644
--- a/soroban-env-host/src/native_contract/testutils.rs
+++ b/soroban-env-host/src/native_contract/testutils.rs
@@ -322,6 +322,7 @@ pub(crate) fn create_account(
     host.add_ledger_entry(
         &key,
         &Host::ledger_entry_from_data(host, LedgerEntryData::Account(acc_entry)).unwrap(),
+        None,
     )
     .unwrap();
 }
diff --git a/soroban-env-host/src/test/auth.rs b/soroban-env-host/src/test/auth.rs
index fcda0f75..6dba8925 100644
--- a/soroban-env-host/src/test/auth.rs
+++ b/soroban-env-host/src/test/auth.rs
@@ -229,13 +229,9 @@ impl AuthTest {
                 if !storage.has(&nonce_key, self.host.budget_ref())? {
                     return Ok(None);
                 }
-                let entry = storage.get(&nonce_key, self.host.budget_ref())?;
-                match &entry.data {
-                    soroban_env_common::xdr::LedgerEntryData::ContractData(contract_data) => {
-                        Ok(Some(contract_data.expiration_ledger_seq))
-                    }
-                    _ => panic!("unexpected entry"),
-                }
+                let (_, expiration_ledger) =
+                    storage.get_with_expiration(&nonce_key, self.host.budget_ref())?;
+                Ok(expiration_ledger)
             })
             .unwrap()
     }
diff --git a/soroban-env-host/src/test/complex.rs b/soroban-env-host/src/test/complex.rs
index 3025e6fa..c9f3279a 100644
--- a/soroban-env-host/src/test/complex.rs
+++ b/soroban-env-host/src/test/complex.rs
@@ -20,7 +20,6 @@ fn run_complex() -> Result<(), HostError> {
         min_persistent_entry_expiration: 4096,
         min_temp_entry_expiration: 16,
         max_entry_expiration: 6312000,
-        autobump_ledgers: 0,
     };
     let account_id = generate_account_id();
     let salt = generate_bytes_array();
diff --git a/soroban-env-host/src/test/ledger.rs b/soroban-env-host/src/test/ledger.rs
index 05c11c92..e98b02bd 100644
--- a/soroban-env-host/src/test/ledger.rs
+++ b/soroban-env-host/src/test/ledger.rs
@@ -22,7 +22,6 @@ fn ledger_network_id() -> Result<(), HostError> {
         min_persistent_entry_expiration: 4096,
         min_temp_entry_expiration: 16,
         max_entry_expiration: 6312000,
-        autobump_ledgers: 0,
     })?;
     let obj = host.get_ledger_network_id()?;
     let np = host.visit_obj(obj, |np: &ScBytes| Ok(np.to_vec()))?;
diff --git a/soroban-env-host/src/test/lifecycle.rs b/soroban-env-host/src/test/lifecycle.rs
index 1954d244..8c3e2239 100644
--- a/soroban-env-host/src/test/lifecycle.rs
+++ b/soroban-env-host/src/test/lifecycle.rs
@@ -13,8 +13,7 @@ use crate::{
 };
 use sha2::{Digest, Sha256};
 use soroban_env_common::xdr::{
-    ContractCodeEntryBody, ContractDataEntry, ContractDataEntryBody, ContractIdPreimage,
-    ContractIdPreimageFromAddress, DepthLimitedWrite, HostFunction, ScAddress,
+    ContractIdPreimage, ContractIdPreimageFromAddress, DepthLimitedWrite, HostFunction, ScAddress,
     SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanAuthorizedInvocation,
     SorobanCredentials, VecM, DEFAULT_XDR_RW_DEPTH_LIMIT,
 };
@@ -30,15 +29,12 @@ fn get_contract_wasm_ref(host: &Host, contract_id: Hash) -> Hash {
         assert!(s.has(&storage_key, host.as_budget()).unwrap());
 
         match &s.get(&storage_key, host.as_budget()).unwrap().data {
-            LedgerEntryData::ContractData(ContractDataEntry { body, .. }) => match body {
-                ContractDataEntryBody::DataEntry(data) => match &data.val {
-                    ScVal::ContractInstance(i) => match &i.executable {
-                        ContractExecutable::Wasm(h) => Ok(h.clone()),
-                        _ => panic!("expectecd Wasm executable"),
-                    },
-                    _ => panic!("expected ContractInstance"),
+            LedgerEntryData::ContractData(e) => match &e.val {
+                ScVal::ContractInstance(i) => match &i.executable {
+                    ContractExecutable::Wasm(h) => Ok(h.clone()),
+                    _ => panic!("expectecd Wasm executable"),
                 },
-                _ => panic!("expected DataEntry"),
+                _ => panic!("expected ContractInstance"),
             },
             _ => panic!("expected contract data"),
         }
@@ -52,10 +48,7 @@ fn get_contract_wasm(host: &Host, wasm_hash: Hash) -> Vec<u8> {
         assert!(s.has(&storage_key, host.as_budget()).unwrap());
 
         match &s.get(&storage_key, host.as_budget()).unwrap().data {
-            LedgerEntryData::ContractCode(code_entry) => match &code_entry.body {
-                ContractCodeEntryBody::DataEntry(code) => Ok(code.to_vec()),
-                _ => panic!("expected DataEntry"),
-            },
+            LedgerEntryData::ContractCode(code_entry) => Ok(code_entry.code.to_vec()),
             _ => panic!("expected contract WASM code"),
         }
     })
diff --git a/soroban-env-host/src/test/metering_benchmark.rs b/soroban-env-host/src/test/metering_benchmark.rs
index 5eb30488..d09340bc 100644
--- a/soroban-env-host/src/test/metering_benchmark.rs
+++ b/soroban-env-host/src/test/metering_benchmark.rs
@@ -29,7 +29,6 @@ const LEDGER_INFO: LedgerInfo = LedgerInfo {
     min_persistent_entry_expiration: 4096,
     min_temp_entry_expiration: 16,
     max_entry_expiration: 6312000,
-    autobump_ledgers: 0,
 };
 
 #[ignore]
diff --git a/soroban-env-host/src/test/prng.rs b/soroban-env-host/src/test/prng.rs
index f493054f..a6026203 100644
--- a/soroban-env-host/src/test/prng.rs
+++ b/soroban-env-host/src/test/prng.rs
@@ -29,7 +29,7 @@ pub struct PRNGUsingTest;
 impl ContractFunctionSet for PRNGUsingTest {
     fn call(&self, func: &Symbol, host: &Host, args: &[Val]) -> Option<Val> {
         let Ok(func) = SymbolSmall::try_from(func.to_val()) else {
-            return None
+            return None;
         };
         let val = if func == BYTES_NEW {
             host.prng_bytes_new(U32Val::from(SEED_LEN))
diff --git a/soroban-env-host/src/test/token.rs b/soroban-env-host/src/test/token.rs
index 6436f966..1246037e 100644
--- a/soroban-env-host/src/test/token.rs
+++ b/soroban-env-host/src/test/token.rs
@@ -58,7 +58,6 @@ impl TokenTest {
             min_persistent_entry_expiration: 4096,
             min_temp_entry_expiration: 16,
             max_entry_expiration: 6_312_000,
-            autobump_ledgers: 0,
         })
         .unwrap();
         Self {
@@ -182,7 +181,7 @@ impl TokenTest {
                             &self.host,
                             LedgerEntryData::Account(account),
                         )?;
-                        s.put(key, &update, self.host.as_budget())
+                        s.put(key, &update, None, self.host.as_budget())
                     }
                     _ => unreachable!(),
                 }
@@ -245,6 +244,7 @@ impl TokenTest {
                     LedgerEntryData::Trustline(trustline_entry),
                 )
                 .unwrap(),
+                None,
             )
             .unwrap();
 
@@ -262,7 +262,7 @@ impl TokenTest {
                             &self.host,
                             LedgerEntryData::Trustline(trustline),
                         )?;
-                        s.put(key, &update, self.host.as_budget())
+                        s.put(key, &update, None, self.host.as_budget())
                     }
                     _ => unreachable!(),
                 }
diff --git a/soroban-env-host/src/test/util.rs b/soroban-env-host/src/test/util.rs
index fa329239..c1e2d263 100644
--- a/soroban-env-host/src/test/util.rs
+++ b/soroban-env-host/src/test/util.rs
@@ -87,7 +87,6 @@ impl Host {
             min_persistent_entry_expiration: 4096,
             min_temp_entry_expiration: 16,
             max_entry_expiration: 6_312_000,
-            autobump_ledgers: 0,
         })
         .unwrap();
         host
diff --git a/soroban-test-wasms/wasm-workspace/Cargo.lock b/soroban-test-wasms/wasm-workspace/Cargo.lock
index fad67ab4..aa833d08 100644
--- a/soroban-test-wasms/wasm-workspace/Cargo.lock
+++ b/soroban-test-wasms/wasm-workspace/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.19.0"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
 dependencies = [
  "gimli",
 ]
@@ -56,9 +56,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.67"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
 dependencies = [
  "addr2line",
  "cc",
@@ -99,15 +99,6 @@ version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
 
-[[package]]
-name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
 [[package]]
 name = "block-buffer"
 version = "0.10.4"
@@ -123,12 +114,6 @@ version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
 
-[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
 [[package]]
 name = "bytes-lit"
 version = "0.0.5"
@@ -143,9 +128,12 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.79"
+version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
 
 [[package]]
 name = "cfg-if"
@@ -168,9 +156,9 @@ dependencies = [
 
 [[package]]
 name = "const-oid"
-version = "0.9.2"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
+checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
 
 [[package]]
 name = "core-foundation-sys"
@@ -180,9 +168,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.7"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
+checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
 dependencies = [
  "libc",
 ]
@@ -205,7 +193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
  "zeroize",
 ]
@@ -222,27 +210,14 @@ dependencies = [
 
 [[package]]
 name = "ctor"
-version = "0.2.2"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1586fa608b1dab41f667475b4a41faec5ba680aee428bfa5de4ea520fdc6e901"
+checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b"
 dependencies = [
  "quote",
  "syn",
 ]
 
-[[package]]
-name = "curve25519-dalek"
-version = "3.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
-dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
- "subtle",
- "zeroize",
-]
-
 [[package]]
 name = "curve25519-dalek"
 version = "4.0.0"
@@ -252,7 +227,7 @@ dependencies = [
  "cfg-if",
  "cpufeatures",
  "curve25519-dalek-derive",
- "digest 0.10.7",
+ "digest",
  "fiat-crypto",
  "platforms",
  "rustc_version",
@@ -273,9 +248,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.20.1"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -283,9 +258,9 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.20.1"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
 dependencies = [
  "fnv",
  "ident_case",
@@ -297,9 +272,9 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
-version = "0.20.1"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
 dependencies = [
  "darling_core",
  "quote",
@@ -308,14 +283,23 @@ dependencies = [
 
 [[package]]
 name = "der"
-version = "0.7.6"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17"
+checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
 dependencies = [
  "const-oid",
  "zeroize",
 ]
 
+[[package]]
+name = "deranged"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "derive_arbitrary"
 version = "1.3.1"
@@ -327,22 +311,13 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
 [[package]]
 name = "digest"
 version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
- "block-buffer 0.10.4",
+ "block-buffer",
  "const-oid",
  "crypto-common",
  "subtle",
@@ -356,49 +331,26 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
 [[package]]
 name = "ecdsa"
-version = "0.16.7"
+version = "0.16.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428"
+checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
 dependencies = [
  "der",
- "digest 0.10.7",
+ "digest",
  "elliptic-curve",
  "rfc6979",
- "signature 2.1.0",
+ "signature",
  "spki",
 ]
 
 [[package]]
 name = "ed25519"
-version = "1.5.3"
+version = "2.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
-dependencies = [
- "signature 1.6.4",
-]
-
-[[package]]
-name = "ed25519"
-version = "2.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
+checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d"
 dependencies = [
  "pkcs8",
- "signature 2.1.0",
-]
-
-[[package]]
-name = "ed25519-dalek"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
-dependencies = [
- "curve25519-dalek 3.2.0",
- "ed25519 1.5.3",
- "rand 0.7.3",
- "serde",
- "sha2 0.9.9",
- "zeroize",
+ "signature",
 ]
 
 [[package]]
@@ -407,19 +359,19 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980"
 dependencies = [
- "curve25519-dalek 4.0.0",
- "ed25519 2.2.1",
- "rand_core 0.6.4",
+ "curve25519-dalek",
+ "ed25519",
+ "rand_core",
  "serde",
- "sha2 0.10.6",
+ "sha2",
  "zeroize",
 ]
 
 [[package]]
 name = "either"
-version = "1.8.1"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
 
 [[package]]
 name = "elliptic-curve"
@@ -429,17 +381,23 @@ checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "digest 0.10.7",
+ "digest",
  "ff",
  "generic-array",
  "group",
  "pkcs8",
- "rand_core 0.6.4",
+ "rand_core",
  "sec1",
  "subtle",
  "zeroize",
 ]
 
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
 [[package]]
 name = "ethnum"
 version = "1.3.2"
@@ -558,7 +516,7 @@ version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
@@ -585,17 +543,6 @@ dependencies = [
  "zeroize",
 ]
 
-[[package]]
-name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
-]
-
 [[package]]
 name = "getrandom"
 version = "0.2.10"
@@ -605,15 +552,15 @@ dependencies = [
  "cfg-if",
  "js-sys",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "gimli"
-version = "0.27.2"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
 
 [[package]]
 name = "group"
@@ -622,7 +569,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
 dependencies = [
  "ff",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
@@ -632,6 +579,12 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
+[[package]]
+name = "hashbrown"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+
 [[package]]
 name = "hex"
 version = "0.4.3"
@@ -647,7 +600,7 @@ version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.7",
+ "digest",
 ]
 
 [[package]]
@@ -686,7 +639,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.0",
  "serde",
 ]
 
@@ -707,9 +671,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.6"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
 
 [[package]]
 name = "js-sys"
@@ -730,8 +694,8 @@ dependencies = [
  "ecdsa",
  "elliptic-curve",
  "once_cell",
- "sha2 0.10.6",
- "signature 2.1.0",
+ "sha2",
+ "signature",
 ]
 
 [[package]]
@@ -745,9 +709,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.146"
+version = "0.2.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
 
 [[package]]
 name = "libm"
@@ -757,9 +721,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
 
 [[package]]
 name = "log"
-version = "0.4.19"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "memchr"
@@ -769,18 +733,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.6.2"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "num-bigint"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
 dependencies = [
  "autocfg",
  "num-integer",
@@ -810,18 +774,18 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "object"
-version = "0.30.4"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
+checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
 dependencies = [
  "memchr",
 ]
@@ -832,17 +796,11 @@ version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
-[[package]]
-name = "opaque-debug"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
-
 [[package]]
 name = "paste"
-version = "1.0.12"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
 
 [[package]]
 name = "pkcs8"
@@ -868,9 +826,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "prettyplease"
-version = "0.2.6"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b69d39aab54d069e7f2fe8cb970493e7834601ca2d8c65fd7bbd183578080d1"
+checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
 dependencies = [
  "proc-macro2",
  "syn",
@@ -878,35 +836,22 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.60"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.28"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
-]
-
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -914,18 +859,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
+ "rand_chacha",
+ "rand_core",
 ]
 
 [[package]]
@@ -935,16 +870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
+ "rand_core",
 ]
 
 [[package]]
@@ -953,16 +879,7 @@ version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom 0.2.10",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-dependencies = [
- "rand_core 0.5.1",
+ "getrandom",
 ]
 
 [[package]]
@@ -992,15 +909,15 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.13"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
 
 [[package]]
 name = "sec1"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e"
+checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
 dependencies = [
  "base16ct",
  "der",
@@ -1012,24 +929,24 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
 
 [[package]]
 name = "serde"
-version = "1.0.164"
+version = "1.0.186"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
+checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.164"
+version = "1.0.186"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
+checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1038,9 +955,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.96"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
+checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
 dependencies = [
  "itoa",
  "ryu",
@@ -1049,14 +966,15 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.0.0"
+version = "3.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
+checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237"
 dependencies = [
  "base64 0.21.2",
  "chrono",
  "hex",
- "indexmap",
+ "indexmap 1.9.3",
+ "indexmap 2.0.0",
  "serde",
  "serde_json",
  "serde_with_macros",
@@ -1065,9 +983,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.0.0"
+version = "3.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"
+checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -1077,26 +995,13 @@ dependencies = [
 
 [[package]]
 name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
-version = "0.10.6"
+version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
+checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.7",
+ "digest",
 ]
 
 [[package]]
@@ -1105,31 +1010,25 @@ version = "0.10.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
 dependencies = [
- "digest 0.10.7",
+ "digest",
  "keccak",
 ]
 
-[[package]]
-name = "signature"
-version = "1.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
-
 [[package]]
 name = "signature"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 dependencies = [
- "digest 0.10.7",
- "rand_core 0.6.4",
+ "digest",
+ "rand_core",
 ]
 
 [[package]]
 name = "smallvec"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
 
 [[package]]
 name = "soroban-env-common"
@@ -1144,7 +1043,7 @@ dependencies = [
  "soroban-env-macros",
  "soroban-wasmi",
  "static_assertions",
- "stellar-xdr",
+ "stellar-xdr 0.0.17 (git+https://github.com/stellar/rs-stellar-xdr?rev=936273b737b99d79eee7a28dd4823436d0bd0abb)",
 ]
 
 [[package]]
@@ -1160,18 +1059,18 @@ name = "soroban-env-host"
 version = "0.0.17"
 dependencies = [
  "backtrace",
- "curve25519-dalek 4.0.0",
- "ed25519-dalek 2.0.0",
- "getrandom 0.2.10",
+ "curve25519-dalek",
+ "ed25519-dalek",
+ "getrandom",
  "hex",
  "k256",
  "log",
  "num-derive",
  "num-integer",
  "num-traits",
- "rand 0.8.5",
- "rand_chacha 0.3.1",
- "sha2 0.10.6",
+ "rand",
+ "rand_chacha",
+ "sha2",
  "sha3",
  "soroban-env-common",
  "soroban-native-sdk-macros",
@@ -1189,7 +1088,7 @@ dependencies = [
  "quote",
  "serde",
  "serde_json",
- "stellar-xdr",
+ "stellar-xdr 0.0.17 (git+https://github.com/stellar/rs-stellar-xdr?rev=936273b737b99d79eee7a28dd4823436d0bd0abb)",
  "syn",
 ]
 
@@ -1221,8 +1120,8 @@ dependencies = [
  "arbitrary",
  "bytes-lit",
  "ctor",
- "ed25519-dalek 1.0.1",
- "rand 0.7.3",
+ "ed25519-dalek",
+ "rand",
  "soroban-env-guest",
  "soroban-env-host",
  "soroban-ledger-snapshot",
@@ -1240,11 +1139,11 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustc_version",
- "sha2 0.9.9",
+ "sha2",
  "soroban-env-common",
  "soroban-spec",
  "soroban-spec-rust",
- "stellar-xdr",
+ "stellar-xdr 0.0.17 (git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567)",
  "syn",
 ]
 
@@ -1253,7 +1152,7 @@ name = "soroban-spec"
 version = "0.9.2"
 dependencies = [
  "base64 0.13.1",
- "stellar-xdr",
+ "stellar-xdr 0.0.17 (git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567)",
  "thiserror",
  "wasmparser",
 ]
@@ -1265,9 +1164,9 @@ dependencies = [
  "prettyplease",
  "proc-macro2",
  "quote",
- "sha2 0.9.9",
+ "sha2",
  "soroban-spec",
- "stellar-xdr",
+ "stellar-xdr 0.0.17 (git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567)",
  "syn",
  "thiserror",
 ]
@@ -1325,7 +1224,7 @@ dependencies = [
 [[package]]
 name = "stellar-xdr"
 version = "0.0.17"
-source = "git+https://github.com/stellar/rs-stellar-xdr?rev=4876e5eb20016caebbd13bcf6401626dc6073b8e#4876e5eb20016caebbd13bcf6401626dc6073b8e"
+source = "git+https://github.com/stellar/rs-stellar-xdr?rev=936273b737b99d79eee7a28dd4823436d0bd0abb#936273b737b99d79eee7a28dd4823436d0bd0abb"
 dependencies = [
  "arbitrary",
  "base64 0.13.1",
@@ -1335,6 +1234,17 @@ dependencies = [
  "serde_with",
 ]
 
+[[package]]
+name = "stellar-xdr"
+version = "0.0.17"
+source = "git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567#e2a9cbf72d94941de1bde6ba34a38e1f49328567"
+dependencies = [
+ "crate-git-revision",
+ "hex",
+ "serde",
+ "serde_with",
+]
+
 [[package]]
 name = "strsim"
 version = "0.10.0"
@@ -1349,9 +1259,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
 
 [[package]]
 name = "syn"
-version = "2.0.18"
+version = "2.0.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1367,18 +1277,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.40"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.40"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1387,10 +1297,11 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.22"
+version = "0.3.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
+checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07"
 dependencies = [
+ "deranged",
  "itoa",
  "serde",
  "time-core",
@@ -1405,9 +1316,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
 
 [[package]]
 name = "time-macros"
-version = "0.2.9"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
+checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9"
 dependencies = [
  "time-core",
 ]
@@ -1420,9 +1331,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.9"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
 
 [[package]]
 name = "version_check"
@@ -1430,12 +1341,6 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
-[[package]]
-name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
-
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -1518,7 +1423,7 @@ version = "0.88.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e"
 dependencies = [
- "indexmap",
+ "indexmap 1.9.3",
 ]
 
 [[package]]
@@ -1563,9 +1468,9 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -1578,62 +1483,48 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "zeroize"
 version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]