Repository: stellar/rs-soroban-env
Pull request #763 (2023-04-11 22:15:49)

Adapt {ui}{128,256} to new xdr definitions; add {ui}256 host functions
### What

Adapt {ui}{128,256} to [new xdr definitions](https://github.com/stellar/stellar-xdr/pull/78) which fixes inconsistent ordering between the host and the xdr forms (issue first discovered in https://github.com/stellar/rs-soroban-env/issues/743#issuecomment-1496661230)

Also added minimal set of host functions for {ui}256 to enable testing.

Added some testing to do roundtrip comparisons. 

(These are currently pinned to my local branch in rs-stellar-xdr, will update once [this PR](https://github.com/stellar/rs-stellar-xdr/pull/243) is merged.)

### Why

[TODO: Why this change is being made. Include any context required to understand the why.]

### Known limitations

[TODO or N/A]



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 84b19ac5..6c6574f4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -577,9 +577,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590"
 
 [[package]]
 name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
 dependencies = [
  "either",
 ]
@@ -1177,7 +1177,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 [[package]]
 name = "stellar-xdr"
 version = "0.0.15"
-source = "git+https://github.com/stellar/rs-stellar-xdr?rev=bcf6f4c3a9dd32822a20af89880650a421d10e7f#bcf6f4c3a9dd32822a20af89880650a421d10e7f"
+source = "git+https://github.com/jayz22/rs-stellar-xdr?rev=b04c3c26546335b063e2797175689c45c752612a#b04c3c26546335b063e2797175689c45c752612a"
 dependencies = [
  "arbitrary",
  "base64",
diff --git a/Cargo.toml b/Cargo.toml
index 12f3e25c..5c4872bb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,7 +27,7 @@ soroban-native-sdk-macros = { version = "0.0.15", path = "soroban-native-sdk-mac
 [workspace.dependencies.stellar-xdr]
 version = "0.0.15"
 git = "https://github.com/stellar/rs-stellar-xdr"
-rev = "bcf6f4c3a9dd32822a20af89880650a421d10e7f"
+rev = "8035c58fa4753de06ec034905d2240addf8b37a6"
 default-features = false
 
 [workspace.dependencies.wasmi]
diff --git a/soroban-env-common/env.json b/soroban-env-common/env.json
index 49e68fee..e1d74d41 100644
--- a/soroban-env-common/env.json
+++ b/soroban-env-common/env.json
@@ -191,16 +191,16 @@
                     "name": "obj_from_u128_pieces",
                     "args": [
                         {
-                            "name": "lo",
+                            "name": "hi",
                             "type": "u64"
                         },
                         {
-                            "name": "hi",
+                            "name": "lo",
                             "type": "u64"
                         }
                     ],
                     "return": "U128Object",
-                    "docs": "Convert the low and high 64-bit words of a u128 to an object containing a u128."
+                    "docs": "Convert the high and low 64-bit words of a u128 to an object containing a u128."
                 },
                 {
                     "export": "6",
@@ -231,16 +231,16 @@
                     "name": "obj_from_i128_pieces",
                     "args": [
                         {
-                            "name": "lo",
-                            "type": "u64"
+                            "name": "hi",
+                            "type": "i64"
                         },
                         {
-                            "name": "hi",
+                            "name": "lo",
                             "type": "u64"
                         }
                     ],
                     "return": "I128Object",
-                    "docs": "Convert the lo and hi 64-bit words of an i128 to an object containing an i128."
+                    "docs": "Convert the high and low 64-bit words of an i128 to an object containing an i128."
                 },
                 {
                     "export": "9",
@@ -263,8 +263,152 @@
                             "type": "I128Object"
                         }
                     ],
-                    "return": "u64",
+                    "return": "i64",
                     "docs": "Extract the high 64 bits from an object containing an i128."
+                },
+                {
+                    "export": "b",
+                    "name": "obj_from_u256_pieces",
+                    "args": [
+                        {
+                            "name": "hi_hi",
+                            "type": "u64"
+                        },
+                        {
+                            "name": "hi_lo",
+                            "type": "u64"
+                        },
+                        {
+                            "name": "lo_hi",
+                            "type": "u64"
+                        },
+                        {
+                            "name": "lo_lo",
+                            "type": "u64"
+                        }
+                    ],
+                    "return": "U256Object",
+                    "docs": "Convert the four 64-bit words of an u256 (big-endian) to an object containing an u256."
+                },
+                {
+                    "export": "c",
+                    "name": "obj_to_u256_hi_hi",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "U256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract the highest 64-bits (bits 192-255) from an object containing an u256."
+                },
+                {
+                    "export": "d",
+                    "name": "obj_to_u256_hi_lo",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "U256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract bits 128-191 from an object containing an u256."
+                },
+                {
+                    "export": "e",
+                    "name": "obj_to_u256_lo_hi",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "U256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract bits 64-127 from an object containing an u256."
+                },
+                {
+                    "export": "f",
+                    "name": "obj_to_u256_lo_lo",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "U256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract the lowest 64-bits (bits 0-63) from an object containing an u256."
+                },                
+                {
+                    "export": "g",
+                    "name": "obj_from_i256_pieces",
+                    "args": [
+                        {
+                            "name": "hi_hi",
+                            "type": "i64"
+                        },
+                        {
+                            "name": "hi_lo",
+                            "type": "u64"
+                        },
+                        {
+                            "name": "lo_hi",
+                            "type": "u64"
+                        },
+                        {
+                            "name": "lo_lo",
+                            "type": "u64"
+                        }
+                    ],
+                    "return": "I256Object",
+                    "docs": "Convert the four 64-bit words of an i256 (big-endian) to an object containing an i256."
+                },
+                {
+                    "export": "h",
+                    "name": "obj_to_i256_hi_hi",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "I256Object"
+                        }
+                    ],
+                    "return": "i64",
+                    "docs": "Extract the highest 64-bits (bits 192-255) from an object containing an i256."
+                },
+                {
+                    "export": "i",
+                    "name": "obj_to_i256_hi_lo",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "I256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract bits 128-191 from an object containing an i256."
+                },
+                {
+                    "export": "j",
+                    "name": "obj_to_i256_lo_hi",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "I256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract bits 64-127 from an object containing an i256."
+                },
+                {
+                    "export": "k",
+                    "name": "obj_to_i256_lo_lo",
+                    "args": [
+                        {
+                            "name": "obj",
+                            "type": "I256Object"
+                        }
+                    ],
+                    "return": "u64",
+                    "docs": "Extract the lowest 64-bits (bits 0-63) from an object containing an i256."
                 }
             ]
         },
diff --git a/soroban-env-common/src/env.rs b/soroban-env-common/src/env.rs
index 5a228e2d..0977db85 100644
--- a/soroban-env-common/src/env.rs
+++ b/soroban-env-common/src/env.rs
@@ -2,8 +2,9 @@ use soroban_env_macros::generate_call_macro_with_all_host_functions;
 
 use super::Symbol;
 use super::{
-    AddressObject, Bool, BytesObject, I128Object, I64Object, MapObject, Object, RawVal, Status,
-    StringObject, SymbolObject, U128Object, U32Val, U64Object, U64Val, VecObject, Void,
+    AddressObject, Bool, BytesObject, I128Object, I256Object, I64Object, MapObject, Object, RawVal,
+    Status, StringObject, SymbolObject, U128Object, U256Object, U32Val, U64Object, U64Val,
+    VecObject, Void,
 };
 use core::any;
 
diff --git a/soroban-env-common/src/env_val.rs b/soroban-env-common/src/env_val.rs
index 68e465fb..113176bf 100644
--- a/soroban-env-common/src/env_val.rs
+++ b/soroban-env-common/src/env_val.rs
@@ -1,13 +1,19 @@
-use crate::{ConversionError, Env, I128Small, I64Small, RawVal, U128Small, U64Small, U64Val};
+use crate::{
+    num::{i256_from_pieces, i256_into_pieces, u256_from_pieces, u256_into_pieces},
+    ConversionError, Env, I128Small, I256Small, I64Small, RawVal, U128Small, U256Small, U64Small,
+    U64Val, I256, U256,
+};
 use core::fmt::Debug;
+use stellar_xdr::int128_helpers;
 
 #[cfg(feature = "std")]
 use crate::{
     num, object::ScValObjRef, Object, RawValConvertible, ScValObject, Status, SymbolSmall, Tag,
-    I256, U256,
 };
 #[cfg(feature = "std")]
-use stellar_xdr::{Duration, Int128Parts, ScVal, TimePoint, Uint256};
+use stellar_xdr::{
+    Duration, Int128Parts, Int256Parts, ScVal, TimePoint, UInt128Parts, UInt256Parts,
+};
 
 pub trait TryIntoVal<E: Env, V> {
     type Error: Debug;
@@ -141,10 +147,9 @@ impl<E: Env> TryFromVal<E, RawVal> for i128 {
             Ok(so.into())
         } else {
             let obj = v.try_into()?;
-            let lo = env.obj_to_i128_lo64(obj).map_err(|_| ConversionError)?;
             let hi = env.obj_to_i128_hi64(obj).map_err(|_| ConversionError)?;
-            let u: u128 = (lo as u128) | ((hi as u128) << 64);
-            Ok(u as i128)
+            let lo = env.obj_to_i128_lo64(obj).map_err(|_| ConversionError)?;
+            Ok(int128_helpers::i128_from_pieces(hi, lo))
         }
     }
 }
@@ -157,7 +162,7 @@ impl<E: Env> TryFromVal<E, i128> for RawVal {
             Ok(so.into())
         } else {
             Ok(env
-                .obj_from_i128_pieces(v as u64, (v as u128 >> 64) as u64)
+                .obj_from_i128_pieces(int128_helpers::i128_hi(v), int128_helpers::i128_lo(v))
                 .map_err(|_| ConversionError)?
                 .into())
         }
@@ -175,10 +180,9 @@ impl<E: Env> TryFromVal<E, RawVal> for u128 {
             Ok(so.into())
         } else {
             let obj = v.try_into()?;
-            let lo = env.obj_to_u128_lo64(obj).map_err(|_| ConversionError)?;
             let hi = env.obj_to_u128_hi64(obj).map_err(|_| ConversionError)?;
-            let u: u128 = (lo as u128) | ((hi as u128) << 64);
-            Ok(u)
+            let lo = env.obj_to_u128_lo64(obj).map_err(|_| ConversionError)?;
+            Ok(int128_helpers::u128_from_pieces(hi, lo))
         }
     }
 }
@@ -191,14 +195,82 @@ impl<E: Env> TryFromVal<E, u128> for RawVal {
             Ok(so.into())
         } else {
             Ok(env
-                .obj_from_u128_pieces(v as u64, (v >> 64) as u64)
+                .obj_from_u128_pieces(int128_helpers::u128_hi(v), int128_helpers::u128_lo(v))
+                .map_err(|_| ConversionError)?
+                .into())
+        }
+    }
+}
+
+// i256 conversions
+impl<E: Env> TryFromVal<E, RawVal> for I256 {
+    type Error = ConversionError;
+
+    fn try_from_val(env: &E, v: &RawVal) -> Result<Self, Self::Error> {
+        let v = *v;
+        if let Ok(so) = I256Small::try_from(v) {
+            Ok(so.into())
+        } else {
+            let obj = v.try_into()?;
+            let hi_hi = env.obj_to_i256_hi_hi(obj).map_err(|_| ConversionError)?;
+            let hi_lo = env.obj_to_i256_hi_lo(obj).map_err(|_| ConversionError)?;
+            let lo_hi = env.obj_to_i256_lo_hi(obj).map_err(|_| ConversionError)?;
+            let lo_lo = env.obj_to_i256_lo_lo(obj).map_err(|_| ConversionError)?;
+            Ok(i256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
+        }
+    }
+}
+impl<E: Env> TryFromVal<E, I256> for RawVal {
+    type Error = ConversionError;
+
+    fn try_from_val(env: &E, v: &I256) -> Result<Self, Self::Error> {
+        let v = *v;
+        if let Ok(so) = I256Small::try_from(v) {
+            Ok(so.into())
+        } else {
+            let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(v);
+            Ok(env
+                .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
                 .map_err(|_| ConversionError)?
                 .into())
         }
     }
 }
 
-// TODO: need some {iu}256 conversions, once we have host functions.
+// u256 conversions
+impl<E: Env> TryFromVal<E, RawVal> for U256 {
+    type Error = ConversionError;
+
+    fn try_from_val(env: &E, v: &RawVal) -> Result<Self, Self::Error> {
+        let v = *v;
+        if let Ok(so) = U256Small::try_from(v) {
+            Ok(so.into())
+        } else {
+            let obj = v.try_into()?;
+            let hi_hi = env.obj_to_u256_hi_hi(obj).map_err(|_| ConversionError)?;
+            let hi_lo = env.obj_to_u256_hi_lo(obj).map_err(|_| ConversionError)?;
+            let lo_hi = env.obj_to_u256_lo_hi(obj).map_err(|_| ConversionError)?;
+            let lo_lo = env.obj_to_u256_lo_lo(obj).map_err(|_| ConversionError)?;
+            Ok(u256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
+        }
+    }
+}
+impl<E: Env> TryFromVal<E, U256> for RawVal {
+    type Error = ConversionError;
+
+    fn try_from_val(env: &E, v: &U256) -> Result<Self, Self::Error> {
+        let v = *v;
+        if let Ok(so) = U256Small::try_from(v) {
+            Ok(so.into())
+        } else {
+            let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_into_pieces(v);
+            Ok(env
+                .obj_from_u256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
+                .map_err(|_| ConversionError)?
+                .into())
+        }
+    }
+}
 
 // ScVal conversions (that require Object conversions)
 
@@ -232,24 +304,32 @@ where
             Tag::I64Small => Ok(ScVal::I64(val.get_signed_body())),
             Tag::TimepointSmall => Ok(ScVal::Timepoint(TimePoint(val.get_body()))),
             Tag::DurationSmall => Ok(ScVal::Duration(Duration(val.get_body()))),
-            Tag::U128Small => Ok(ScVal::U128(Int128Parts {
+            Tag::U128Small => Ok(ScVal::U128(UInt128Parts {
                 hi: 0,
                 lo: val.get_body(),
             })),
             Tag::I128Small => {
                 let body = val.get_signed_body() as i128;
                 Ok(ScVal::I128(Int128Parts {
-                    hi: (body >> 64) as u64,
+                    hi: (body >> 64) as i64,
                     lo: body as u64,
                 }))
             }
-            Tag::U256Small => {
-                let val = U256::new(val.get_body() as u128);
-                Ok(ScVal::U256(Uint256(val.to_be_bytes())))
-            }
+            Tag::U256Small => Ok(ScVal::U256(UInt256Parts {
+                hi_hi: 0,
+                hi_lo: 0,
+                lo_hi: 0,
+                lo_lo: val.get_body(),
+            })),
             Tag::I256Small => {
-                let val = I256::new(val.get_signed_body() as i128);
-                Ok(ScVal::I256(Uint256(val.to_be_bytes())))
+                let body = val.get_signed_body() as i128;
+                let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(I256::from(body));
+                Ok(ScVal::I256(Int256Parts {
+                    hi_hi,
+                    hi_lo,
+                    lo_hi,
+                    lo_lo,
+                }))
             }
             Tag::SymbolSmall => {
                 let sym: SymbolSmall =
@@ -330,14 +410,12 @@ where
                 unsafe { RawVal::from_body_and_tag((i as i64) as u64, Tag::I128Small) }
             }
             ScVal::U256(u) => {
-                let u: U256 = U256::from_be_bytes(u.0.clone());
-                assert!(num::is_small_u256(&u));
-                unsafe { RawVal::from_body_and_tag(u.as_u64(), Tag::U256Small) }
+                assert!(num::is_small_u256_parts(u));
+                unsafe { RawVal::from_body_and_tag(u.lo_lo, Tag::U256Small) }
             }
             ScVal::I256(i) => {
-                let i: I256 = I256::from_be_bytes(i.0.clone());
-                assert!(num::is_small_i256(&i));
-                unsafe { RawVal::from_body_and_tag(i.as_i64() as u64, Tag::I256Small) }
+                assert!(num::is_small_i256_parts(i));
+                unsafe { RawVal::from_body_and_tag(i.lo_lo as u64, Tag::I256Small) }
             }
             ScVal::Symbol(bytes) => {
                 let ss = match std::str::from_utf8(bytes.as_slice()) {
diff --git a/soroban-env-common/src/meta.rs b/soroban-env-common/src/meta.rs
index 2a382ed8..883abb4d 100644
--- a/soroban-env-common/src/meta.rs
+++ b/soroban-env-common/src/meta.rs
@@ -58,5 +58,5 @@
 pub const ENV_META_V0_SECTION_NAME: &'static str = "contractenvmetav0";
 
 soroban_env_macros::generate_env_meta_consts!(
-    interface_version: 33,
+    interface_version: 34,
 );
diff --git a/soroban-env-common/src/num.rs b/soroban-env-common/src/num.rs
index 8ec809d1..f159f4fe 100644
--- a/soroban-env-common/src/num.rs
+++ b/soroban-env-common/src/num.rs
@@ -7,7 +7,7 @@ use crate::{
     raw_val::TAG_BITS, Compare, ConversionError, Env, RawVal, Tag,
 };
 pub use ethnum::{AsI256, AsU256, I256, U256};
-use stellar_xdr::{ScVal, Uint256};
+use stellar_xdr::{Int256Parts, ScVal, UInt256Parts};
 
 declare_tag_based_wrapper!(U32Val);
 declare_tag_based_wrapper!(I32Val);
@@ -216,7 +216,13 @@ impl TryFrom<U256Small> for ScVal {
     type Error = ConversionError;
     fn try_from(value: U256Small) -> Result<Self, Self::Error> {
         let val = U256::new(value.as_raw().get_body() as u128);
-        Ok(ScVal::U256(Uint256(val.to_be_bytes())))
+        let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_into_pieces(val);
+        Ok(ScVal::U256(UInt256Parts {
+            hi_hi,
+            hi_lo,
+            lo_hi,
+            lo_lo,
+        }))
     }
 }
 
@@ -231,7 +237,13 @@ impl TryFrom<I256Small> for ScVal {
     type Error = ConversionError;
     fn try_from(value: I256Small) -> Result<Self, Self::Error> {
         let val = I256::new(value.as_raw().get_signed_body() as i128);
-        Ok(ScVal::I256(Uint256(val.to_be_bytes())))
+        let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(val);
+        Ok(ScVal::I256(Int256Parts {
+            hi_hi,
+            hi_lo,
+            lo_hi,
+            lo_lo,
+        }))
     }
 }
 
@@ -270,6 +282,41 @@ pub fn is_small_i256(i: &I256) -> bool {
     is_small_i64(word) && *i == I256::from(word)
 }
 
+pub fn is_small_u256_parts(u: &UInt256Parts) -> bool {
+    u.hi_hi == 0 && u.hi_lo == 0 && u.lo_hi == 0 && is_small_u64(u.lo_lo)
+}
+
+pub fn is_small_i256_parts(i: &Int256Parts) -> bool {
+    let i = i256_from_pieces(i.hi_hi, i.hi_lo, i.lo_hi, i.lo_lo);
+    is_small_i256(&i)
+}
+
+pub fn u256_from_pieces(hi_hi: u64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> U256 {
+    let high = (u128::from(hi_hi)) << 64 | u128::from(hi_lo);
+    let low = (u128::from(lo_hi)) << 64 | u128::from(lo_lo);
+    U256::from_words(high, low)
+}
+
+pub fn u256_into_pieces(u: U256) -> (u64, u64, u64, u64) {
+    let (high, low) = u.into_words();
+    let (hi_hi, hi_lo) = ((high >> 64) as u64, high as u64);
+    let (lo_hi, lo_lo) = ((low >> 64) as u64, low as u64);
+    (hi_hi, hi_lo, lo_hi, lo_lo)
+}
+
+pub fn i256_from_pieces(hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> I256 {
+    let high = ((u128::from(hi_hi as u64) << 64) | u128::from(hi_lo)) as i128;
+    let low = ((u128::from(lo_hi) << 64) | u128::from(lo_lo)) as i128;
+    I256::from_words(high, low)
+}
+
+pub fn i256_into_pieces(i: I256) -> (i64, u64, u64, u64) {
+    let (high, low) = i.into_words();
+    let (hi_hi, hi_lo) = ((high >> 64) as i64, high as u64);
+    let (lo_hi, lo_lo) = ((low >> 64) as u64, low as u64);
+    (hi_hi, hi_lo, lo_hi, lo_lo)
+}
+
 pub const MIN_SMALL_U64: u64 = 0;
 pub const MAX_SMALL_U64: u64 = 0x00ff_ffff_ffff_ffff_u64;
 
diff --git a/soroban-env-common/src/object.rs b/soroban-env-common/src/object.rs
index 237fea70..36104182 100644
--- a/soroban-env-common/src/object.rs
+++ b/soroban-env-common/src/object.rs
@@ -3,7 +3,6 @@ use crate::{
     RawValConvertible, Tag, TryFromVal,
 };
 use core::{cmp::Ordering, fmt::Debug};
-use ethnum::{I256, U256};
 use stellar_xdr::{Duration, ScVal, TimePoint};
 
 /// Wrapper for a [RawVal] that is tagged with one of the object types,
@@ -175,17 +174,15 @@ impl<'a> ScValObjRef<'a> {
                     Some(ScValObjRef(value))
                 }
             }
-            ScVal::U256(bytes) => {
-                let u = U256::from_be_bytes(bytes.0.clone());
-                if num::is_small_u256(&u) {
+            ScVal::U256(u) => {
+                if num::is_small_u256_parts(u) {
                     None
                 } else {
                     Some(ScValObjRef(value))
                 }
             }
-            ScVal::I256(bytes) => {
-                let i = I256::from_be_bytes(bytes.0.clone());
-                if num::is_small_i256(&i) {
+            ScVal::I256(i) => {
+                if num::is_small_i256_parts(i) {
                     None
                 } else {
                     Some(ScValObjRef(value))
diff --git a/soroban-env-common/src/unimplemented_env.rs b/soroban-env-common/src/unimplemented_env.rs
index f496e61e..41f2e9d8 100644
--- a/soroban-env-common/src/unimplemented_env.rs
+++ b/soroban-env-common/src/unimplemented_env.rs
@@ -1,7 +1,8 @@
 use super::{call_macro_with_all_host_functions, Env, EnvBase, Symbol};
 use super::{
-    AddressObject, Bool, BytesObject, I128Object, I64Object, MapObject, Object, RawVal, Status,
-    StringObject, SymbolObject, U128Object, U32Val, U64Object, U64Val, VecObject, Void,
+    AddressObject, Bool, BytesObject, I128Object, I256Object, I64Object, MapObject, Object, RawVal,
+    Status, StringObject, SymbolObject, U128Object, U256Object, U32Val, U64Object, U64Val,
+    VecObject, Void,
 };
 use core::{any, convert::Infallible};
 
diff --git a/soroban-env-common/src/vmcaller_env.rs b/soroban-env-common/src/vmcaller_env.rs
index 7c7389c3..bc6581e8 100644
--- a/soroban-env-common/src/vmcaller_env.rs
+++ b/soroban-env-common/src/vmcaller_env.rs
@@ -2,8 +2,9 @@
 use crate::xdr::ScHostContextErrorCode;
 
 use super::{
-    AddressObject, Bool, BytesObject, I128Object, I64Object, MapObject, Object, RawVal, Status,
-    StringObject, SymbolObject, U128Object, U32Val, U64Object, U64Val, VecObject, Void,
+    AddressObject, Bool, BytesObject, I128Object, I256Object, I64Object, MapObject, Object, RawVal,
+    Status, StringObject, SymbolObject, U128Object, U256Object, U32Val, U64Object, U64Val,
+    VecObject, Void,
 };
 use crate::call_macro_with_all_host_functions;
 use crate::{EnvBase, Symbol};
diff --git a/soroban-env-guest/src/guest.rs b/soroban-env-guest/src/guest.rs
index ccf50210..5c60530e 100644
--- a/soroban-env-guest/src/guest.rs
+++ b/soroban-env-guest/src/guest.rs
@@ -6,8 +6,9 @@ use core::convert::Infallible;
 use soroban_env_common::call_macro_with_all_host_functions;
 
 use super::{
-    AddressObject, Bool, BytesObject, I128Object, I64Object, MapObject, Object, RawVal, Status,
-    StringObject, SymbolObject, U128Object, U32Val, U64Object, U64Val, VecObject, Void,
+    AddressObject, Bool, BytesObject, I128Object, I256Object, I64Object, MapObject, Object, RawVal,
+    Status, StringObject, SymbolObject, U128Object, U256Object, U32Val, U64Object, U64Val,
+    VecObject, Void,
 };
 use super::{Env, EnvBase, Symbol};
 #[cfg(target_family = "wasm")]
@@ -513,7 +514,7 @@ macro_rules! generate_extern_modules {
                 #[allow(unused_imports)]
                 use crate::{RawVal,Object,Symbol,Status,MapObject,VecObject,BytesObject};
                 #[allow(unused_imports)]
-                use crate::{U64Val,U64Object,I64Val,I64Object,U128Object,I128Object,U32Val};
+                use crate::{I128Object, I256Object, I64Object, I64Val, U128Object, U256Object, U32Val, U64Object, U64Val};
                 #[allow(unused_imports)]
                 use crate::{Void,AddressObject,SymbolObject,StringObject,Bool};
                 #[link(wasm_import_module = $mod_str)]
diff --git a/soroban-env-host/src/host.rs b/soroban-env-host/src/host.rs
index cb83438f..4cc340b6 100644
--- a/soroban-env-host/src/host.rs
+++ b/soroban-env-host/src/host.rs
@@ -7,17 +7,20 @@ use core::fmt::Debug;
 use std::rc::Rc;
 
 use soroban_env_common::{
+    num::{i256_from_pieces, i256_into_pieces, u256_from_pieces, u256_into_pieces},
     xdr::{
-        AccountId, Asset, ContractCodeEntry, ContractDataEntry, ContractEventType, ContractId,
-        CreateContractArgs, ExtensionPoint, Hash, HashIdPreimage, HostFunction, HostFunctionType,
-        InstallContractCodeArgs, Int128Parts, LedgerEntryData, LedgerKey, LedgerKeyContractCode,
-        PublicKey, ScAddress, ScBytes, ScContractExecutable, ScHostContextErrorCode,
-        ScHostFnErrorCode, ScHostObjErrorCode, ScHostStorageErrorCode, ScHostValErrorCode, ScMap,
-        ScMapEntry, ScStatusType, ScString, ScSymbol, ScUnknownErrorCode, ScVal, ScVec, Uint256,
+        int128_helpers, AccountId, Asset, ContractCodeEntry, ContractDataEntry, ContractEventType,
+        ContractId, CreateContractArgs, ExtensionPoint, Hash, HashIdPreimage, HostFunction,
+        HostFunctionType, InstallContractCodeArgs, Int128Parts, Int256Parts, LedgerEntryData,
+        LedgerKey, LedgerKeyContractCode, PublicKey, ScAddress, ScBytes, ScContractExecutable,
+        ScHostContextErrorCode, ScHostFnErrorCode, ScHostObjErrorCode, ScHostStorageErrorCode,
+        ScHostValErrorCode, ScMap, ScMapEntry, ScStatusType, ScString, ScSymbol,
+        ScUnknownErrorCode, ScVal, ScVec, UInt128Parts, UInt256Parts,
     },
-    AddressObject, Bool, BytesObject, Convert, I128Object, I64Object, MapObject, ScValObjRef,
-    ScValObject, Status, StringObject, SymbolObject, SymbolSmall, TryFromVal, TryIntoVal,
-    U128Object, U32Val, U64Object, U64Val, VecObject, VmCaller, VmCallerEnv, Void, I256, U256,
+    AddressObject, Bool, BytesObject, Convert, I128Object, I256Object, I64Object, MapObject,
+    ScValObjRef, ScValObject, Status, StringObject, SymbolObject, SymbolSmall, TryFromVal,
+    TryIntoVal, U128Object, U256Object, U32Val, U64Object, U64Val, VecObject, VmCaller,
+    VmCallerEnv, Void, I256, U256,
 };
 
 use crate::auth::{AuthorizationManager, AuthorizationManagerSnapshot, RecordedAuthPayload};
@@ -828,19 +831,32 @@ impl Host {
                         HostObject::Duration(d) => {
                             ScVal::Duration(d.metered_clone(self.as_budget())?)
                         }
-                        HostObject::U128(u) => ScVal::U128(Int128Parts {
-                            lo: *u as u64,
-                            hi: (*u >> 64) as u64,
+                        HostObject::U128(u) => ScVal::U128(UInt128Parts {
+                            hi: int128_helpers::u128_hi(*u),
+                            lo: int128_helpers::u128_lo(*u),
                         }),
-                        HostObject::I128(u) => {
-                            let u = *u as u128;
-                            ScVal::I128(Int128Parts {
-                                lo: u as u64,
-                                hi: (u >> 64) as u64,
+                        HostObject::I128(i) => ScVal::I128(Int128Parts {
+                            hi: int128_helpers::i128_hi(*i),
+                            lo: int128_helpers::i128_lo(*i),
+                        }),
+                        HostObject::U256(u) => {
+                            let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_into_pieces(*u);
+                            ScVal::U256(UInt256Parts {
+                                hi_hi,
+                                hi_lo,
+                                lo_hi,
+                                lo_lo,
+                            })
+                        }
+                        HostObject::I256(i) => {
+                            let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(*i);
+                            ScVal::I256(Int256Parts {
+                                hi_hi,
+                                hi_lo,
+                                lo_hi,
+                                lo_lo,
                             })
                         }
-                        HostObject::U256(u) => ScVal::U256(Uint256(u.to_be_bytes())),
-                        HostObject::I256(i) => ScVal::I256(Uint256(i.to_be_bytes())),
                         HostObject::Bytes(b) => ScVal::Bytes(b.metered_clone(self.as_budget())?),
                         HostObject::String(s) => ScVal::String(s.metered_clone(self.as_budget())?),
                         HostObject::Symbol(s) => ScVal::Symbol(s.metered_clone(self.as_budget())?),
@@ -899,16 +915,16 @@ impl Host {
                 .add_host_object(d.metered_clone(self.as_budget())?)?
                 .into()),
             ScVal::U128(u) => Ok(self
-                .add_host_object(u.lo as u128 | ((u.hi as u128) << 64))?
+                .add_host_object(int128_helpers::u128_from_pieces(u.hi, u.lo))?
                 .into()),
             ScVal::I128(i) => Ok(self
-                .add_host_object((i.lo as u128 | ((i.hi as u128) << 64)) as i128)?
+                .add_host_object(int128_helpers::i128_from_pieces(i.hi, i.lo))?
                 .into()),
             ScVal::U256(u) => Ok(self
-                .add_host_object(U256::from_be_bytes(u.0.metered_clone(self.as_budget())?))?
+                .add_host_object(u256_from_pieces(u.hi_hi, u.hi_lo, u.lo_hi, u.lo_lo))?
                 .into()),
             ScVal::I256(i) => Ok(self
-                .add_host_object(I256::from_be_bytes(i.0.metered_clone(self.as_budget())?))?
+                .add_host_object(i256_from_pieces(i.hi_hi, i.hi_lo, i.lo_hi, i.lo_lo))?
                 .into()),
             ScVal::Bytes(b) => Ok(self
                 .add_host_object(b.metered_clone(self.as_budget())?)?
@@ -1864,11 +1880,10 @@ impl VmCallerEnv for Host {
     fn obj_from_u128_pieces(
         &self,
         vmcaller: &mut VmCaller<Self::VmUserState>,
-        lo: u64,
         hi: u64,
+        lo: u64,
     ) -> Result<U128Object, Self::Error> {
-        let u: u128 = ((hi as u128) << 64) | lo as u128;
-        self.add_host_object(u)
+        self.add_host_object(int128_helpers::u128_from_pieces(hi, lo))
     }
 
     fn obj_to_u128_lo64(
@@ -1876,7 +1891,7 @@ impl VmCallerEnv for Host {
         vmcaller: &mut VmCaller<Self::VmUserState>,
         obj: U128Object,
     ) -> Result<u64, Self::Error> {
-        self.visit_obj(obj, move |u: &u128| Ok(*u as u64))
+        self.visit_obj(obj, move |u: &u128| Ok(int128_helpers::u128_lo(*u)))
     }
 
     fn obj_to_u128_hi64(
@@ -1884,19 +1899,16 @@ impl VmCallerEnv for Host {
         vmcaller: &mut VmCaller<Self::VmUserState>,
         obj: U128Object,
     ) -> Result<u64, Self::Error> {
-        self.visit_obj(obj, move |u: &u128| Ok((*u >> 64) as u64))
+        self.visit_obj(obj, move |u: &u128| Ok(int128_helpers::u128_hi(*u)))
     }
 
     fn obj_from_i128_pieces(
         &self,
         vmcaller: &mut VmCaller<Self::VmUserState>,
+        hi: i64,
         lo: u64,
-        hi: u64,
     ) -> Result<I128Object, Self::Error> {
-        // NB: always do assembly/disassembly as unsigned, to avoid sign extension.
-        let u: u128 = ((hi as u128) << 64) | lo as u128;
-        let i: i128 = u as i128;
-        self.add_host_object(i)
+        self.add_host_object(int128_helpers::i128_from_pieces(hi, lo))
     }
 
     fn obj_to_i128_lo64(
@@ -1904,15 +1916,125 @@ impl VmCallerEnv for Host {
         vmcaller: &mut VmCaller<Self::VmUserState>,
         obj: I128Object,
     ) -> Result<u64, Self::Error> {
-        self.visit_obj(obj, move |u: &i128| Ok((*u as u128) as u64))
+        self.visit_obj(obj, move |i: &i128| Ok(int128_helpers::i128_lo(*i)))
     }
 
     fn obj_to_i128_hi64(
         &self,
         vmcaller: &mut VmCaller<Self::VmUserState>,
         obj: I128Object,
-    ) -> Result<u64, Self::Error> {
-        self.visit_obj(obj, move |u: &i128| Ok(((*u as u128) >> 64) as u64))
+    ) -> Result<i64, Self::Error> {
+        self.visit_obj(obj, move |i: &i128| Ok(int128_helpers::i128_hi(*i)))
+    }
+
+    fn obj_from_u256_pieces(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        hi_hi: u64,
+        hi_lo: u64,
+        lo_hi: u64,
+        lo_lo: u64,
+    ) -> Result<U256Object, Self::Error> {
+        self.add_host_object(u256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
+    }
+
+    fn obj_to_u256_hi_hi(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: U256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |u: &U256| {
+            let (hi_hi, _, _, _) = u256_into_pieces(*u);
+            Ok(hi_hi)
+        })
+    }
+
+    fn obj_to_u256_hi_lo(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: U256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |u: &U256| {
+            let (_, hi_lo, _, _) = u256_into_pieces(*u);
+            Ok(hi_lo)
+        })
+    }
+
+    fn obj_to_u256_lo_hi(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: U256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |u: &U256| {
+            let (_, _, lo_hi, _) = u256_into_pieces(*u);
+            Ok(lo_hi)
+        })
+    }
+
+    fn obj_to_u256_lo_lo(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: U256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |u: &U256| {
+            let (_, _, _, lo_lo) = u256_into_pieces(*u);
+            Ok(lo_lo)
+        })
+    }
+
+    fn obj_from_i256_pieces(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        hi_hi: i64,
+        hi_lo: u64,
+        lo_hi: u64,
+        lo_lo: u64,
+    ) -> Result<I256Object, Self::Error> {
+        self.add_host_object(i256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
+    }
+
+    fn obj_to_i256_hi_hi(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: I256Object,
+    ) -> Result<i64, HostError> {
+        self.visit_obj(obj, move |i: &I256| {
+            let (hi_hi, _, _, _) = i256_into_pieces(*i);
+            Ok(hi_hi)
+        })
+    }
+
+    fn obj_to_i256_hi_lo(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: I256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |i: &I256| {
+            let (_, hi_lo, _, _) = i256_into_pieces(*i);
+            Ok(hi_lo)
+        })
+    }
+
+    fn obj_to_i256_lo_hi(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: I256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |i: &I256| {
+            let (_, _, lo_hi, _) = i256_into_pieces(*i);
+            Ok(lo_hi)
+        })
+    }
+
+    fn obj_to_i256_lo_lo(
+        &self,
+        vmcaller: &mut VmCaller<Self::VmUserState>,
+        obj: I256Object,
+    ) -> Result<u64, HostError> {
+        self.visit_obj(obj, move |i: &I256| {
+            let (_, _, _, lo_lo) = i256_into_pieces(*i);
+            Ok(lo_lo)
+        })
     }
 
     fn map_new(&self, _vmcaller: &mut VmCaller<Host>) -> Result<MapObject, HostError> {
diff --git a/soroban-env-host/src/host/comparison.rs b/soroban-env-host/src/host/comparison.rs
index 146f3fd9..a2ea6d82 100644
--- a/soroban-env-host/src/host/comparison.rs
+++ b/soroban-env-host/src/host/comparison.rs
@@ -503,16 +503,26 @@ mod tests {
             ScVal::I64(i64::MAX),
             ScVal::Timepoint(xdr::TimePoint(u64::MAX)),
             ScVal::Duration(xdr::Duration(u64::MAX)),
-            ScVal::U128(xdr::Int128Parts {
-                lo: u64::MAX,
+            ScVal::U128(xdr::UInt128Parts {
                 hi: u64::MAX,
+                lo: u64::MAX,
             }),
             ScVal::I128(xdr::Int128Parts {
+                hi: i64::MIN,
                 lo: u64::MAX,
-                hi: 0,
             }),
-            ScVal::U256(xdr::Uint256([0xff; 32])),
-            ScVal::I256(xdr::Uint256([0xf0; 32])),
+            ScVal::U256(xdr::UInt256Parts {
+                hi_hi: u64::MAX,
+                hi_lo: u64::MAX,
+                lo_hi: u64::MAX,
+                lo_lo: u64::MAX,
+            }),
+            ScVal::I256(xdr::Int256Parts {
+                hi_hi: i64::MIN,
+                hi_lo: u64::MAX,
+                lo_hi: u64::MAX,
+                lo_lo: u64::MAX,
+            }),
             ScVal::Bytes(xdr::ScBytes::try_from(vec![]).unwrap()),
             ScVal::String(xdr::ScString::try_from(vec![]).unwrap()),
             ScVal::Symbol(xdr::ScSymbol::try_from("big-symbol").unwrap()),
diff --git a/soroban-env-host/src/vm/dispatch.rs b/soroban-env-host/src/vm/dispatch.rs
index 0d6176f5..1d433280 100644
--- a/soroban-env-host/src/vm/dispatch.rs
+++ b/soroban-env-host/src/vm/dispatch.rs
@@ -1,7 +1,7 @@
 use crate::{budget::CostType, Host, HostError, VmCaller, VmCallerEnv};
 use crate::{
-    AddressObject, BytesObject, I128Object, I64Object, MapObject, RawVal, Status, StringObject,
-    Symbol, SymbolObject, U128Object, U32Val, U64Object, VecObject,
+    AddressObject, BytesObject, I128Object, I256Object, I64Object, MapObject, RawVal, Status,
+    StringObject, Symbol, SymbolObject, U128Object, U256Object, U32Val, U64Object, VecObject,
 };
 use soroban_env_common::call_macro_with_all_host_functions;
 use wasmi::core::{FromValue, Trap, TrapCode::UnexpectedSignature, Value};


Test patch:
diff --git a/soroban-env-host/src/test/num.rs b/soroban-env-host/src/test/num.rs
index 4fe68b1f..51e365fd 100644
--- a/soroban-env-host/src/test/num.rs
+++ b/soroban-env-host/src/test/num.rs
@@ -1,71 +1,62 @@
-use soroban_env_common::{
-    xdr::{ScVal, Uint256},
-    TryFromVal, TryIntoVal, I256,
-};
+use soroban_env_common::{num::*, xdr::ScVal, Compare, TryFromVal, TryIntoVal, I256};
 
-use crate::{Host, HostError, RawVal};
+use crate::{budget::AsBudget, Host, RawVal};
 use core::fmt::Debug;
+use std::cmp::Ordering;
 
-#[test]
-fn test_i64_roundtrip() -> Result<(), HostError> {
-    let host = Host::default();
-    let i: i64 = -1;
-    let rv: RawVal = i.try_into_val(&host)?;
-    let iv: i64 = rv.try_into_val(&host)?;
-    assert_eq!(i, iv);
-    Ok(())
+fn check_roundtrip_ok<
+    T: Eq + Debug + Copy + TryIntoVal<Host, RawVal> + TryFromVal<Host, RawVal>,
+>(
+    h: &Host,
+    input: T,
+    expect_object: bool,
+) {
+    let raw1: RawVal = input.try_into_val(h).unwrap();
+    let sc1: ScVal = raw1.try_into_val(h).unwrap();
+    let raw2: RawVal = sc1.try_into_val(h).unwrap();
+    let output: T = raw2.try_into_val(h).unwrap();
+    assert_eq!(input, output);
+    assert_eq!(h.compare(&raw1, &raw2).unwrap(), Ordering::Equal);
+    if expect_object {
+        assert!(raw1.is_object());
+        assert!(raw2.is_object());
+    } else {
+        assert!(!raw1.is_object());
+        assert!(!raw2.is_object());
+        assert_eq!(raw1.get_payload(), raw2.get_payload());
+    }
 }
 
-#[test]
-fn test_i128_roundtrip() -> Result<(), HostError> {
-    let host = Host::default();
-    let i: i128 = -1;
-    let rv: RawVal = i.try_into_val(&host)?;
-    let iv: i128 = rv.try_into_val(&host)?;
-    assert_eq!(i, iv);
-    Ok(())
-}
+fn check_roundtrip_compare_ok<
+    T: Eq + Debug + Copy + Ord + TryIntoVal<Host, RawVal> + TryFromVal<Host, RawVal>,
+>(
+    h: &Host,
+    input_vec: Vec<T>,
+) {
+    let pairs: Vec<((RawVal, ScVal), &T)> = input_vec
+        .iter()
+        .map(|v| {
+            let raw: RawVal = v.try_into_val(h).unwrap();
+            let scv: ScVal = raw.try_into_val(h).unwrap();
+            (raw, scv)
+        })
+        .zip(input_vec.iter())
+        .collect();
 
-#[test]
-fn test_256_roundtrip() -> Result<(), HostError> {
-    let host = Host::default();
-
-    let i: I256 = I256::new(-1234_i128);
-    let rv = host.add_host_object(i)?.to_raw();
-    let scv_back = host.from_host_val(rv)?;
-
-    let scv_ref = ScVal::I256(Uint256(i.to_be_bytes()));
-    assert_eq!(scv_back, scv_ref);
-
-    Ok(())
+    for first in &pairs {
+        for second in &pairs {
+            let ord = first.1.cmp(second.1);
+            assert_eq!(h.compare(&first.0 .0, &second.0 .0).unwrap(), ord);
+            assert_eq!(
+                h.as_budget().compare(&first.0 .1, &second.0 .1).unwrap(),
+                ord
+            );
+        }
+    }
 }
 
 #[test]
 fn test_num_scval_roundtrips() {
-    use soroban_env_common::num::*;
-
-    fn check_roundtrip_ok<
-        T: Eq + Debug + Copy + TryIntoVal<Host, RawVal> + TryFromVal<Host, RawVal>,
-    >(
-        h: &Host,
-        input: T,
-        expect_object: bool,
-    ) {
-        let raw1: RawVal = input.try_into_val(h).unwrap();
-        let sc1: ScVal = raw1.try_into_val(h).unwrap();
-        let raw2: RawVal = sc1.try_into_val(h).unwrap();
-        let output: T = raw2.try_into_val(h).unwrap();
-        assert_eq!(input, output);
-        if expect_object {
-            assert!(raw1.is_object());
-            assert!(raw2.is_object());
-        } else {
-            assert!(!raw1.is_object());
-            assert!(!raw2.is_object());
-            assert_eq!(raw1.get_payload(), raw2.get_payload());
-        }
-    }
-
     let host = Host::default();
 
     check_roundtrip_ok::<i64>(&host, 0_i64, false);
@@ -106,5 +97,103 @@ fn test_num_scval_roundtrips() {
     check_roundtrip_ok::<u128>(&host, MAX_SMALL_U128 + 1, true);
     check_roundtrip_ok::<u128>(&host, u128::MAX, true);
 
-    // TODO: add roundtrips for {iu}256 when conversions exist.
+    check_roundtrip_ok::<U256>(&host, U256::from(0_u128), false);
+    check_roundtrip_ok::<U256>(&host, U256::from(1_u128), false);
+    check_roundtrip_ok::<U256>(&host, U256::from(12345_u128), false);
+    check_roundtrip_ok::<U256>(&host, MAX_SMALL_U256, false);
+    check_roundtrip_ok::<U256>(&host, MAX_SMALL_U256 + 1, true);
+    check_roundtrip_ok::<U256>(&host, U256::MAX, true);
+
+    check_roundtrip_ok::<I256>(&host, I256::from(0_i128), false);
+    check_roundtrip_ok::<I256>(&host, I256::from(1_i128), false);
+    check_roundtrip_ok::<I256>(&host, I256::from(-1_i128), false);
+    check_roundtrip_ok::<I256>(&host, I256::from(12345_i128), false);
+    check_roundtrip_ok::<I256>(&host, I256::from(-12345_i128), false);
+    check_roundtrip_ok::<I256>(&host, MIN_SMALL_I256, false);
+    check_roundtrip_ok::<I256>(&host, MAX_SMALL_I256, false);
+    check_roundtrip_ok::<I256>(&host, MIN_SMALL_I256 - 1, true);
+    check_roundtrip_ok::<I256>(&host, MAX_SMALL_I256 + 1, true);
+    check_roundtrip_ok::<I256>(&host, I256::MIN, true);
+    check_roundtrip_ok::<I256>(&host, I256::MAX, true);
+
+    let pos = 0x00ab_cdef_9876_5432u64; // some positive int64
+    let neg = 0xfedc_ba98_7654_3210u64; // some negative int64
+    let v = vec![pos, neg];
+    for hi_hi in &v {
+        for hi_lo in &v {
+            for lo_hi in &v {
+                for lo_lo in &v {
+                    let i = i256_from_pieces(*hi_hi as i64, *hi_lo, *lo_hi, *lo_lo);
+                    check_roundtrip_ok::<I256>(&host, i, true)
+                }
+            }
+        }
+    }
+}
+
+#[test]
+fn test_num_rawval_scval_roundtrip_ordering() {
+    let host = Host::default();
+    let input_vec = vec![
+        0_i128,
+        1_i128,
+        -1_i128,
+        12345_i128,
+        -12345_i128,
+        MIN_SMALL_I128,
+        MAX_SMALL_I128,
+        MIN_SMALL_I128 - 1,
+        MAX_SMALL_I128 + 1,
+        i128::MIN,
+        i128::MAX,
+    ];
+    check_roundtrip_compare_ok::<i128>(&host, input_vec);
+
+    let input_vec = vec![
+        0_u128,
+        1_u128,
+        12345_u128,
+        MAX_SMALL_U128,
+        MAX_SMALL_U128 + 1,
+        u128::MAX,
+    ];
+    check_roundtrip_compare_ok::<u128>(&host, input_vec);
+
+    let input_vec = vec![
+        U256::from(0_u128),
+        U256::from(1_u128),
+        U256::from(12345_u128),
+        MAX_SMALL_U256,
+        MAX_SMALL_U256 + 1,
+        U256::MAX,
+    ];
+    check_roundtrip_compare_ok::<U256>(&host, input_vec);
+
+    let mut input_vec = vec![
+        I256::from(0_i128),
+        I256::from(1_i128),
+        I256::from(-1_i128),
+        I256::from(12345_i128),
+        I256::from(-12345_i128),
+        MIN_SMALL_I256,
+        MAX_SMALL_I256,
+        MIN_SMALL_I256 - 1,
+        MAX_SMALL_I256 + 1,
+        I256::MIN,
+        I256::MAX,
+    ];
+
+    let pos = 0x00ab_cdef_9876_5432u64; // some positive int64
+    let neg = 0xfedc_ba98_7654_3210u64; // some negative int64
+    let v = vec![pos, neg];
+    for hi_hi in &v {
+        for hi_lo in &v {
+            for lo_hi in &v {
+                for lo_lo in &v {
+                    input_vec.push(i256_from_pieces(*hi_hi as i64, *hi_lo, *lo_hi, *lo_lo));
+                }
+            }
+        }
+    }
+    check_roundtrip_compare_ok::<I256>(&host, input_vec);
 }
diff --git a/soroban-test-wasms/wasm-workspace/Cargo.lock b/soroban-test-wasms/wasm-workspace/Cargo.lock
index 93b88ae4..92251b7b 100644
--- a/soroban-test-wasms/wasm-workspace/Cargo.lock
+++ b/soroban-test-wasms/wasm-workspace/Cargo.lock
@@ -26,6 +26,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "arbitrary"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
+dependencies = [
+ "derive_arbitrary",
+]
+
 [[package]]
 name = "auth_test_contract"
 version = "0.0.0"
@@ -271,6 +280,17 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "derive_arbitrary"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "digest"
 version = "0.9.0"
@@ -884,7 +904,7 @@ checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
 
 [[package]]
 name = "soroban-auth"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "soroban-env-host",
  "soroban-sdk",
@@ -892,20 +912,21 @@ dependencies = [
 
 [[package]]
 name = "soroban-env-common"
-version = "0.0.14"
+version = "0.0.15"
 dependencies = [
+ "arbitrary",
  "crate-git-revision",
  "ethnum",
  "serde",
  "soroban-env-macros",
  "soroban-wasmi",
  "static_assertions",
- "stellar-xdr",
+ "stellar-xdr 0.0.15 (git+https://github.com/jayz22/rs-stellar-xdr?rev=b04c3c26546335b063e2797175689c45c752612a)",
 ]
 
 [[package]]
 name = "soroban-env-guest"
-version = "0.0.14"
+version = "0.0.15"
 dependencies = [
  "soroban-env-common",
  "static_assertions",
@@ -913,7 +934,7 @@ dependencies = [
 
 [[package]]
 name = "soroban-env-host"
-version = "0.0.14"
+version = "0.0.15"
 dependencies = [
  "backtrace",
  "curve25519-dalek",
@@ -934,21 +955,21 @@ dependencies = [
 
 [[package]]
 name = "soroban-env-macros"
-version = "0.0.14"
+version = "0.0.15"
 dependencies = [
  "itertools",
  "proc-macro2",
  "quote",
  "serde",
  "serde_json",
- "stellar-xdr",
+ "stellar-xdr 0.0.15 (git+https://github.com/jayz22/rs-stellar-xdr?rev=b04c3c26546335b063e2797175689c45c752612a)",
  "syn",
  "thiserror",
 ]
 
 [[package]]
 name = "soroban-ledger-snapshot"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "serde",
  "serde_json",
@@ -958,7 +979,7 @@ dependencies = [
 
 [[package]]
 name = "soroban-native-sdk-macros"
-version = "0.0.14"
+version = "0.0.15"
 dependencies = [
  "itertools",
  "proc-macro2",
@@ -968,7 +989,7 @@ dependencies = [
 
 [[package]]
 name = "soroban-sdk"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "bytes-lit",
  "ed25519-dalek",
@@ -982,7 +1003,7 @@ dependencies = [
 
 [[package]]
 name = "soroban-sdk-macros"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "darling",
  "itertools",
@@ -991,13 +1012,13 @@ dependencies = [
  "sha2 0.10.6",
  "soroban-env-common",
  "soroban-spec",
- "stellar-xdr",
+ "stellar-xdr 0.0.15 (git+https://github.com/stellar/rs-stellar-xdr?rev=bcf6f4c3a9dd32822a20af89880650a421d10e7f)",
  "syn",
 ]
 
 [[package]]
 name = "soroban-spec"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "base64",
  "darling",
@@ -1009,7 +1030,7 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "sha2 0.10.6",
- "stellar-xdr",
+ "stellar-xdr 0.0.15 (git+https://github.com/stellar/rs-stellar-xdr?rev=bcf6f4c3a9dd32822a20af89880650a421d10e7f)",
  "syn",
  "thiserror",
  "wasmparser",
@@ -1060,9 +1081,10 @@ dependencies = [
 
 [[package]]
 name = "stellar-xdr"
-version = "0.0.14"
-source = "git+https://github.com/stellar/rs-stellar-xdr?rev=07aff1190dc3f97b889d31b2bfb77098e7db55ce#07aff1190dc3f97b889d31b2bfb77098e7db55ce"
+version = "0.0.15"
+source = "git+https://github.com/jayz22/rs-stellar-xdr?rev=b04c3c26546335b063e2797175689c45c752612a#b04c3c26546335b063e2797175689c45c752612a"
 dependencies = [
+ "arbitrary",
  "base64",
  "crate-git-revision",
  "hex",
@@ -1070,6 +1092,17 @@ dependencies = [
  "serde_with",
 ]
 
+[[package]]
+name = "stellar-xdr"
+version = "0.0.15"
+source = "git+https://github.com/stellar/rs-stellar-xdr?rev=bcf6f4c3a9dd32822a20af89880650a421d10e7f#bcf6f4c3a9dd32822a20af89880650a421d10e7f"
+dependencies = [
+ "crate-git-revision",
+ "hex",
+ "serde",
+ "serde_with",
+]
+
 [[package]]
 name = "strsim"
 version = "0.10.0"
diff --git a/soroban-test-wasms/wasm-workspace/Cargo.toml b/soroban-test-wasms/wasm-workspace/Cargo.toml
index 003956a1..d20ddcb4 100644
--- a/soroban-test-wasms/wasm-workspace/Cargo.toml
+++ b/soroban-test-wasms/wasm-workspace/Cargo.toml
@@ -49,11 +49,11 @@ soroban-env-guest = { path = "../../soroban-env-guest" }
 soroban-env-host = { path = "../../soroban-env-host" }
 
 [workspace.dependencies.soroban-sdk]
-version = "0.6.0"
+version = "0.7.0"
 git = "https://github.com/stellar/rs-soroban-sdk"
 
 [workspace.dependencies.soroban-auth]
-version = "0.6.0"
+version = "0.7.0"
 git = "https://github.com/stellar/rs-soroban-sdk"
 
 # Always build using the local SDK. Usually the env change is accompanied with
@@ -63,4 +63,4 @@ soroban-sdk = { path = "../../../rs-soroban-sdk/soroban-sdk" }
 soroban-auth = { path = "../../../rs-soroban-sdk/soroban-auth" }
 
 #[patch."https://github.com/stellar/rs-stellar-xdr"]
-#stellar-xdr = { path = "../../../rs-stellar-xdr/" }
\ No newline at end of file
+#stellar-xdr = { path = "../../../rs-stellar-xdr/" }