diff --git a/cli/Cargo.lock b/cli/Cargo.lock index d68ac31..70e9aed 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -2763,8 +2763,8 @@ dependencies = [ [[package]] name = "sdk-common" -version = "0.4.2-rc3" -source = "git+https://github.com/breez/breez-sdk?branch=main#8c27e8bf9bd438da411c7bfefd6a7fa10afa269e" +version = "0.5.0" +source = "git+https://github.com/breez/breez-sdk?branch=main#acadf5bfe616c5d1d119910ca8a876362b1cd969" dependencies = [ "aes 0.8.4", "anyhow", diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 68b4d7d..5748457 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -123,6 +123,10 @@ pub(crate) enum Command { LnurlPay { /// LN Address or LNURL-pay endpoint lnurl: String, + + /// Validates the success action URL + #[clap(name = "validate_success_url", short = 'v', long = "validate")] + validate_success_url: Option, }, LnurlWithdraw { /// LNURL-withdraw endpoint @@ -373,7 +377,10 @@ pub(crate) async fn handle_command( let res = LiquidSdk::parse(&input).await?; command_result!(res) } - Command::LnurlPay { lnurl } => { + Command::LnurlPay { + lnurl, + validate_success_url, + } => { let input = LiquidSdk::parse(&lnurl).await?; let res = match input { InputType::LnUrlPay { data: pd } => { @@ -389,6 +396,7 @@ pub(crate) async fn handle_command( amount_msat: amount_msat.parse::()?, comment: None, payment_label: None, + validate_success_action_url: validate_success_url, }) .await?; Ok(pay_res) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 9094c57..6754890 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -3084,8 +3084,8 @@ dependencies = [ [[package]] name = "sdk-common" -version = "0.4.2-rc3" -source = "git+https://github.com/breez/breez-sdk?branch=main#8c27e8bf9bd438da411c7bfefd6a7fa10afa269e" +version = "0.5.0" +source = "git+https://github.com/breez/breez-sdk?branch=main#acadf5bfe616c5d1d119910ca8a876362b1cd969" dependencies = [ "aes 0.8.4", "anyhow", diff --git a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h index 218eb71..fe7b420 100644 --- a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h +++ b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h @@ -83,6 +83,7 @@ typedef struct wire_cst_ln_url_pay_request { uint64_t amount_msat; struct wire_cst_list_prim_u_8_strict *comment; struct wire_cst_list_prim_u_8_strict *payment_label; + bool *validate_success_action_url; } wire_cst_ln_url_pay_request; typedef struct wire_cst_ln_url_withdraw_request_data { @@ -324,6 +325,7 @@ typedef struct wire_cst_SuccessActionProcessed_Message { typedef struct wire_cst_url_success_action_data { struct wire_cst_list_prim_u_8_strict *description; struct wire_cst_list_prim_u_8_strict *url; + bool matches_callback_domain; } wire_cst_url_success_action_data; typedef struct wire_cst_SuccessActionProcessed_Url { diff --git a/lib/bindings/src/breez_sdk_liquid.udl b/lib/bindings/src/breez_sdk_liquid.udl index c0cf304..393d16b 100644 --- a/lib/bindings/src/breez_sdk_liquid.udl +++ b/lib/bindings/src/breez_sdk_liquid.udl @@ -114,6 +114,7 @@ dictionary MessageSuccessActionData { dictionary UrlSuccessActionData { string description; string url; + boolean matches_callback_domain; }; dictionary LnUrlPayErrorData { @@ -126,6 +127,7 @@ dictionary LnUrlPayRequest { u64 amount_msat; string? comment = null; string? payment_label = null; + boolean? validate_success_action_url = null; }; [Error] diff --git a/lib/core/src/bindings.rs b/lib/core/src/bindings.rs index b460acc..a0c3683 100644 --- a/lib/core/src/bindings.rs +++ b/lib/core/src/bindings.rs @@ -341,6 +341,7 @@ pub struct _LnUrlPayRequest { pub amount_msat: u64, pub comment: Option, pub payment_label: Option, + pub validate_success_action_url: Option, } #[frb(mirror(SuccessActionProcessed))] @@ -371,6 +372,7 @@ pub struct _MessageSuccessActionData { pub struct _UrlSuccessActionData { pub description: String, pub url: String, + pub matches_callback_domain: bool, } #[frb(mirror(LnUrlPayErrorData))] diff --git a/lib/core/src/frb_generated.io.rs b/lib/core/src/frb_generated.io.rs index 5cc59dc..7629731 100644 --- a/lib/core/src/frb_generated.io.rs +++ b/lib/core/src/frb_generated.io.rs @@ -836,6 +836,7 @@ impl CstDecode for wire_cst_ln_url_pay_request amount_msat: self.amount_msat.cst_decode(), comment: self.comment.cst_decode(), payment_label: self.payment_label.cst_decode(), + validate_success_action_url: self.validate_success_action_url.cst_decode(), } } } @@ -1441,6 +1442,7 @@ impl CstDecode for wire_cst_url_success_a crate::bindings::UrlSuccessActionData { description: self.description.cst_decode(), url: self.url.cst_decode(), + matches_callback_domain: self.matches_callback_domain.cst_decode(), } } } @@ -1753,6 +1755,7 @@ impl NewWithNullPtr for wire_cst_ln_url_pay_request { amount_msat: Default::default(), comment: core::ptr::null_mut(), payment_label: core::ptr::null_mut(), + validate_success_action_url: core::ptr::null_mut(), } } } @@ -2326,6 +2329,7 @@ impl NewWithNullPtr for wire_cst_url_success_action_data { Self { description: core::ptr::null_mut(), url: core::ptr::null_mut(), + matches_callback_domain: Default::default(), } } } @@ -3445,6 +3449,7 @@ pub struct wire_cst_ln_url_pay_request { amount_msat: u64, comment: *mut wire_cst_list_prim_u_8_strict, payment_label: *mut wire_cst_list_prim_u_8_strict, + validate_success_action_url: *mut bool, } #[repr(C)] #[derive(Clone, Copy)] @@ -3940,4 +3945,5 @@ pub struct wire_cst_symbol { pub struct wire_cst_url_success_action_data { description: *mut wire_cst_list_prim_u_8_strict, url: *mut wire_cst_list_prim_u_8_strict, + matches_callback_domain: bool, } diff --git a/lib/core/src/frb_generated.rs b/lib/core/src/frb_generated.rs index 625efdf..7c3abe9 100644 --- a/lib/core/src/frb_generated.rs +++ b/lib/core/src/frb_generated.rs @@ -1577,6 +1577,7 @@ const _: fn() = || { let _: u64 = LnUrlPayRequest.amount_msat; let _: Option = LnUrlPayRequest.comment; let _: Option = LnUrlPayRequest.payment_label; + let _: Option = LnUrlPayRequest.validate_success_action_url; } { let LnUrlPayRequestData = None::.unwrap(); @@ -1660,6 +1661,7 @@ const _: fn() = || { let UrlSuccessActionData = None::.unwrap(); let _: String = UrlSuccessActionData.description; let _: String = UrlSuccessActionData.url; + let _: bool = UrlSuccessActionData.matches_callback_domain; } }; @@ -2425,11 +2427,13 @@ impl SseDecode for crate::bindings::LnUrlPayRequest { let mut var_amountMsat = ::sse_decode(deserializer); let mut var_comment = >::sse_decode(deserializer); let mut var_paymentLabel = >::sse_decode(deserializer); + let mut var_validateSuccessActionUrl = >::sse_decode(deserializer); return crate::bindings::LnUrlPayRequest { data: var_data, amount_msat: var_amountMsat, comment: var_comment, payment_label: var_paymentLabel, + validate_success_action_url: var_validateSuccessActionUrl, }; } } @@ -3352,9 +3356,11 @@ impl SseDecode for crate::bindings::UrlSuccessActionData { fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut var_description = ::sse_decode(deserializer); let mut var_url = ::sse_decode(deserializer); + let mut var_matchesCallbackDomain = ::sse_decode(deserializer); return crate::bindings::UrlSuccessActionData { description: var_description, url: var_url, + matches_callback_domain: var_matchesCallbackDomain, }; } } @@ -3958,6 +3964,10 @@ impl flutter_rust_bridge::IntoDart for FrbWrapper::sse_encode(self.amount_msat, serializer); >::sse_encode(self.comment, serializer); >::sse_encode(self.payment_label, serializer); + >::sse_encode(self.validate_success_action_url, serializer); } } @@ -6224,6 +6236,7 @@ impl SseEncode for crate::bindings::UrlSuccessActionData { fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.description, serializer); ::sse_encode(self.url, serializer); + ::sse_encode(self.matches_callback_domain, serializer); } } diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs index 921be81..c84a91a 100644 --- a/lib/core/src/sdk.rs +++ b/lib/core/src/sdk.rs @@ -1500,6 +1500,7 @@ impl LiquidSdk { &req.comment, &req.data, self.config.network.into(), + req.validate_success_action_url, ) .await? { diff --git a/packages/dart/lib/src/bindings.dart b/packages/dart/lib/src/bindings.dart index 2e029b0..13aa55e 100644 --- a/packages/dart/lib/src/bindings.dart +++ b/packages/dart/lib/src/bindings.dart @@ -394,16 +394,23 @@ class LnUrlPayRequest { final BigInt amountMsat; final String? comment; final String? paymentLabel; + final bool? validateSuccessActionUrl; const LnUrlPayRequest({ required this.data, required this.amountMsat, this.comment, this.paymentLabel, + this.validateSuccessActionUrl, }); @override - int get hashCode => data.hashCode ^ amountMsat.hashCode ^ comment.hashCode ^ paymentLabel.hashCode; + int get hashCode => + data.hashCode ^ + amountMsat.hashCode ^ + comment.hashCode ^ + paymentLabel.hashCode ^ + validateSuccessActionUrl.hashCode; @override bool operator ==(Object other) => @@ -413,7 +420,8 @@ class LnUrlPayRequest { data == other.data && amountMsat == other.amountMsat && comment == other.comment && - paymentLabel == other.paymentLabel; + paymentLabel == other.paymentLabel && + validateSuccessActionUrl == other.validateSuccessActionUrl; } class LnUrlPayRequestData { @@ -716,14 +724,16 @@ class Symbol { class UrlSuccessActionData { final String description; final String url; + final bool matchesCallbackDomain; const UrlSuccessActionData({ required this.description, required this.url, + required this.matchesCallbackDomain, }); @override - int get hashCode => description.hashCode ^ url.hashCode; + int get hashCode => description.hashCode ^ url.hashCode ^ matchesCallbackDomain.hashCode; @override bool operator ==(Object other) => @@ -731,5 +741,6 @@ class UrlSuccessActionData { other is UrlSuccessActionData && runtimeType == other.runtimeType && description == other.description && - url == other.url; + url == other.url && + matchesCallbackDomain == other.matchesCallbackDomain; } diff --git a/packages/dart/lib/src/frb_generated.dart b/packages/dart/lib/src/frb_generated.dart index fdc3ec5..eb3b8fe 100644 --- a/packages/dart/lib/src/frb_generated.dart +++ b/packages/dart/lib/src/frb_generated.dart @@ -1741,12 +1741,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { LnUrlPayRequest dco_decode_ln_url_pay_request(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs final arr = raw as List; - if (arr.length != 4) throw Exception('unexpected arr length: expect 4 but see ${arr.length}'); + if (arr.length != 5) throw Exception('unexpected arr length: expect 5 but see ${arr.length}'); return LnUrlPayRequest( data: dco_decode_ln_url_pay_request_data(arr[0]), amountMsat: dco_decode_u_64(arr[1]), comment: dco_decode_opt_String(arr[2]), paymentLabel: dco_decode_opt_String(arr[3]), + validateSuccessActionUrl: dco_decode_opt_box_autoadd_bool(arr[4]), ); } @@ -2463,10 +2464,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { UrlSuccessActionData dco_decode_url_success_action_data(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs final arr = raw as List; - if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); + if (arr.length != 3) throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); return UrlSuccessActionData( description: dco_decode_String(arr[0]), url: dco_decode_String(arr[1]), + matchesCallbackDomain: dco_decode_bool(arr[2]), ); } @@ -3245,8 +3247,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { var var_amountMsat = sse_decode_u_64(deserializer); var var_comment = sse_decode_opt_String(deserializer); var var_paymentLabel = sse_decode_opt_String(deserializer); + var var_validateSuccessActionUrl = sse_decode_opt_box_autoadd_bool(deserializer); return LnUrlPayRequest( - data: var_data, amountMsat: var_amountMsat, comment: var_comment, paymentLabel: var_paymentLabel); + data: var_data, + amountMsat: var_amountMsat, + comment: var_comment, + paymentLabel: var_paymentLabel, + validateSuccessActionUrl: var_validateSuccessActionUrl); } @protected @@ -3929,7 +3936,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { // Codec=Sse (Serialization based), see doc to use other codecs var var_description = sse_decode_String(deserializer); var var_url = sse_decode_String(deserializer); - return UrlSuccessActionData(description: var_description, url: var_url); + var var_matchesCallbackDomain = sse_decode_bool(deserializer); + return UrlSuccessActionData( + description: var_description, url: var_url, matchesCallbackDomain: var_matchesCallbackDomain); } @protected @@ -4715,6 +4724,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_u_64(self.amountMsat, serializer); sse_encode_opt_String(self.comment, serializer); sse_encode_opt_String(self.paymentLabel, serializer); + sse_encode_opt_box_autoadd_bool(self.validateSuccessActionUrl, serializer); } @protected @@ -5300,6 +5310,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_String(self.description, serializer); sse_encode_String(self.url, serializer); + sse_encode_bool(self.matchesCallbackDomain, serializer); } @protected diff --git a/packages/dart/lib/src/frb_generated.io.dart b/packages/dart/lib/src/frb_generated.io.dart index fa8c1e2..100199a 100644 --- a/packages/dart/lib/src/frb_generated.io.dart +++ b/packages/dart/lib/src/frb_generated.io.dart @@ -1922,6 +1922,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { wireObj.amount_msat = cst_encode_u_64(apiObj.amountMsat); wireObj.comment = cst_encode_opt_String(apiObj.comment); wireObj.payment_label = cst_encode_opt_String(apiObj.paymentLabel); + wireObj.validate_success_action_url = cst_encode_opt_box_autoadd_bool(apiObj.validateSuccessActionUrl); } @protected @@ -2450,6 +2451,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { UrlSuccessActionData apiObj, wire_cst_url_success_action_data wireObj) { wireObj.description = cst_encode_String(apiObj.description); wireObj.url = cst_encode_String(apiObj.url); + wireObj.matches_callback_domain = cst_encode_bool(apiObj.matchesCallbackDomain); } @protected @@ -4254,6 +4256,8 @@ final class wire_cst_ln_url_pay_request extends ffi.Struct { external ffi.Pointer comment; external ffi.Pointer payment_label; + + external ffi.Pointer validate_success_action_url; } final class wire_cst_ln_url_withdraw_request_data extends ffi.Struct { @@ -4601,6 +4605,9 @@ final class wire_cst_url_success_action_data extends ffi.Struct { external ffi.Pointer description; external ffi.Pointer url; + + @ffi.Bool() + external bool matches_callback_domain; } final class wire_cst_SuccessActionProcessed_Url extends ffi.Struct { diff --git a/packages/flutter/example/pubspec.lock b/packages/flutter/example/pubspec.lock index 2a42c83..2d1196e 100644 --- a/packages/flutter/example/pubspec.lock +++ b/packages/flutter/example/pubspec.lock @@ -218,10 +218,10 @@ packages: dependency: transitive description: name: freezed_annotation - sha256: f9f6597ac43cc262fa7d7f2e65259a6060c23a560525d1f2631be374540f2a9b + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.4" glob: dependency: transitive description: diff --git a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart index d984b13..c05f210 100644 --- a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart +++ b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart @@ -1396,6 +1396,8 @@ final class wire_cst_ln_url_pay_request extends ffi.Struct { external ffi.Pointer comment; external ffi.Pointer payment_label; + + external ffi.Pointer validate_success_action_url; } final class wire_cst_ln_url_withdraw_request_data extends ffi.Struct { @@ -1743,6 +1745,9 @@ final class wire_cst_url_success_action_data extends ffi.Struct { external ffi.Pointer description; external ffi.Pointer url; + + @ffi.Bool() + external bool matches_callback_domain; } final class wire_cst_SuccessActionProcessed_Url extends ffi.Struct { diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt index 8ef0d17..4ae7538 100644 --- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt +++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt @@ -684,11 +684,22 @@ fun asLnUrlPayRequest(lnUrlPayRequest: ReadableMap): LnUrlPayRequest? { val amountMsat = lnUrlPayRequest.getDouble("amountMsat").toULong() val comment = if (hasNonNullKey(lnUrlPayRequest, "comment")) lnUrlPayRequest.getString("comment") else null val paymentLabel = if (hasNonNullKey(lnUrlPayRequest, "paymentLabel")) lnUrlPayRequest.getString("paymentLabel") else null + val validateSuccessActionUrl = + if (hasNonNullKey( + lnUrlPayRequest, + "validateSuccessActionUrl", + ) + ) { + lnUrlPayRequest.getBoolean("validateSuccessActionUrl") + } else { + null + } return LnUrlPayRequest( data, amountMsat, comment, paymentLabel, + validateSuccessActionUrl, ) } @@ -698,6 +709,7 @@ fun readableMapOf(lnUrlPayRequest: LnUrlPayRequest): ReadableMap = "amountMsat" to lnUrlPayRequest.amountMsat, "comment" to lnUrlPayRequest.comment, "paymentLabel" to lnUrlPayRequest.paymentLabel, + "validateSuccessActionUrl" to lnUrlPayRequest.validateSuccessActionUrl, ) fun asLnUrlPayRequestList(arr: ReadableArray): List { @@ -2043,6 +2055,7 @@ fun asUrlSuccessActionData(urlSuccessActionData: ReadableMap): UrlSuccessActionD arrayOf( "description", "url", + "matchesCallbackDomain", ), ) ) { @@ -2050,9 +2063,11 @@ fun asUrlSuccessActionData(urlSuccessActionData: ReadableMap): UrlSuccessActionD } val description = urlSuccessActionData.getString("description")!! val url = urlSuccessActionData.getString("url")!! + val matchesCallbackDomain = urlSuccessActionData.getBoolean("matchesCallbackDomain") return UrlSuccessActionData( description, url, + matchesCallbackDomain, ) } @@ -2060,6 +2075,7 @@ fun readableMapOf(urlSuccessActionData: UrlSuccessActionData): ReadableMap = readableMapOf( "description" to urlSuccessActionData.description, "url" to urlSuccessActionData.url, + "matchesCallbackDomain" to urlSuccessActionData.matchesCallbackDomain, ) fun asUrlSuccessActionDataList(arr: ReadableArray): List { diff --git a/packages/react-native/ios/BreezSDKLiquidMapper.swift b/packages/react-native/ios/BreezSDKLiquidMapper.swift index 2d8c110..01d9d16 100644 --- a/packages/react-native/ios/BreezSDKLiquidMapper.swift +++ b/packages/react-native/ios/BreezSDKLiquidMapper.swift @@ -822,12 +822,20 @@ enum BreezSDKLiquidMapper { } paymentLabel = paymentLabelTmp } + var validateSuccessActionUrl: Bool? + if hasNonNilKey(data: lnUrlPayRequest, key: "validateSuccessActionUrl") { + guard let validateSuccessActionUrlTmp = lnUrlPayRequest["validateSuccessActionUrl"] as? Bool else { + throw SdkError.Generic(message: errUnexpectedValue(fieldName: "validateSuccessActionUrl")) + } + validateSuccessActionUrl = validateSuccessActionUrlTmp + } return LnUrlPayRequest( data: data, amountMsat: amountMsat, comment: comment, - paymentLabel: paymentLabel + paymentLabel: paymentLabel, + validateSuccessActionUrl: validateSuccessActionUrl ) } @@ -837,6 +845,7 @@ enum BreezSDKLiquidMapper { "amountMsat": lnUrlPayRequest.amountMsat, "comment": lnUrlPayRequest.comment == nil ? nil : lnUrlPayRequest.comment, "paymentLabel": lnUrlPayRequest.paymentLabel == nil ? nil : lnUrlPayRequest.paymentLabel, + "validateSuccessActionUrl": lnUrlPayRequest.validateSuccessActionUrl == nil ? nil : lnUrlPayRequest.validateSuccessActionUrl, ] } @@ -2375,10 +2384,14 @@ enum BreezSDKLiquidMapper { guard let url = urlSuccessActionData["url"] as? String else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "url", typeName: "UrlSuccessActionData")) } + guard let matchesCallbackDomain = urlSuccessActionData["matchesCallbackDomain"] as? Bool else { + throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "matchesCallbackDomain", typeName: "UrlSuccessActionData")) + } return UrlSuccessActionData( description: description, - url: url + url: url, + matchesCallbackDomain: matchesCallbackDomain ) } @@ -2386,6 +2399,7 @@ enum BreezSDKLiquidMapper { return [ "description": urlSuccessActionData.description, "url": urlSuccessActionData.url, + "matchesCallbackDomain": urlSuccessActionData.matchesCallbackDomain, ] } diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index 45c9bc2..f773ba6 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -129,6 +129,7 @@ export interface LnUrlPayRequest { amountMsat: number comment?: string paymentLabel?: string + validateSuccessActionUrl?: boolean } export interface LnUrlPayRequestData { @@ -331,6 +332,7 @@ export interface SymbolType { export interface UrlSuccessActionData { description: string url: string + matchesCallbackDomain: boolean } export enum AesSuccessActionDataResultVariant {