diff --git a/soroban-spec-rust/src/lib.rs b/soroban-spec-rust/src/lib.rs index 4d59d3688..f7918bac9 100644 --- a/soroban-spec-rust/src/lib.rs +++ b/soroban-spec-rust/src/lib.rs @@ -2,13 +2,14 @@ mod syn_ext; pub mod r#trait; pub mod types; +use std::borrow::Cow; use std::{fs, io}; use proc_macro2::TokenStream; use quote::quote; use sha2::{Digest, Sha256}; use stellar_xdr::curr as stellar_xdr; -use stellar_xdr::ScSpecEntry; +use stellar_xdr::{ScSpecEntry, ScSpecTypeDef, ScSpecTypeUdt, ScSpecUdtUnionCaseV0}; use syn::Error; use soroban_spec::read::{from_wasm, FromWasmError}; @@ -107,6 +108,9 @@ pub fn generate_without_file_with_options( specs: &[ScSpecEntry], opts: &GenerateOptions, ) -> Result { + let specs = apply_error_udt_override(specs); + let specs: &[ScSpecEntry] = &specs; + let mut spec_fns = Vec::new(); let mut spec_structs = Vec::new(); let mut spec_unions = Vec::new(); @@ -161,6 +165,101 @@ pub fn generate_without_file_with_options( }) } +/// The `#[contractimpl]` macro emits any type named `Error` in a contract's +/// function signatures as the built-in `ScSpecTypeDef::Error` in the spec, +/// regardless of whether the contract defined its own error enum named `Error` +/// or used `soroban_sdk::Error` directly. To let clients of contracts that +/// define their own `Error` enum see the user-defined type instead of +/// `soroban_sdk::Error`, this pass rewrites every `ScSpecTypeDef::Error` +/// reference in the spec to `Udt { name: "Error" }` whenever the spec also +/// contains a `UdtErrorEnumV0` named `Error`. +/// +/// This keeps the on-the-wire spec format unchanged (so already-deployed +/// contracts benefit without redeployment) and shifts the resolution to the +/// client generator. +/// +/// Returns a borrowed slice when no rewrite is needed, otherwise a +/// freshly-owned `Vec` with the rewrite applied. +fn apply_error_udt_override(specs: &[ScSpecEntry]) -> Cow<'_, [ScSpecEntry]> { + let has_error_udt = specs.iter().any(|e| { + matches!( + e, + ScSpecEntry::UdtErrorEnumV0(err) if err.name.to_utf8_string_lossy() == "Error" + ) + }); + if has_error_udt { + let mut v = specs.to_vec(); + rewrite_error_to_udt(&mut v); + Cow::Owned(v) + } else { + Cow::Borrowed(specs) + } +} + +/// Rewrites every `ScSpecTypeDef::Error` reference in the given entries to +/// `ScSpecTypeDef::Udt { name: "Error" }`. Called only when the spec contains +/// a user-defined error enum named `Error`, so the UDT reference resolves to +/// that enum during code generation. +fn rewrite_error_to_udt(entries: &mut [ScSpecEntry]) { + fn rewrite_ty(t: &mut ScSpecTypeDef) { + match t { + ScSpecTypeDef::Error => { + *t = ScSpecTypeDef::Udt(ScSpecTypeUdt { + name: "Error".try_into().unwrap(), + }); + } + ScSpecTypeDef::Option(o) => rewrite_ty(&mut o.value_type), + ScSpecTypeDef::Result(r) => { + rewrite_ty(&mut r.ok_type); + rewrite_ty(&mut r.error_type); + } + ScSpecTypeDef::Vec(v) => rewrite_ty(&mut v.element_type), + ScSpecTypeDef::Map(m) => { + rewrite_ty(&mut m.key_type); + rewrite_ty(&mut m.value_type); + } + ScSpecTypeDef::Tuple(tu) => { + for vt in tu.value_types.iter_mut() { + rewrite_ty(vt); + } + } + _ => {} + } + } + for entry in entries.iter_mut() { + match entry { + ScSpecEntry::FunctionV0(f) => { + for input in f.inputs.iter_mut() { + rewrite_ty(&mut input.type_); + } + for output in f.outputs.iter_mut() { + rewrite_ty(output); + } + } + ScSpecEntry::UdtStructV0(s) => { + for field in s.fields.iter_mut() { + rewrite_ty(&mut field.type_); + } + } + ScSpecEntry::UdtUnionV0(u) => { + for case in u.cases.iter_mut() { + if let ScSpecUdtUnionCaseV0::TupleV0(t) = case { + for ty in t.type_.iter_mut() { + rewrite_ty(ty); + } + } + } + } + ScSpecEntry::UdtEnumV0(_) | ScSpecEntry::UdtErrorEnumV0(_) => {} + ScSpecEntry::EventV0(e) => { + for p in e.params.iter_mut() { + rewrite_ty(&mut p.type_); + } + } + } + } +} + /// Implemented by types that can be converted into pretty formatted Strings of /// Rust code. pub trait ToFormattedString { @@ -249,6 +348,273 @@ pub enum UdtEnum2 { A = 10, B = 15, } +"#, + ); + } + + const ADD_U64_WASM: &[u8] = + include_bytes!("../../target/wasm32v1-none/release/test_add_u64.wasm"); + + /// Test that Result types with user-defined error types are generated correctly. + /// This specifically tests that: + /// - An error enum named `Error` generates `Result` (not `Result`) + /// - An error enum named `MyError` generates `Result` + #[test] + fn test_add_u64_result_types() { + let entries = from_wasm(ADD_U64_WASM).unwrap(); + let rust = generate(&entries, "", "") + .unwrap() + .to_formatted_string() + .unwrap(); + assert_eq!( + rust, + r#"pub const WASM: &[u8] = soroban_sdk::contractfile!(file = "", sha256 = ""); +#[soroban_sdk::contractargs(name = "Args")] +#[soroban_sdk::contractclient(name = "Client")] +pub trait Contract { + fn add(env: soroban_sdk::Env, a: u64, b: u64) -> u64; + fn safe_add(env: soroban_sdk::Env, a: u64, b: u64) -> Result; + fn safe_add_two(env: soroban_sdk::Env, a: u64, b: u64) -> Result; +} +#[soroban_sdk::contracterror(export = false)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum Error { + Overflow = 1, +} +#[soroban_sdk::contracterror(export = false)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum MyError { + Overflow = 1, +} +"#, + ); + } + + /// Test that shows the raw spec entries from the wasm. + /// Verifies that the on-the-wire spec format is unchanged: a contract + /// error enum named `Error` is still emitted as the built-in + /// `ScSpecTypeDef::Error` in function signatures (the user-defined-vs-SDK + /// disambiguation happens at client generation time, not here). A + /// differently-named error enum (`MyError`) is emitted as a UDT reference. + #[test] + fn test_add_u64_spec_entries() { + use super::ScSpecEntry; + use stellar_xdr::curr::ScSpecTypeDef; + + let entries = from_wasm(ADD_U64_WASM).unwrap(); + + // Find the safe_add function spec + let safe_add_fn = entries + .iter() + .find_map(|e| match e { + ScSpecEntry::FunctionV0(f) if f.name.to_utf8_string().unwrap() == "safe_add" => { + Some(f) + } + _ => None, + }) + .expect("safe_add function not found"); + + let output = safe_add_fn.outputs.to_option().expect("should have output"); + let ScSpecTypeDef::Result(r) = output else { + panic!("output should be a Result type"); + }; + assert!( + matches!(r.ok_type.as_ref(), ScSpecTypeDef::U64), + "ok_type should be U64" + ); + assert!( + matches!(r.error_type.as_ref(), ScSpecTypeDef::Error), + "error_type should be the built-in Error in the wasm spec, got {:?}", + r.error_type + ); + + // Find the safe_add_two function spec + let safe_add_two_fn = entries + .iter() + .find_map(|e| match e { + ScSpecEntry::FunctionV0(f) + if f.name.to_utf8_string().unwrap() == "safe_add_two" => + { + Some(f) + } + _ => None, + }) + .expect("safe_add_two function not found"); + + let output = safe_add_two_fn + .outputs + .to_option() + .expect("should have output"); + let ScSpecTypeDef::Result(r) = output else { + panic!("output should be a Result type"); + }; + assert!( + matches!(r.ok_type.as_ref(), ScSpecTypeDef::U64), + "ok_type should be U64" + ); + let ScSpecTypeDef::Udt(u) = r.error_type.as_ref() else { + panic!( + "error_type should be a UDT for MyError, got {:?}", + r.error_type + ); + }; + assert_eq!( + u.name.to_utf8_string().unwrap(), + "MyError", + "error_type should be MyError UDT" + ); + } + + /// When the spec references `ScSpecTypeDef::Error` and contains no error + /// enum named `Error`, the generator must leave it as `soroban_sdk::Error`. + /// This covers contracts that use `soroban_sdk::Error` directly as their + /// Result error type, including every contract compiled before the + /// error-enum override was introduced. + #[test] + fn test_missing_error_udt_falls_back_to_sdk_error() { + use super::ScSpecEntry; + use stellar_xdr::curr::{ScSpecFunctionV0, ScSpecTypeDef, ScSpecTypeResult}; + + let func = ScSpecFunctionV0 { + doc: "".try_into().unwrap(), + name: "safe_add".try_into().unwrap(), + inputs: [].try_into().unwrap(), + outputs: [ScSpecTypeDef::Result(Box::new(ScSpecTypeResult { + ok_type: Box::new(ScSpecTypeDef::U64), + error_type: Box::new(ScSpecTypeDef::Error), + }))] + .try_into() + .unwrap(), + }; + let entries = [ScSpecEntry::FunctionV0(func)]; + let rust = generate(&entries, "", "") + .unwrap() + .to_formatted_string() + .unwrap(); + assert_eq!( + rust, + r#"pub const WASM: &[u8] = soroban_sdk::contractfile!(file = "", sha256 = ""); +#[soroban_sdk::contractargs(name = "Args")] +#[soroban_sdk::contractclient(name = "Client")] +pub trait Contract { + fn safe_add(env: soroban_sdk::Env) -> Result; +} +"#, + ); + } + + /// When the spec contains a user-defined `Error` error enum, every + /// `ScSpecTypeDef::Error` reference in the spec must be rewritten to + /// reference that UDT instead of `soroban_sdk::Error`. + #[test] + fn test_error_udt_overrides_sdk_error() { + use super::ScSpecEntry; + use stellar_xdr::curr::{ + ScSpecFunctionV0, ScSpecTypeDef, ScSpecTypeResult, ScSpecUdtErrorEnumCaseV0, + ScSpecUdtErrorEnumV0, + }; + + let func = ScSpecFunctionV0 { + doc: "".try_into().unwrap(), + name: "safe_add".try_into().unwrap(), + inputs: [].try_into().unwrap(), + outputs: [ScSpecTypeDef::Result(Box::new(ScSpecTypeResult { + ok_type: Box::new(ScSpecTypeDef::U64), + error_type: Box::new(ScSpecTypeDef::Error), + }))] + .try_into() + .unwrap(), + }; + let error_enum = ScSpecUdtErrorEnumV0 { + doc: "".try_into().unwrap(), + lib: "".try_into().unwrap(), + name: "Error".try_into().unwrap(), + cases: [ScSpecUdtErrorEnumCaseV0 { + doc: "".try_into().unwrap(), + name: "Overflow".try_into().unwrap(), + value: 1, + }] + .try_into() + .unwrap(), + }; + let entries = [ + ScSpecEntry::FunctionV0(func), + ScSpecEntry::UdtErrorEnumV0(error_enum), + ]; + let rust = generate(&entries, "", "") + .unwrap() + .to_formatted_string() + .unwrap(); + assert_eq!( + rust, + r#"pub const WASM: &[u8] = soroban_sdk::contractfile!(file = "", sha256 = ""); +#[soroban_sdk::contractargs(name = "Args")] +#[soroban_sdk::contractclient(name = "Client")] +pub trait Contract { + fn safe_add(env: soroban_sdk::Env) -> Result; +} +#[soroban_sdk::contracterror(export = false)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum Error { + Overflow = 1, +} +"#, + ); + } + + /// When the `Error` override applies, nested `ScSpecTypeDef::Error` + /// references must be rewritten too. + #[test] + fn test_error_udt_override_rewrites_nested_vec() { + use super::ScSpecEntry; + use stellar_xdr::curr::{ + ScSpecFunctionV0, ScSpecTypeDef, ScSpecTypeVec, ScSpecUdtErrorEnumCaseV0, + ScSpecUdtErrorEnumV0, + }; + + let func = ScSpecFunctionV0 { + doc: "".try_into().unwrap(), + name: "errors".try_into().unwrap(), + inputs: [].try_into().unwrap(), + outputs: [ScSpecTypeDef::Vec(Box::new(ScSpecTypeVec { + element_type: Box::new(ScSpecTypeDef::Error), + }))] + .try_into() + .unwrap(), + }; + let error_enum = ScSpecUdtErrorEnumV0 { + doc: "".try_into().unwrap(), + lib: "".try_into().unwrap(), + name: "Error".try_into().unwrap(), + cases: [ScSpecUdtErrorEnumCaseV0 { + doc: "".try_into().unwrap(), + name: "Overflow".try_into().unwrap(), + value: 1, + }] + .try_into() + .unwrap(), + }; + let entries = [ + ScSpecEntry::FunctionV0(func), + ScSpecEntry::UdtErrorEnumV0(error_enum), + ]; + let rust = generate(&entries, "", "") + .unwrap() + .to_formatted_string() + .unwrap(); + assert_eq!( + rust, + r#"pub const WASM: &[u8] = soroban_sdk::contractfile!(file = "", sha256 = ""); +#[soroban_sdk::contractargs(name = "Args")] +#[soroban_sdk::contractclient(name = "Client")] +pub trait Contract { + fn errors(env: soroban_sdk::Env) -> soroban_sdk::Vec; +} +#[soroban_sdk::contracterror(export = false)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum Error { + Overflow = 1, +} "#, ); } diff --git a/tests-expanded/test_add_u64_tests.rs b/tests-expanded/test_add_u64_tests.rs index 8dac902c5..ce6b002d4 100644 --- a/tests-expanded/test_add_u64_tests.rs +++ b/tests-expanded/test_add_u64_tests.rs @@ -4,7 +4,7 @@ extern crate core; #[prelude_import] use core::prelude::rust_2021::*; -use soroban_sdk::{contract, contractimpl}; +use soroban_sdk::{contract, contracterror, contractimpl}; pub struct Contract; ///ContractArgs is a type for building arg lists for functions defined in "Contract". pub struct ContractArgs; @@ -136,10 +136,282 @@ impl soroban_sdk::testutils::ContractFunctionSet for Contract { __contract_fn_set_registry::call(func, env, args) } } +pub enum Error { + Overflow = 1, +} +#[automatically_derived] +impl ::core::fmt::Debug for Error { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for Error {} +#[automatically_derived] +impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + true + } +} +pub static __SPEC_XDR_TYPE_ERROR: [u8; 48usize] = Error::spec_xdr(); +impl Error { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } +} +impl soroban_sdk::SpecShakingMarker for Error { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() {} +} +impl TryFrom for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } +} +impl TryFrom<&soroban_sdk::Error> for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::Error { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::Error { + match val { + Error::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } +} +impl TryFrom for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } +} +impl TryFrom<&soroban_sdk::InvokeError> for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::InvokeError { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::InvokeError { + match val { + Error::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } +} +impl soroban_sdk::TryFromVal for Error { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &Error, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&Error, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } +} +pub enum MyError { + Overflow = 1, +} +#[automatically_derived] +impl ::core::fmt::Debug for MyError { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for MyError {} +#[automatically_derived] +impl ::core::cmp::PartialEq for MyError { + #[inline] + fn eq(&self, other: &MyError) -> bool { + true + } +} +pub static __SPEC_XDR_TYPE_MYERROR: [u8; 48usize] = MyError::spec_xdr(); +impl MyError { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x07MyError\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } +} +impl soroban_sdk::SpecShakingMarker for MyError { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() {} +} +impl TryFrom for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } +} +impl TryFrom<&soroban_sdk::Error> for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::Error { + <_ as From<&MyError>>::from(&val) + } +} +impl From<&MyError> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::Error { + match val { + MyError::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } +} +impl TryFrom for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } +} +impl TryFrom<&soroban_sdk::InvokeError> for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::InvokeError { + <_ as From<&MyError>>::from(&val) + } +} +impl From<&MyError> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::InvokeError { + match val { + MyError::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } +} +impl soroban_sdk::TryFromVal for MyError { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &MyError, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&MyError, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } +} impl Contract { pub fn add(a: u64, b: u64) -> u64 { a + b } + pub fn safe_add(a: u64, b: u64) -> Result { + a.checked_add(b).ok_or(Error::Overflow) + } + pub fn safe_add_two(a: u64, b: u64) -> Result { + a.checked_add(b).ok_or(MyError::Overflow) + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -155,6 +427,34 @@ impl Contract { *b"\0\0\0\0\0\0\0\0\0\0\0\x03add\0\0\0\0\x02\0\0\0\0\0\0\0\x01a\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01b\0\0\0\0\0\0\x06\0\0\0\x01\0\0\0\x06" } } +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + pub static __SPEC_XDR_FN_SAFE_ADD: [u8; 72usize] = super::Contract::spec_xdr_safe_add(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add() -> [u8; 72usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x08safe_add\0\0\0\x02\0\0\0\0\0\0\0\x01a\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01b\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\0\x03" + } +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add_two__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + pub static __SPEC_XDR_FN_SAFE_ADD_TWO: [u8; 88usize] = super::Contract::spec_xdr_safe_add_two(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add_two() -> [u8; 88usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x0csafe_add_two\0\0\0\x02\0\0\0\0\0\0\0\x01a\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01b\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\x07\xd0\0\0\0\x07MyError\0" + } +} impl<'a> ContractClient<'a> { pub fn add(&self, a: &u64, b: &u64) -> u64 { use core::ops::Not; @@ -243,6 +543,172 @@ impl<'a> ContractClient<'a> { } res } + pub fn safe_add(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn try_safe_add( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn safe_add_two(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn try_safe_add_two( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } } impl ContractArgs { #[inline(always)] @@ -250,6 +716,16 @@ impl ContractArgs { pub fn add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { (a, b) } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_two<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -309,8 +785,120 @@ pub extern "C" fn __Contract__add__invoke_raw_extern( } #[doc(hidden)] #[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add( + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add` instead")] +pub fn __Contract__safe_add__invoke_raw_slice( + env: soroban_sdk::Env, + args: &[soroban_sdk::Val], +) -> soroban_sdk::Val { + if args.len() != 2usize { + { + ::core::panicking::panic_fmt(format_args!( + "invalid number of input arguments: {0} expected, got {1}", + 2usize, + args.len(), + )); + }; + } + #[allow(deprecated)] + __Contract__safe_add__invoke_raw(env, args[0usize], args[1usize]) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add` instead")] +pub extern "C" fn __Contract__safe_add__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_two` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add_two__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add_two( + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_two` instead")] +pub fn __Contract__safe_add_two__invoke_raw_slice( + env: soroban_sdk::Env, + args: &[soroban_sdk::Val], +) -> soroban_sdk::Val { + if args.len() != 2usize { + { + ::core::panicking::panic_fmt(format_args!( + "invalid number of input arguments: {0} expected, got {1}", + 2usize, + args.len(), + )); + }; + } + #[allow(deprecated)] + __Contract__safe_add_two__invoke_raw(env, args[0usize], args[1usize]) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_two` instead")] +pub extern "C" fn __Contract__safe_add_two__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add_two__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1) +} +#[doc(hidden)] +#[allow(non_snake_case)] #[allow(unused)] -fn __Contract____7e9e5ac30f2216fd0fd6f5faed316f2d5983361a4203c3330cfa46ef65bb4767_ctor() { +fn __Contract____6ecf4b81a1826b186b96027a980a40b74ef0e4056b0b7fa44cfd522125765f33_ctor() { #[allow(unsafe_code)] { #[link_section = ".init_array"] @@ -322,7 +910,7 @@ fn __Contract____7e9e5ac30f2216fd0fd6f5faed316f2d5983361a4203c3330cfa46ef65bb476 #[allow(non_snake_case)] extern "C" fn f() -> ::ctor::__support::CtorRetType { unsafe { - __Contract____7e9e5ac30f2216fd0fd6f5faed316f2d5983361a4203c3330cfa46ef65bb4767_ctor(); + __Contract____6ecf4b81a1826b186b96027a980a40b74ef0e4056b0b7fa44cfd522125765f33_ctor(); }; core::default::Default::default() } @@ -335,10 +923,20 @@ fn __Contract____7e9e5ac30f2216fd0fd6f5faed316f2d5983361a4203c3330cfa46ef65bb476 #[allow(deprecated)] &__Contract__add__invoke_raw_slice, ); + ::register( + "safe_add", + #[allow(deprecated)] + &__Contract__safe_add__invoke_raw_slice, + ); + ::register( + "safe_add_two", + #[allow(deprecated)] + &__Contract__safe_add_two__invoke_raw_slice, + ); } } mod test { - use crate::{Contract, ContractClient}; + use crate::{Contract, ContractClient, Error}; use soroban_sdk::Env; extern crate test; #[rustc_test_marker = "test::test_add"] @@ -349,9 +947,9 @@ mod test { ignore: false, ignore_message: ::core::option::Option::None, source_file: "tests/add_u64/src/lib.rs", - start_line: 21usize, + start_line: 39usize, start_col: 8usize, - end_line: 21usize, + end_line: 39usize, end_col: 16usize, compile_fail: false, no_run: false, @@ -374,11 +972,55 @@ mod test { ::core::panicking::panic("assertion failed: z == 22") } } + extern crate test; + #[rustc_test_marker = "test::test_safe_add"] + #[doc(hidden)] + pub const test_safe_add: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("test::test_safe_add"), + ignore: false, + ignore_message: ::core::option::Option::None, + source_file: "tests/add_u64/src/lib.rs", + start_line: 50usize, + start_col: 8usize, + end_line: 50usize, + end_col: 21usize, + compile_fail: false, + no_run: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn( + #[coverage(off)] + || test::assert_test_result(test_safe_add()), + ), + }; + fn test_safe_add() { + let e = Env::default(); + let contract_id = e.register(Contract, ()); + let client = ContractClient::new(&e, &contract_id); + let x = u64::MAX; + let y = 1; + let z = client.try_safe_add(&x, &y); + match (&z, &Err(Ok(Error::Overflow))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + let kind = ::core::panicking::AssertKind::Eq; + ::core::panicking::assert_failed( + kind, + &*left_val, + &*right_val, + ::core::option::Option::None, + ); + } + } + }; + } } #[rustc_main] #[coverage(off)] #[doc(hidden)] pub fn main() -> () { extern crate test; - test::test_main_static(&[&test_add]) + test::test_main_static(&[&test_add, &test_safe_add]) } diff --git a/tests-expanded/test_add_u64_wasm32v1-none.rs b/tests-expanded/test_add_u64_wasm32v1-none.rs index 62a1bcc94..0bcdd1476 100644 --- a/tests-expanded/test_add_u64_wasm32v1-none.rs +++ b/tests-expanded/test_add_u64_wasm32v1-none.rs @@ -4,7 +4,7 @@ extern crate core; #[prelude_import] use core::prelude::rust_2021::*; -use soroban_sdk::{contract, contractimpl}; +use soroban_sdk::{contract, contracterror, contractimpl}; pub struct Contract; ///ContractArgs is a type for building arg lists for functions defined in "Contract". pub struct ContractArgs; @@ -24,10 +24,294 @@ impl<'a> ContractClient<'a> { } } } +pub enum Error { + Overflow = 1, +} +#[automatically_derived] +impl ::core::fmt::Debug for Error { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for Error {} +#[automatically_derived] +impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + true + } +} +#[link_section = "contractspecv0"] +pub static __SPEC_XDR_TYPE_ERROR: [u8; 48usize] = Error::spec_xdr(); +impl Error { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } +} +impl soroban_sdk::SpecShakingMarker for Error { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() { + { + static MARKER: [u8; 14usize] = *b"SpEcV1\xd6\xb8`\x15\xac\x9ei\x1a"; + let _ = unsafe { ::core::ptr::read_volatile(MARKER.as_ptr()) }; + } + } +} +impl TryFrom for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } +} +impl TryFrom<&soroban_sdk::Error> for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::Error { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::Error { + match val { + Error::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } +} +impl TryFrom for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } +} +impl TryFrom<&soroban_sdk::InvokeError> for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::InvokeError { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::InvokeError { + match val { + Error::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } +} +impl soroban_sdk::TryFromVal for Error { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &Error, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&Error, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } +} +pub enum MyError { + Overflow = 1, +} +#[automatically_derived] +impl ::core::fmt::Debug for MyError { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for MyError {} +#[automatically_derived] +impl ::core::cmp::PartialEq for MyError { + #[inline] + fn eq(&self, other: &MyError) -> bool { + true + } +} +#[link_section = "contractspecv0"] +pub static __SPEC_XDR_TYPE_MYERROR: [u8; 48usize] = MyError::spec_xdr(); +impl MyError { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x07MyError\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } +} +impl soroban_sdk::SpecShakingMarker for MyError { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() { + { + static MARKER: [u8; 14usize] = *b"SpEcV1\x95\xd0j*\x1d\xfam\xa3"; + let _ = unsafe { ::core::ptr::read_volatile(MARKER.as_ptr()) }; + } + } +} +impl TryFrom for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } +} +impl TryFrom<&soroban_sdk::Error> for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::Error { + <_ as From<&MyError>>::from(&val) + } +} +impl From<&MyError> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::Error { + match val { + MyError::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } +} +impl TryFrom for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } +} +impl TryFrom<&soroban_sdk::InvokeError> for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::InvokeError { + <_ as From<&MyError>>::from(&val) + } +} +impl From<&MyError> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::InvokeError { + match val { + MyError::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } +} +impl soroban_sdk::TryFromVal for MyError { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &MyError, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&MyError, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } +} impl Contract { pub fn add(a: u64, b: u64) -> u64 { a + b } + pub fn safe_add(a: u64, b: u64) -> Result { + a.checked_add(b).ok_or(Error::Overflow) + } + pub fn safe_add_two(a: u64, b: u64) -> Result { + a.checked_add(b).ok_or(MyError::Overflow) + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -44,6 +328,36 @@ impl Contract { *b"\0\0\0\0\0\0\0\0\0\0\0\x03add\0\0\0\0\x02\0\0\0\0\0\0\0\x01a\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01b\0\0\0\0\0\0\x06\0\0\0\x01\0\0\0\x06" } } +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + #[link_section = "contractspecv0"] + pub static __SPEC_XDR_FN_SAFE_ADD: [u8; 72usize] = super::Contract::spec_xdr_safe_add(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add() -> [u8; 72usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x08safe_add\0\0\0\x02\0\0\0\0\0\0\0\x01a\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01b\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\0\x03" + } +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add_two__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + #[link_section = "contractspecv0"] + pub static __SPEC_XDR_FN_SAFE_ADD_TWO: [u8; 88usize] = super::Contract::spec_xdr_safe_add_two(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add_two() -> [u8; 88usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x0csafe_add_two\0\0\0\x02\0\0\0\0\0\0\0\x01a\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01b\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\x07\xd0\0\0\0\x07MyError\0" + } +} impl<'a> ContractClient<'a> { pub fn add(&self, a: &u64, b: &u64) -> u64 { use core::ops::Not; @@ -85,6 +399,78 @@ impl<'a> ContractClient<'a> { ); res } + pub fn safe_add(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } + pub fn try_safe_add( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } + pub fn safe_add_two(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } + pub fn try_safe_add_two( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } } impl ContractArgs { #[inline(always)] @@ -92,6 +478,16 @@ impl ContractArgs { pub fn add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { (a, b) } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_two<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -131,3 +527,79 @@ pub extern "C" fn __Contract__add__invoke_raw_extern( #[allow(deprecated)] __Contract__add__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1) } +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add( + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add` instead")] +#[export_name = "safe_add"] +pub extern "C" fn __Contract__safe_add__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_two` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add_two__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add_two( + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_two` instead")] +#[export_name = "safe_add_two"] +pub extern "C" fn __Contract__safe_add_two__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add_two__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1) +} diff --git a/tests-expanded/test_import_contract_tests.rs b/tests-expanded/test_import_contract_tests.rs index cdc1ff099..d9c99e5c4 100644 --- a/tests-expanded/test_import_contract_tests.rs +++ b/tests-expanded/test_import_contract_tests.rs @@ -4,11 +4,13 @@ extern crate core; #[prelude_import] use core::prelude::rust_2021::*; -use soroban_sdk::{contract, contractimpl, Address, Env}; +use soroban_sdk::{contract, contracterror, contractimpl, Address, Env}; mod addcontract { - pub const WASM: &[u8] = b"\x00asm\x01\x00\x00\x00\x01\x14\x04`\x01~\x01~`\x02\x7f~\x00`\x02~~\x01~`\x00\x00\x02\r\x02\x01i\x010\x00\x00\x01i\x01_\x00\x00\x03\x05\x04\x01\x02\x03\x03\x05\x03\x01\x00\x10\x06!\x04\x7f\x01A\x80\x80\xc0\x00\x0b\x7f\x00A\x80\x80\xc0\x00\x0b\x7f\x00A\x80\x80\xc0\x00\x0b\x7f\x00A\x80\x80\xc0\x00\x0b\x07/\x05\x06memory\x02\x00\x03add\x00\x03\x01_\x03\x01\n__data_end\x03\x02\x0b__heap_base\x03\x03\n\x8b\x02\x04]\x02\x01\x7f\x01~\x02@\x02@ \x01\xa7A\xff\x01q\"\x02A\xc0\x00F\r\x00\x02@ \x02A\x06F\r\x00B\x01!\x03B\x83\x90\x80\x80\x80\x01!\x01\x0c\x02\x0b \x01B\x08\x88!\x01B\x00!\x03\x0c\x01\x0bB\x00!\x03 \x01\x10\x80\x80\x80\x80\x00!\x01\x0b \x00 \x037\x03\x00 \x00 \x017\x03\x08\x0b\x9c\x01\x01\x01\x7f#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08\"\x01 \x00|\"\x00 \x01T\r\x01\x02@\x02@ \x00B\xff\xff\xff\xff\xff\xff\xff\xff\x00V\r\x00 \x00B\x08\x86B\x06\x84!\x00\x0c\x01\x0b \x00\x10\x81\x80\x80\x80\x00!\x00\x0b \x02A\x10j$\x80\x80\x80\x80\x00 \x00\x0f\x0b\x00\x0b\x10\x84\x80\x80\x80\x00\x00\x0b\t\x00\x10\x85\x80\x80\x80\x00\x00\x0b\x03\x00\x00\x0b\x0b\t\x01\x00A\x80\x80\xc0\x00\x0b\x00\x00K\x0econtractspecv0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03add\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x06\x00\x1e\x11contractenvmetav0\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00O\x0econtractmetav0\x00\x00\x00\x00\x00\x00\x00\x05rsver\x00\x00\x00\x00\x00\x00\x061.91.0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12rssdk_spec_shaking\x00\x00\x00\x00\x00\x012\x00\x00\x00"; + pub const WASM: &[u8] = b"\x00asm\x01\x00\x00\x00\x01\x14\x04`\x01~\x01~`\x02\x7f~\x00`\x02~~\x01~`\x00\x00\x02\r\x02\x01i\x010\x00\x00\x01i\x01_\x00\x00\x03\x08\x07\x01\x01\x02\x03\x02\x02\x03\x05\x03\x01\x00\x11\x06!\x04\x7f\x01A\x80\x80\xc0\x00\x0b\x7f\x00A\x9c\x80\xc0\x00\x0b\x7f\x00A\x9c\x80\xc0\x00\x0b\x7f\x00A\xa0\x80\xc0\x00\x0b\x07I\x07\x06memory\x02\x00\x03add\x00\x04\x08safe_add\x00\x06\x0csafe_add_two\x00\x07\x01_\x03\x01\n__data_end\x03\x02\x0b__heap_base\x03\x03\n\xf3\x04\x07]\x02\x01\x7f\x01~\x02@\x02@ \x01\xa7A\xff\x01q\"\x02A\xc0\x00F\r\x00\x02@ \x02A\x06F\r\x00B\x01!\x03B\x83\x90\x80\x80\x80\x01!\x01\x0c\x02\x0b \x01B\x08\x88!\x01B\x00!\x03\x0c\x01\x0bB\x00!\x03 \x01\x10\x80\x80\x80\x80\x00!\x01\x0b \x00 \x037\x03\x00 \x00 \x017\x03\x08\x0b;\x00\x02@\x02@ \x01B\xff\xff\xff\xff\xff\xff\xff\xff\x00V\r\x00 \x01B\x08\x86B\x06\x84!\x01\x0c\x01\x0b \x01\x10\x81\x80\x80\x80\x00!\x01\x0b \x00B\x007\x03\x00 \x00 \x017\x03\x08\x0b\x8e\x01\x01\x01\x7f#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@\x02@\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08\"\x01 \x00|\"\x00 \x01T\r\x01 \x02 \x00\x10\x83\x80\x80\x80\x00 \x02(\x02\x00A\x01G\r\x02\x0b\x00\x0b\x10\x85\x80\x80\x80\x00\x00\x0b \x02)\x03\x08!\x00 \x02A\x10j$\x80\x80\x80\x80\x00 \x00\x0b\t\x00\x10\x88\x80\x80\x80\x00\x00\x0b\x9b\x01\x02\x01\x7f\x01~#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x03 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00A\x00-\x00\x80\x80\xc0\x80\x00\x1aB\x83\x80\x80\x80\x10!\x01\x02@ \x00 \x03|\"\x03 \x00T\r\x00 \x02 \x03\x10\x83\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x01 \x02)\x03\x08!\x01\x0b \x02A\x10j$\x80\x80\x80\x80\x00 \x01\x0f\x0b\x00\x0b\x9b\x01\x02\x01\x7f\x01~#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x03 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00A\x00-\x00\x8e\x80\xc0\x80\x00\x1aB\x83\x80\x80\x80\x10!\x01\x02@ \x00 \x03|\"\x03 \x00T\r\x00 \x02 \x03\x10\x83\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x01 \x02)\x03\x08!\x01\x0b \x02A\x10j$\x80\x80\x80\x80\x00 \x01\x0f\x0b\x00\x0b\x03\x00\x00\x0b\x0b%\x01\x00A\x80\x80\xc0\x00\x0b\x1cSpEcV1\xd6\xb8`\x15\xac\x9ei\x1aSpEcV1\x95\xd0j*\x1d\xfam\xa3\x00\xcb\x02\x0econtractspecv0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03add\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05Error\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x08Overflow\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07MyError\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x08Overflow\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08safe_add\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x03\xe9\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0csafe_add_two\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x03\xe9\x00\x00\x00\x06\x00\x00\x07\xd0\x00\x00\x00\x07MyError\x00\x00\x1e\x11contractenvmetav0\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00O\x0econtractmetav0\x00\x00\x00\x00\x00\x00\x00\x05rsver\x00\x00\x00\x00\x00\x00\x061.91.0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12rssdk_spec_shaking\x00\x00\x00\x00\x00\x012\x00\x00\x00"; pub trait Contract { fn add(env: soroban_sdk::Env, a: u64, b: u64) -> u64; + fn safe_add(env: soroban_sdk::Env, a: u64, b: u64) -> Result; + fn safe_add_two(env: soroban_sdk::Env, a: u64, b: u64) -> Result; } ///Client is a client for calling the contract defined in "Contract". pub struct Client<'a> { @@ -194,6 +196,178 @@ mod addcontract { } res } + pub fn safe_add(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn try_safe_add( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result< + u64, + >::Error, + >, + Result, + > { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn safe_add_two(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn try_safe_add_two( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result< + u64, + >::Error, + >, + Result, + > { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } } ///Args is a type for building arg lists for functions defined in "Contract". pub struct Args; @@ -203,6 +377,488 @@ mod addcontract { pub fn add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { (a, b) } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_two<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } + } + pub enum Error { + Overflow = 1, + } + #[automatically_derived] + impl ::core::fmt::Debug for Error { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } + } + #[automatically_derived] + impl ::core::marker::Copy for Error {} + #[automatically_derived] + impl ::core::clone::Clone for Error { + #[inline] + fn clone(&self) -> Error { + *self + } + } + #[automatically_derived] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + #[coverage(off)] + fn assert_receiver_is_total_eq(&self) -> () {} + } + #[automatically_derived] + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + true + } + } + #[automatically_derived] + impl ::core::cmp::Ord for Error { + #[inline] + fn cmp(&self, other: &Error) -> ::core::cmp::Ordering { + ::core::cmp::Ordering::Equal + } + } + #[automatically_derived] + impl ::core::cmp::PartialOrd for Error { + #[inline] + fn partial_cmp(&self, other: &Error) -> ::core::option::Option<::core::cmp::Ordering> { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } + } + pub static __SPEC_XDR_TYPE_ERROR: [u8; 48usize] = Error::spec_xdr(); + impl Error { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } + } + impl soroban_sdk::SpecShakingMarker for Error { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() {} + } + impl TryFrom for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } + } + impl TryFrom<&soroban_sdk::Error> for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::Error { + <_ as From<&Error>>::from(&val) + } + } + impl From<&Error> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::Error { + match val { + Error::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } + } + impl TryFrom for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } + } + impl TryFrom<&soroban_sdk::InvokeError> for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::InvokeError { + <_ as From<&Error>>::from(&val) + } + } + impl From<&Error> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::InvokeError { + match val { + Error::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } + } + impl soroban_sdk::TryFromVal for Error { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &Error, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&Error, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } + } + pub enum MyError { + Overflow = 1, + } + #[automatically_derived] + impl ::core::fmt::Debug for MyError { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } + } + #[automatically_derived] + impl ::core::marker::Copy for MyError {} + #[automatically_derived] + impl ::core::clone::Clone for MyError { + #[inline] + fn clone(&self) -> MyError { + *self + } + } + #[automatically_derived] + impl ::core::cmp::Eq for MyError { + #[inline] + #[doc(hidden)] + #[coverage(off)] + fn assert_receiver_is_total_eq(&self) -> () {} + } + #[automatically_derived] + impl ::core::marker::StructuralPartialEq for MyError {} + #[automatically_derived] + impl ::core::cmp::PartialEq for MyError { + #[inline] + fn eq(&self, other: &MyError) -> bool { + true + } + } + #[automatically_derived] + impl ::core::cmp::Ord for MyError { + #[inline] + fn cmp(&self, other: &MyError) -> ::core::cmp::Ordering { + ::core::cmp::Ordering::Equal + } + } + #[automatically_derived] + impl ::core::cmp::PartialOrd for MyError { + #[inline] + fn partial_cmp(&self, other: &MyError) -> ::core::option::Option<::core::cmp::Ordering> { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } + } + pub static __SPEC_XDR_TYPE_MYERROR: [u8; 48usize] = MyError::spec_xdr(); + impl MyError { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x07MyError\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } + } + impl soroban_sdk::SpecShakingMarker for MyError { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() {} + } + impl TryFrom for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } + } + impl TryFrom<&soroban_sdk::Error> for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::Error { + <_ as From<&MyError>>::from(&val) + } + } + impl From<&MyError> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::Error { + match val { + MyError::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } + } + impl TryFrom for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } + } + impl TryFrom<&soroban_sdk::InvokeError> for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::InvokeError { + <_ as From<&MyError>>::from(&val) + } + } + impl From<&MyError> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::InvokeError { + match val { + MyError::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } + } + impl soroban_sdk::TryFromVal for MyError { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &MyError, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&MyError, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } + } +} +pub enum Error { + Abort = 0, + Overflow = 1, +} +#[automatically_derived] +impl ::core::fmt::Debug for Error { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str( + f, + match self { + Error::Abort => "Abort", + Error::Overflow => "Overflow", + }, + ) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for Error {} +#[automatically_derived] +impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr + } +} +pub static __SPEC_XDR_TYPE_ERROR: [u8; 68usize] = Error::spec_xdr(); +impl Error { + pub const fn spec_xdr() -> [u8; 68usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x02\0\0\0\0\0\0\0\x05Abort\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } +} +impl soroban_sdk::SpecShakingMarker for Error { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() {} +} +impl TryFrom for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 0u32 => Self::Abort, + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } +} +impl TryFrom<&soroban_sdk::Error> for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::Error { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::Error { + match val { + Error::Abort => soroban_sdk::Error::from_contract_error(0u32), + Error::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } +} +impl TryFrom for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 0u32 => Self::Abort, + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } +} +impl TryFrom<&soroban_sdk::InvokeError> for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::InvokeError { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::InvokeError { + match val { + Error::Abort => soroban_sdk::InvokeError::Contract(0u32), + Error::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } +} +impl soroban_sdk::TryFromVal for Error { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &Error, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&Error, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) } } pub struct Contract; @@ -324,39 +980,267 @@ impl soroban_sdk::testutils::ContractFunctionRegister for Contract { fn register(name: &'static str, func: &'static __contract_fn_set_registry::F) { __contract_fn_set_registry::register(name, func); } -} -#[doc(hidden)] -impl soroban_sdk::testutils::ContractFunctionSet for Contract { - fn call( +} +#[doc(hidden)] +impl soroban_sdk::testutils::ContractFunctionSet for Contract { + fn call( + &self, + func: &str, + env: soroban_sdk::Env, + args: &[soroban_sdk::Val], + ) -> Option { + __contract_fn_set_registry::call(func, env, args) + } +} +impl Contract { + pub fn add_with(env: Env, contract_id: Address, x: u64, y: u64) -> u64 { + addcontract::Client::new(&env, &contract_id).add(&x, &y) + } + pub fn safe_add_with(env: Env, contract_id: Address, x: u64, y: u64) -> Result { + match addcontract::Client::new(&env, &contract_id).try_safe_add(&x, &y) { + Ok(Ok(i)) => Ok(i), + Err(Ok(addcontract::Error::Overflow)) => Err(Error::Overflow), + _ => Err(Error::Abort), + } + } + pub fn safe_add_with_two(env: Env, contract_id: Address, x: u64, y: u64) -> Result { + match addcontract::Client::new(&env, &contract_id).try_safe_add_two(&x, &y) { + Ok(Ok(i)) => Ok(i), + Err(Ok(addcontract::MyError::Overflow)) => Err(Error::Overflow), + _ => Err(Error::Abort), + } + } +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__add_with__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + pub static __SPEC_XDR_FN_ADD_WITH: [u8; 88usize] = super::Contract::spec_xdr_add_with(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_add_with() -> [u8; 88usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x08add_with\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\0\x06" + } +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add_with__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + pub static __SPEC_XDR_FN_SAFE_ADD_WITH: [u8; 104usize] = + super::Contract::spec_xdr_safe_add_with(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add_with() -> [u8; 104usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\rsafe_add_with\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\0\x03" + } +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add_with_two__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + pub static __SPEC_XDR_FN_SAFE_ADD_WITH_TWO: [u8; 108usize] = + super::Contract::spec_xdr_safe_add_with_two(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add_with_two() -> [u8; 108usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x11safe_add_with_two\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\0\x03" + } +} +impl<'a> ContractClient<'a> { + pub fn add_with(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("add_with"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn try_add_with( + &self, + contract_id: &Address, + x: &u64, + y: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("add_with"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn safe_add_with(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res + } + pub fn try_safe_add_with( &self, - func: &str, - env: soroban_sdk::Env, - args: &[soroban_sdk::Val], - ) -> Option { - __contract_fn_set_registry::call(func, env, args) - } -} -impl Contract { - pub fn add_with(env: Env, contract_id: Address, x: u64, y: u64) -> u64 { - addcontract::Client::new(&env, &contract_id).add(&x, &y) - } -} -#[doc(hidden)] -#[allow(non_snake_case)] -pub mod __Contract__add_with__spec { - #[doc(hidden)] - #[allow(non_snake_case)] - #[allow(non_upper_case_globals)] - pub static __SPEC_XDR_FN_ADD_WITH: [u8; 88usize] = super::Contract::spec_xdr_add_with(); -} -impl Contract { - #[allow(non_snake_case)] - pub const fn spec_xdr_add_with() -> [u8; 88usize] { - *b"\0\0\0\0\0\0\0\0\0\0\0\x08add_with\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\0\x06" + contract_id: &Address, + x: &u64, + y: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use core::ops::Not; + let old_auth_manager = self + .env + .in_contract() + .not() + .then(|| self.env.host().snapshot_auth_manager().unwrap()); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } + } + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res } -} -impl<'a> ContractClient<'a> { - pub fn add_with(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { + pub fn safe_add_with_two(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { use core::ops::Not; let old_auth_manager = self .env @@ -381,11 +1265,7 @@ impl<'a> ContractClient<'a> { use soroban_sdk::{FromVal, IntoVal}; let res = self.env.invoke_contract( &self.address, - &{ - #[allow(deprecated)] - const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("add_with"); - SYMBOL - }, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with_two") }, ::soroban_sdk::Vec::from_array( &self.env, [ @@ -400,14 +1280,14 @@ impl<'a> ContractClient<'a> { } res } - pub fn try_add_with( + pub fn try_safe_add_with_two( &self, contract_id: &Address, x: &u64, y: &u64, ) -> Result< Result>::Error>, - Result, + Result, > { use core::ops::Not; let old_auth_manager = self @@ -433,11 +1313,7 @@ impl<'a> ContractClient<'a> { use soroban_sdk::{FromVal, IntoVal}; let res = self.env.try_invoke_contract( &self.address, - &{ - #[allow(deprecated)] - const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("add_with"); - SYMBOL - }, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with_two") }, ::soroban_sdk::Vec::from_array( &self.env, [ @@ -463,6 +1339,24 @@ impl ContractArgs { ) -> (&'i Address, &'i u64, &'i u64) { (contract_id, x, y) } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_with<'i>( + contract_id: &'i Address, + x: &'i u64, + y: &'i u64, + ) -> (&'i Address, &'i u64, &'i u64) { + (contract_id, x, y) + } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_with_two<'i>( + contract_id: &'i Address, + x: &'i u64, + y: &'i u64, + ) -> (&'i Address, &'i u64, &'i u64) { + (contract_id, x, y) + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -531,8 +1425,138 @@ pub extern "C" fn __Contract__add_with__invoke_raw_extern( } #[doc(hidden)] #[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add_with__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add_with( + env.clone(), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_2), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with` instead")] +pub fn __Contract__safe_add_with__invoke_raw_slice( + env: soroban_sdk::Env, + args: &[soroban_sdk::Val], +) -> soroban_sdk::Val { + if args.len() != 3usize { + { + ::core::panicking::panic_fmt(format_args!( + "invalid number of input arguments: {0} expected, got {1}", + 3usize, + args.len(), + )); + }; + } + #[allow(deprecated)] + __Contract__safe_add_with__invoke_raw(env, args[0usize], args[1usize], args[2usize]) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with` instead")] +pub extern "C" fn __Contract__safe_add_with__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add_with__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1, arg_2) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with_two` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add_with_two__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add_with_two( + env.clone(), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_2), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with_two` instead")] +pub fn __Contract__safe_add_with_two__invoke_raw_slice( + env: soroban_sdk::Env, + args: &[soroban_sdk::Val], +) -> soroban_sdk::Val { + if args.len() != 3usize { + { + ::core::panicking::panic_fmt(format_args!( + "invalid number of input arguments: {0} expected, got {1}", + 3usize, + args.len(), + )); + }; + } + #[allow(deprecated)] + __Contract__safe_add_with_two__invoke_raw(env, args[0usize], args[1usize], args[2usize]) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with_two` instead")] +pub extern "C" fn __Contract__safe_add_with_two__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add_with_two__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1, arg_2) +} +#[doc(hidden)] +#[allow(non_snake_case)] #[allow(unused)] -fn __Contract____70a46203e4054de1ddff57b7a47699d47775f2dc3cd806328562e85117ee9756_ctor() { +fn __Contract____7f4ee4d361d09b9f0b349441853c9c2507e71fb15e4ddfe088d43fd41f0e1d27_ctor() { #[allow(unsafe_code)] { #[link_section = ".init_array"] @@ -544,7 +1568,7 @@ fn __Contract____70a46203e4054de1ddff57b7a47699d47775f2dc3cd806328562e85117ee975 #[allow(non_snake_case)] extern "C" fn f() -> ::ctor::__support::CtorRetType { unsafe { - __Contract____70a46203e4054de1ddff57b7a47699d47775f2dc3cd806328562e85117ee9756_ctor(); + __Contract____7f4ee4d361d09b9f0b349441853c9c2507e71fb15e4ddfe088d43fd41f0e1d27_ctor(); }; core::default::Default::default() } @@ -557,10 +1581,20 @@ fn __Contract____70a46203e4054de1ddff57b7a47699d47775f2dc3cd806328562e85117ee975 #[allow(deprecated)] &__Contract__add_with__invoke_raw_slice, ); + ::register( + "safe_add_with", + #[allow(deprecated)] + &__Contract__safe_add_with__invoke_raw_slice, + ); + ::register( + "safe_add_with_two", + #[allow(deprecated)] + &__Contract__safe_add_with_two__invoke_raw_slice, + ); } } mod test { - use crate::{addcontract, Contract, ContractClient}; + use crate::{addcontract, Contract, ContractClient, Error}; use soroban_sdk::Env; extern crate test; #[rustc_test_marker = "test::test_add"] @@ -571,9 +1605,9 @@ mod test { ignore: false, ignore_message: ::core::option::Option::None, source_file: "tests/import_contract/src/lib.rs", - start_line: 25usize, + start_line: 46usize, start_col: 8usize, - end_line: 25usize, + end_line: 46usize, end_col: 16usize, compile_fail: false, no_run: false, @@ -597,11 +1631,70 @@ mod test { ::core::panicking::panic("assertion failed: z == 22") } } + extern crate test; + #[rustc_test_marker = "test::test_safe_add"] + #[doc(hidden)] + pub const test_safe_add: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("test::test_safe_add"), + ignore: false, + ignore_message: ::core::option::Option::None, + source_file: "tests/import_contract/src/lib.rs", + start_line: 60usize, + start_col: 8usize, + end_line: 60usize, + end_col: 21usize, + compile_fail: false, + no_run: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn( + #[coverage(off)] + || test::assert_test_result(test_safe_add()), + ), + }; + fn test_safe_add() { + let e = Env::default(); + let add_contract_id = e.register(addcontract::WASM, ()); + let contract_id = e.register(Contract, ()); + let client = ContractClient::new(&e, &contract_id); + let x = u64::MAX; + let y = 1; + let z = client.try_safe_add_with(&add_contract_id, &x, &y); + match (&z, &Err(Ok(Error::Overflow))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + let kind = ::core::panicking::AssertKind::Eq; + ::core::panicking::assert_failed( + kind, + &*left_val, + &*right_val, + ::core::option::Option::None, + ); + } + } + }; + let z = client.try_safe_add_with_two(&add_contract_id, &x, &y); + match (&z, &Err(Ok(Error::Overflow))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + let kind = ::core::panicking::AssertKind::Eq; + ::core::panicking::assert_failed( + kind, + &*left_val, + &*right_val, + ::core::option::Option::None, + ); + } + } + }; + } } #[rustc_main] #[coverage(off)] #[doc(hidden)] pub fn main() -> () { extern crate test; - test::test_main_static(&[&test_add]) + test::test_main_static(&[&test_add, &test_safe_add]) } diff --git a/tests-expanded/test_import_contract_wasm32v1-none.rs b/tests-expanded/test_import_contract_wasm32v1-none.rs index 7cf04ad08..30d666d0e 100644 --- a/tests-expanded/test_import_contract_wasm32v1-none.rs +++ b/tests-expanded/test_import_contract_wasm32v1-none.rs @@ -4,11 +4,13 @@ extern crate core; #[prelude_import] use core::prelude::rust_2021::*; -use soroban_sdk::{contract, contractimpl, Address, Env}; +use soroban_sdk::{contract, contracterror, contractimpl, Address, Env}; mod addcontract { - pub const WASM: &[u8] = b"\x00asm\x01\x00\x00\x00\x01\x14\x04`\x01~\x01~`\x02\x7f~\x00`\x02~~\x01~`\x00\x00\x02\r\x02\x01i\x010\x00\x00\x01i\x01_\x00\x00\x03\x05\x04\x01\x02\x03\x03\x05\x03\x01\x00\x10\x06!\x04\x7f\x01A\x80\x80\xc0\x00\x0b\x7f\x00A\x80\x80\xc0\x00\x0b\x7f\x00A\x80\x80\xc0\x00\x0b\x7f\x00A\x80\x80\xc0\x00\x0b\x07/\x05\x06memory\x02\x00\x03add\x00\x03\x01_\x03\x01\n__data_end\x03\x02\x0b__heap_base\x03\x03\n\x8b\x02\x04]\x02\x01\x7f\x01~\x02@\x02@ \x01\xa7A\xff\x01q\"\x02A\xc0\x00F\r\x00\x02@ \x02A\x06F\r\x00B\x01!\x03B\x83\x90\x80\x80\x80\x01!\x01\x0c\x02\x0b \x01B\x08\x88!\x01B\x00!\x03\x0c\x01\x0bB\x00!\x03 \x01\x10\x80\x80\x80\x80\x00!\x01\x0b \x00 \x037\x03\x00 \x00 \x017\x03\x08\x0b\x9c\x01\x01\x01\x7f#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08\"\x01 \x00|\"\x00 \x01T\r\x01\x02@\x02@ \x00B\xff\xff\xff\xff\xff\xff\xff\xff\x00V\r\x00 \x00B\x08\x86B\x06\x84!\x00\x0c\x01\x0b \x00\x10\x81\x80\x80\x80\x00!\x00\x0b \x02A\x10j$\x80\x80\x80\x80\x00 \x00\x0f\x0b\x00\x0b\x10\x84\x80\x80\x80\x00\x00\x0b\t\x00\x10\x85\x80\x80\x80\x00\x00\x0b\x03\x00\x00\x0b\x0b\t\x01\x00A\x80\x80\xc0\x00\x0b\x00\x00K\x0econtractspecv0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03add\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x06\x00\x1e\x11contractenvmetav0\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00O\x0econtractmetav0\x00\x00\x00\x00\x00\x00\x00\x05rsver\x00\x00\x00\x00\x00\x00\x061.91.0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12rssdk_spec_shaking\x00\x00\x00\x00\x00\x012\x00\x00\x00"; + pub const WASM: &[u8] = b"\x00asm\x01\x00\x00\x00\x01\x14\x04`\x01~\x01~`\x02\x7f~\x00`\x02~~\x01~`\x00\x00\x02\r\x02\x01i\x010\x00\x00\x01i\x01_\x00\x00\x03\x08\x07\x01\x01\x02\x03\x02\x02\x03\x05\x03\x01\x00\x11\x06!\x04\x7f\x01A\x80\x80\xc0\x00\x0b\x7f\x00A\x9c\x80\xc0\x00\x0b\x7f\x00A\x9c\x80\xc0\x00\x0b\x7f\x00A\xa0\x80\xc0\x00\x0b\x07I\x07\x06memory\x02\x00\x03add\x00\x04\x08safe_add\x00\x06\x0csafe_add_two\x00\x07\x01_\x03\x01\n__data_end\x03\x02\x0b__heap_base\x03\x03\n\xf3\x04\x07]\x02\x01\x7f\x01~\x02@\x02@ \x01\xa7A\xff\x01q\"\x02A\xc0\x00F\r\x00\x02@ \x02A\x06F\r\x00B\x01!\x03B\x83\x90\x80\x80\x80\x01!\x01\x0c\x02\x0b \x01B\x08\x88!\x01B\x00!\x03\x0c\x01\x0bB\x00!\x03 \x01\x10\x80\x80\x80\x80\x00!\x01\x0b \x00 \x037\x03\x00 \x00 \x017\x03\x08\x0b;\x00\x02@\x02@ \x01B\xff\xff\xff\xff\xff\xff\xff\xff\x00V\r\x00 \x01B\x08\x86B\x06\x84!\x01\x0c\x01\x0b \x01\x10\x81\x80\x80\x80\x00!\x01\x0b \x00B\x007\x03\x00 \x00 \x017\x03\x08\x0b\x8e\x01\x01\x01\x7f#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@\x02@\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08\"\x01 \x00|\"\x00 \x01T\r\x01 \x02 \x00\x10\x83\x80\x80\x80\x00 \x02(\x02\x00A\x01G\r\x02\x0b\x00\x0b\x10\x85\x80\x80\x80\x00\x00\x0b \x02)\x03\x08!\x00 \x02A\x10j$\x80\x80\x80\x80\x00 \x00\x0b\t\x00\x10\x88\x80\x80\x80\x00\x00\x0b\x9b\x01\x02\x01\x7f\x01~#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x03 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00A\x00-\x00\x80\x80\xc0\x80\x00\x1aB\x83\x80\x80\x80\x10!\x01\x02@ \x00 \x03|\"\x03 \x00T\r\x00 \x02 \x03\x10\x83\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x01 \x02)\x03\x08!\x01\x0b \x02A\x10j$\x80\x80\x80\x80\x00 \x01\x0f\x0b\x00\x0b\x9b\x01\x02\x01\x7f\x01~#\x80\x80\x80\x80\x00A\x10k\"\x02$\x80\x80\x80\x80\x00 \x02 \x00\x10\x82\x80\x80\x80\x00\x02@ \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x03 \x02 \x01\x10\x82\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x00 \x02)\x03\x08!\x00A\x00-\x00\x8e\x80\xc0\x80\x00\x1aB\x83\x80\x80\x80\x10!\x01\x02@ \x00 \x03|\"\x03 \x00T\r\x00 \x02 \x03\x10\x83\x80\x80\x80\x00 \x02(\x02\x00A\x01F\r\x01 \x02)\x03\x08!\x01\x0b \x02A\x10j$\x80\x80\x80\x80\x00 \x01\x0f\x0b\x00\x0b\x03\x00\x00\x0b\x0b%\x01\x00A\x80\x80\xc0\x00\x0b\x1cSpEcV1\xd6\xb8`\x15\xac\x9ei\x1aSpEcV1\x95\xd0j*\x1d\xfam\xa3\x00\xcb\x02\x0econtractspecv0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03add\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05Error\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x08Overflow\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07MyError\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x08Overflow\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08safe_add\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x03\xe9\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0csafe_add_two\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01a\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01b\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x03\xe9\x00\x00\x00\x06\x00\x00\x07\xd0\x00\x00\x00\x07MyError\x00\x00\x1e\x11contractenvmetav0\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00O\x0econtractmetav0\x00\x00\x00\x00\x00\x00\x00\x05rsver\x00\x00\x00\x00\x00\x00\x061.91.0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12rssdk_spec_shaking\x00\x00\x00\x00\x00\x012\x00\x00\x00"; pub trait Contract { fn add(env: soroban_sdk::Env, a: u64, b: u64) -> u64; + fn safe_add(env: soroban_sdk::Env, a: u64, b: u64) -> Result; + fn safe_add_two(env: soroban_sdk::Env, a: u64, b: u64) -> Result; } ///Client is a client for calling the contract defined in "Contract". pub struct Client<'a> { @@ -70,6 +72,84 @@ mod addcontract { ); res } + pub fn safe_add(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } + pub fn try_safe_add( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result< + u64, + >::Error, + >, + Result, + > { + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ + #[allow(deprecated)] + const SYMBOL: soroban_sdk::Symbol = soroban_sdk::Symbol::short("safe_add"); + SYMBOL + }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } + pub fn safe_add_two(&self, a: &u64, b: &u64) -> u64 { + use core::ops::Not; + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } + pub fn try_safe_add_two( + &self, + a: &u64, + b: &u64, + ) -> Result< + Result< + u64, + >::Error, + >, + Result, + > { + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [a.into_val(&self.env), b.into_val(&self.env)], + ), + ); + res + } } ///Args is a type for building arg lists for functions defined in "Contract". pub struct Args; @@ -79,6 +159,506 @@ mod addcontract { pub fn add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { (a, b) } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_two<'i>(a: &'i u64, b: &'i u64) -> (&'i u64, &'i u64) { + (a, b) + } + } + pub enum Error { + Overflow = 1, + } + #[automatically_derived] + impl ::core::fmt::Debug for Error { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } + } + #[automatically_derived] + impl ::core::marker::Copy for Error {} + #[automatically_derived] + impl ::core::clone::Clone for Error { + #[inline] + fn clone(&self) -> Error { + *self + } + } + #[automatically_derived] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + #[coverage(off)] + fn assert_receiver_is_total_eq(&self) -> () {} + } + #[automatically_derived] + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + true + } + } + #[automatically_derived] + impl ::core::cmp::Ord for Error { + #[inline] + fn cmp(&self, other: &Error) -> ::core::cmp::Ordering { + ::core::cmp::Ordering::Equal + } + } + #[automatically_derived] + impl ::core::cmp::PartialOrd for Error { + #[inline] + fn partial_cmp(&self, other: &Error) -> ::core::option::Option<::core::cmp::Ordering> { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } + } + #[link_section = "contractspecv0"] + pub static __SPEC_XDR_TYPE_ERROR: [u8; 48usize] = Error::spec_xdr(); + impl Error { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } + } + impl soroban_sdk::SpecShakingMarker for Error { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() { + { + static MARKER: [u8; 14usize] = *b"SpEcV1\xd6\xb8`\x15\xac\x9ei\x1a"; + let _ = unsafe { ::core::ptr::read_volatile(MARKER.as_ptr()) }; + } + } + } + impl TryFrom for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } + } + impl TryFrom<&soroban_sdk::Error> for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::Error { + <_ as From<&Error>>::from(&val) + } + } + impl From<&Error> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::Error { + match val { + Error::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } + } + impl TryFrom for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } + } + impl TryFrom<&soroban_sdk::InvokeError> for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::InvokeError { + <_ as From<&Error>>::from(&val) + } + } + impl From<&Error> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::InvokeError { + match val { + Error::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } + } + impl soroban_sdk::TryFromVal for Error { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &Error, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&Error, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } + } + pub enum MyError { + Overflow = 1, + } + #[automatically_derived] + impl ::core::fmt::Debug for MyError { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Overflow") + } + } + #[automatically_derived] + impl ::core::marker::Copy for MyError {} + #[automatically_derived] + impl ::core::clone::Clone for MyError { + #[inline] + fn clone(&self) -> MyError { + *self + } + } + #[automatically_derived] + impl ::core::cmp::Eq for MyError { + #[inline] + #[doc(hidden)] + #[coverage(off)] + fn assert_receiver_is_total_eq(&self) -> () {} + } + #[automatically_derived] + impl ::core::marker::StructuralPartialEq for MyError {} + #[automatically_derived] + impl ::core::cmp::PartialEq for MyError { + #[inline] + fn eq(&self, other: &MyError) -> bool { + true + } + } + #[automatically_derived] + impl ::core::cmp::Ord for MyError { + #[inline] + fn cmp(&self, other: &MyError) -> ::core::cmp::Ordering { + ::core::cmp::Ordering::Equal + } + } + #[automatically_derived] + impl ::core::cmp::PartialOrd for MyError { + #[inline] + fn partial_cmp(&self, other: &MyError) -> ::core::option::Option<::core::cmp::Ordering> { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } + } + #[link_section = "contractspecv0"] + pub static __SPEC_XDR_TYPE_MYERROR: [u8; 48usize] = MyError::spec_xdr(); + impl MyError { + pub const fn spec_xdr() -> [u8; 48usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x07MyError\0\0\0\0\x01\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } + } + impl soroban_sdk::SpecShakingMarker for MyError { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() { + { + static MARKER: [u8; 14usize] = *b"SpEcV1\x95\xd0j*\x1d\xfam\xa3"; + let _ = unsafe { ::core::ptr::read_volatile(MARKER.as_ptr()) }; + } + } + } + impl TryFrom for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } + } + impl TryFrom<&soroban_sdk::Error> for MyError { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::Error { + <_ as From<&MyError>>::from(&val) + } + } + impl From<&MyError> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::Error { + match val { + MyError::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } + } + impl TryFrom for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } + } + impl TryFrom<&soroban_sdk::InvokeError> for MyError { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } + } + impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: MyError) -> soroban_sdk::InvokeError { + <_ as From<&MyError>>::from(&val) + } + } + impl From<&MyError> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &MyError) -> soroban_sdk::InvokeError { + match val { + MyError::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } + } + impl soroban_sdk::TryFromVal for MyError { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &MyError, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } + } + impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&MyError, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) + } + } +} +pub enum Error { + Abort = 0, + Overflow = 1, +} +#[automatically_derived] +impl ::core::fmt::Debug for Error { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str( + f, + match self { + Error::Abort => "Abort", + Error::Overflow => "Overflow", + }, + ) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for Error {} +#[automatically_derived] +impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr + } +} +#[link_section = "contractspecv0"] +pub static __SPEC_XDR_TYPE_ERROR: [u8; 68usize] = Error::spec_xdr(); +impl Error { + pub const fn spec_xdr() -> [u8; 68usize] { + *b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x02\0\0\0\0\0\0\0\x05Abort\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08Overflow\0\0\0\x01" + } +} +impl soroban_sdk::SpecShakingMarker for Error { + #[doc(hidden)] + #[inline(always)] + fn spec_shaking_marker() { + { + static MARKER: [u8; 14usize] = *b"SpEcV1~\x83GNX\x9f\xc3\xfd"; + let _ = unsafe { ::core::ptr::read_volatile(MARKER.as_ptr()) }; + } + } +} +impl TryFrom for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: soroban_sdk::Error) -> Result { + if error.is_type(soroban_sdk::xdr::ScErrorType::Contract) { + let discriminant = error.get_code(); + Ok(match discriminant { + 0u32 => Self::Abort, + 1u32 => Self::Overflow, + _ => return Err(error), + }) + } else { + Err(error) + } + } +} +impl TryFrom<&soroban_sdk::Error> for Error { + type Error = soroban_sdk::Error; + #[inline(always)] + fn try_from(error: &soroban_sdk::Error) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::Error { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::Error { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::Error { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::Error { + match val { + Error::Abort => soroban_sdk::Error::from_contract_error(0u32), + Error::Overflow => soroban_sdk::Error::from_contract_error(1u32), + } + } +} +impl TryFrom for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: soroban_sdk::InvokeError) -> Result { + match error { + soroban_sdk::InvokeError::Abort => Err(error), + soroban_sdk::InvokeError::Contract(code) => Ok(match code { + 0u32 => Self::Abort, + 1u32 => Self::Overflow, + _ => return Err(error), + }), + } + } +} +impl TryFrom<&soroban_sdk::InvokeError> for Error { + type Error = soroban_sdk::InvokeError; + #[inline(always)] + fn try_from(error: &soroban_sdk::InvokeError) -> Result { + <_ as TryFrom>::try_from(*error) + } +} +impl From for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: Error) -> soroban_sdk::InvokeError { + <_ as From<&Error>>::from(&val) + } +} +impl From<&Error> for soroban_sdk::InvokeError { + #[inline(always)] + fn from(val: &Error) -> soroban_sdk::InvokeError { + match val { + Error::Abort => soroban_sdk::InvokeError::Contract(0u32), + Error::Overflow => soroban_sdk::InvokeError::Contract(1u32), + } + } +} +impl soroban_sdk::TryFromVal for Error { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &soroban_sdk::Val, + ) -> Result { + use soroban_sdk::TryIntoVal; + let error: soroban_sdk::Error = val.try_into_val(env)?; + error.try_into().map_err(|_| soroban_sdk::ConversionError) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &Error, + ) -> Result { + let error: soroban_sdk::Error = val.into(); + Ok(error.into()) + } +} +impl soroban_sdk::TryFromVal for soroban_sdk::Val { + type Error = soroban_sdk::ConversionError; + #[inline(always)] + fn try_from_val( + env: &soroban_sdk::Env, + val: &&Error, + ) -> Result { + <_ as soroban_sdk::TryFromVal>::try_from_val(env, *val) } } pub struct Contract; @@ -104,6 +684,20 @@ impl Contract { pub fn add_with(env: Env, contract_id: Address, x: u64, y: u64) -> u64 { addcontract::Client::new(&env, &contract_id).add(&x, &y) } + pub fn safe_add_with(env: Env, contract_id: Address, x: u64, y: u64) -> Result { + match addcontract::Client::new(&env, &contract_id).try_safe_add(&x, &y) { + Ok(Ok(i)) => Ok(i), + Err(Ok(addcontract::Error::Overflow)) => Err(Error::Overflow), + _ => Err(Error::Abort), + } + } + pub fn safe_add_with_two(env: Env, contract_id: Address, x: u64, y: u64) -> Result { + match addcontract::Client::new(&env, &contract_id).try_safe_add_two(&x, &y) { + Ok(Ok(i)) => Ok(i), + Err(Ok(addcontract::MyError::Overflow)) => Err(Error::Overflow), + _ => Err(Error::Abort), + } + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -120,6 +714,38 @@ impl Contract { *b"\0\0\0\0\0\0\0\0\0\0\0\x08add_with\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\0\x06" } } +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add_with__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + #[link_section = "contractspecv0"] + pub static __SPEC_XDR_FN_SAFE_ADD_WITH: [u8; 104usize] = + super::Contract::spec_xdr_safe_add_with(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add_with() -> [u8; 104usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\rsafe_add_with\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\0\x03" + } +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub mod __Contract__safe_add_with_two__spec { + #[doc(hidden)] + #[allow(non_snake_case)] + #[allow(non_upper_case_globals)] + #[link_section = "contractspecv0"] + pub static __SPEC_XDR_FN_SAFE_ADD_WITH_TWO: [u8; 108usize] = + super::Contract::spec_xdr_safe_add_with_two(); +} +impl Contract { + #[allow(non_snake_case)] + pub const fn spec_xdr_safe_add_with_two() -> [u8; 108usize] { + *b"\0\0\0\0\0\0\0\0\0\0\0\x11safe_add_with_two\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\x0bcontract_id\0\0\0\0\x13\0\0\0\0\0\0\0\x01x\0\0\0\0\0\0\x06\0\0\0\0\0\0\0\x01y\0\0\0\0\0\0\x06\0\0\0\x01\0\0\x03\xe9\0\0\0\x06\0\0\0\x03" + } +} impl<'a> ContractClient<'a> { pub fn add_with(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { use core::ops::Not; @@ -170,6 +796,88 @@ impl<'a> ContractClient<'a> { ); res } + pub fn safe_add_with(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { + use core::ops::Not; + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + res + } + pub fn try_safe_add_with( + &self, + contract_id: &Address, + x: &u64, + y: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + res + } + pub fn safe_add_with_two(&self, contract_id: &Address, x: &u64, y: &u64) -> u64 { + use core::ops::Not; + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + res + } + pub fn try_safe_add_with_two( + &self, + contract_id: &Address, + x: &u64, + y: &u64, + ) -> Result< + Result>::Error>, + Result, + > { + use soroban_sdk::{FromVal, IntoVal}; + let res = self.env.try_invoke_contract( + &self.address, + &{ soroban_sdk::Symbol::new(&self.env, "safe_add_with_two") }, + ::soroban_sdk::Vec::from_array( + &self.env, + [ + contract_id.into_val(&self.env), + x.into_val(&self.env), + y.into_val(&self.env), + ], + ), + ); + res + } } impl ContractArgs { #[inline(always)] @@ -181,6 +889,24 @@ impl ContractArgs { ) -> (&'i Address, &'i u64, &'i u64) { (contract_id, x, y) } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_with<'i>( + contract_id: &'i Address, + x: &'i u64, + y: &'i u64, + ) -> (&'i Address, &'i u64, &'i u64) { + (contract_id, x, y) + } + #[inline(always)] + #[allow(clippy::unused_unit)] + pub fn safe_add_with_two<'i>( + contract_id: &'i Address, + x: &'i u64, + y: &'i u64, + ) -> (&'i Address, &'i u64, &'i u64) { + (contract_id, x, y) + } } #[doc(hidden)] #[allow(non_snake_case)] @@ -229,3 +955,97 @@ pub extern "C" fn __Contract__add_with__invoke_raw_extern( #[allow(deprecated)] __Contract__add_with__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1, arg_2) } +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add_with__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add_with( + env.clone(), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_2), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with` instead")] +#[export_name = "safe_add_with"] +pub extern "C" fn __Contract__safe_add_with__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add_with__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1, arg_2) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with_two` instead")] +#[allow(deprecated)] +pub fn __Contract__safe_add_with_two__invoke_raw( + env: soroban_sdk::Env, + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + soroban_sdk::IntoValForContractFn::into_val_for_contract_fn( + ::safe_add_with_two( + env.clone(), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_0), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_1), + ), + <_ as soroban_sdk::unwrap::UnwrapOptimized>::unwrap_optimized( + <_ as soroban_sdk::TryFromValForContractFn< + soroban_sdk::Env, + soroban_sdk::Val, + >>::try_from_val_for_contract_fn(&env, &arg_2), + ), + ), + &env, + ) +} +#[doc(hidden)] +#[allow(non_snake_case)] +#[deprecated(note = "use `ContractClient::new(&env, &contract_id).safe_add_with_two` instead")] +#[export_name = "safe_add_with_two"] +pub extern "C" fn __Contract__safe_add_with_two__invoke_raw_extern( + arg_0: soroban_sdk::Val, + arg_1: soroban_sdk::Val, + arg_2: soroban_sdk::Val, +) -> soroban_sdk::Val { + #[allow(deprecated)] + __Contract__safe_add_with_two__invoke_raw(soroban_sdk::Env::default(), arg_0, arg_1, arg_2) +} diff --git a/tests/add_u64/src/lib.rs b/tests/add_u64/src/lib.rs index 78dc60692..0579b5dcc 100644 --- a/tests/add_u64/src/lib.rs +++ b/tests/add_u64/src/lib.rs @@ -1,21 +1,39 @@ #![no_std] -use soroban_sdk::{contract, contractimpl}; +use soroban_sdk::{contract, contracterror, contractimpl}; #[contract] pub struct Contract; +#[contracterror] +#[derive(Debug, PartialEq)] +pub enum Error { + Overflow = 1, +} + +#[contracterror] +#[derive(Debug, PartialEq)] +pub enum MyError { + Overflow = 1, +} + #[contractimpl] impl Contract { pub fn add(a: u64, b: u64) -> u64 { a + b } + pub fn safe_add(a: u64, b: u64) -> Result { + a.checked_add(b).ok_or(Error::Overflow) + } + pub fn safe_add_two(a: u64, b: u64) -> Result { + a.checked_add(b).ok_or(MyError::Overflow) + } } #[cfg(test)] mod test { use soroban_sdk::Env; - use crate::{Contract, ContractClient}; + use crate::{Contract, ContractClient, Error}; #[test] fn test_add() { @@ -28,4 +46,15 @@ mod test { let z = client.add(&x, &y); assert!(z == 22); } + #[test] + fn test_safe_add() { + let e = Env::default(); + let contract_id = e.register(Contract, ()); + let client = ContractClient::new(&e, &contract_id); + + let x = u64::MAX; + let y = 1; + let z = client.try_safe_add(&x, &y); + assert_eq!(z, Err(Ok(Error::Overflow))); + } } diff --git a/tests/add_u64/test_snapshots/test/test_safe_add.1.json b/tests/add_u64/test_snapshots/test/test_safe_add.1.json new file mode 100644 index 000000000..3a921a4b4 --- /dev/null +++ b/tests/add_u64/test_snapshots/test/test_safe_add.1.json @@ -0,0 +1,61 @@ +{ + "generators": { + "address": 1, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/tests/import_contract/src/lib.rs b/tests/import_contract/src/lib.rs index 33af0f5c6..3936fa269 100644 --- a/tests/import_contract/src/lib.rs +++ b/tests/import_contract/src/lib.rs @@ -1,10 +1,17 @@ #![no_std] -use soroban_sdk::{contract, contractimpl, Address, Env}; +use soroban_sdk::{contract, contracterror, contractimpl, Address, Env}; mod addcontract { soroban_sdk::contractimport!(file = "../../target/wasm32v1-none/release/test_add_u64.wasm"); } +#[contracterror] +#[derive(Debug, PartialEq)] +pub enum Error { + Abort = 0, + Overflow = 1, +} + #[contract] pub struct Contract; @@ -13,13 +20,27 @@ impl Contract { pub fn add_with(env: Env, contract_id: Address, x: u64, y: u64) -> u64 { addcontract::Client::new(&env, &contract_id).add(&x, &y) } + pub fn safe_add_with(env: Env, contract_id: Address, x: u64, y: u64) -> Result { + match addcontract::Client::new(&env, &contract_id).try_safe_add(&x, &y) { + Ok(Ok(i)) => Ok(i), + Err(Ok(addcontract::Error::Overflow)) => Err(Error::Overflow), + _ => Err(Error::Abort), + } + } + pub fn safe_add_with_two(env: Env, contract_id: Address, x: u64, y: u64) -> Result { + match addcontract::Client::new(&env, &contract_id).try_safe_add_two(&x, &y) { + Ok(Ok(i)) => Ok(i), + Err(Ok(addcontract::MyError::Overflow)) => Err(Error::Overflow), + _ => Err(Error::Abort), + } + } } #[cfg(test)] mod test { use soroban_sdk::Env; - use crate::{addcontract, Contract, ContractClient}; + use crate::{addcontract, Contract, ContractClient, Error}; #[test] fn test_add() { @@ -34,4 +55,20 @@ mod test { let z = client.add_with(&add_contract_id, &x, &y); assert!(z == 22); } + + #[test] + fn test_safe_add() { + let e = Env::default(); + let add_contract_id = e.register(addcontract::WASM, ()); + + let contract_id = e.register(Contract, ()); + let client = ContractClient::new(&e, &contract_id); + + let x = u64::MAX; + let y = 1; + let z = client.try_safe_add_with(&add_contract_id, &x, &y); + assert_eq!(z, Err(Ok(Error::Overflow))); + let z = client.try_safe_add_with_two(&add_contract_id, &x, &y); + assert_eq!(z, Err(Ok(Error::Overflow))); + } }