diff --git a/android/truapi-host/src/main/kotlin/io/parity/truapi/TrUAPIHost.kt b/android/truapi-host/src/main/kotlin/io/parity/truapi/TrUAPIHost.kt index 8b1704e54..91ac870fe 100644 --- a/android/truapi-host/src/main/kotlin/io/parity/truapi/TrUAPIHost.kt +++ b/android/truapi-host/src/main/kotlin/io/parity/truapi/TrUAPIHost.kt @@ -32,6 +32,7 @@ import uniffi.truapi.HostPushNotificationRequest import uniffi.truapi.RemotePermission import uniffi.truapi.ThemeVariant import uniffi.truapi_platform.AuthState +import uniffi.truapi_platform.HostChainSet import uniffi.truapi_platform.PermissionAuthorizationRequest import uniffi.truapi_platform.PermissionAuthorizationStatus import uniffi.truapi_platform.UserConfirmationReview @@ -302,6 +303,13 @@ interface HostBridge { @Throws(HostRejection::class) suspend fun featureSupported(request: HostFeatureSupportedRequest): Boolean + /** + * Enumerate the chains this host serves: its environment plus one entry + * per chain role. Must match exactly what [chainConnect] accepts. + */ + @Throws(HostRejection::class) + fun supportedChains(): HostChainSet = HostChainSet(network = "", chains = emptyList()) + /** Product-scoped key-value storage for the Rust core. */ val storage: HostStorage @@ -366,6 +374,9 @@ private class HostCallbackAdapter(private val bridge: HostBridge) : HostCallback override suspend fun featureSupported(request: HostFeatureSupportedRequest): Boolean = bridge.featureSupported(request) + override fun supportedChains(): HostChainSet = + bridge.supportedChains() + override fun localStorageRead(key: String): ByteArray? = bridge.storage.read(key) diff --git a/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift b/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift index 71182712a..0add372c7 100644 --- a/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift +++ b/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift @@ -402,6 +402,11 @@ public protocol HostBridge: AnyObject, Sendable { /// return promptly. func featureSupported(request: HostFeatureSupportedRequest) async throws -> Bool + /// Enumerate the chains this host serves: its environment plus one entry + /// per chain role. Must match exactly what ``chainConnect(genesisHash:)`` + /// accepts. Invoked on the dispatcher thread; must return promptly. + func supportedChains() throws -> HostChainSet + /// Scoped key-value storage for the Rust core. var storage: HostStorageBackend { get } @@ -445,6 +450,7 @@ public extension HostBridge { func confirmUserAction(review: UserConfirmationReview) async throws -> Bool { false } func lookupPreimage(key: Data) async throws -> Data? { nil } func currentTheme() throws -> ThemeVariant { .dark } + func supportedChains() throws -> HostChainSet { HostChainSet(network: "", chains: []) } } /// Adapter that bridges the public `ChatHostBridge` to the generated UniFFI @@ -609,6 +615,12 @@ private final class HostCallbackAdapter: HostCallbacks, @unchecked Sendable { } } + func supportedChains() throws -> HostChainSet { + try withHostRejection { + try bridge.supportedChains() + } + } + func localStorageRead(key: String) throws -> Data? { try withStorageError { try bridge.storage.read(key: key) diff --git a/ios/truapi-host/Sources/TrUAPIHost/truapi.swift b/ios/truapi-host/Sources/TrUAPIHost/truapi.swift index f889b39d0..d1dd8b802 100644 --- a/ios/truapi-host/Sources/TrUAPIHost/truapi.swift +++ b/ios/truapi-host/Sources/TrUAPIHost/truapi.swift @@ -3688,6 +3688,101 @@ public func FfiConverterTypeButtonVariant_lower(_ value: ButtonVariant) -> RustB +/** + * Role of a chain within the host's configured environment. + */ + +public enum ChainIdentifier: Equatable, Hashable { + + /** + * The relay chain. + */ + case relay + /** + * The asset hub system chain. + */ + case assetHub + /** + * The people chain. + */ + case people + /** + * The bulletin chain. + */ + case bulletin + + + + + +} + +#if compiler(>=6) +extension ChainIdentifier: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeChainIdentifier: FfiConverterRustBuffer { + typealias SwiftType = ChainIdentifier + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChainIdentifier { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .relay + + case 2: return .assetHub + + case 3: return .people + + case 4: return .bulletin + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ChainIdentifier, into buf: inout [UInt8]) { + switch value { + + + case .relay: + writeInt(&buf, Int32(1)) + + + case .assetHub: + writeInt(&buf, Int32(2)) + + + case .people: + writeInt(&buf, Int32(3)) + + + case .bulletin: + writeInt(&buf, Int32(4)) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeChainIdentifier_lift(_ buf: RustBuffer) throws -> ChainIdentifier { + return try FfiConverterTypeChainIdentifier.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeChainIdentifier_lower(_ value: ChainIdentifier) -> RustBuffer { + return FfiConverterTypeChainIdentifier.lower(value) +} + + + /** * Layout for action buttons. */ diff --git a/ios/truapi-host/Sources/TrUAPIHost/truapi_platform.swift b/ios/truapi-host/Sources/TrUAPIHost/truapi_platform.swift index d2aace538..d15683af4 100644 --- a/ios/truapi-host/Sources/TrUAPIHost/truapi_platform.swift +++ b/ios/truapi-host/Sources/TrUAPIHost/truapi_platform.swift @@ -780,6 +780,145 @@ public func FfiConverterTypeCreateProofReview_lower(_ value: CreateProofReview) } +/** + * One chain a host serves: a protocol chain role mapped to the concrete + * chain of the host's configured environment. + */ +public struct HostChainEntry: Equatable, Hashable { + /** + * Protocol role this entry answers for. + */ + public var identifier: ChainIdentifier + /** + * Genesis hash identifying the chain in all chain-scoped calls. + */ + public var genesisHash: Bytes32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Protocol role this entry answers for. + */identifier: ChainIdentifier, + /** + * Genesis hash identifying the chain in all chain-scoped calls. + */genesisHash: Bytes32) { + self.identifier = identifier + self.genesisHash = genesisHash + } + + + + +} + +#if compiler(>=6) +extension HostChainEntry: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeHostChainEntry: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> HostChainEntry { + return + try HostChainEntry( + identifier: FfiConverterTypeChainIdentifier.read(from: &buf), + genesisHash: FfiConverterTypeBytes32.read(from: &buf) + ) + } + + public static func write(_ value: HostChainEntry, into buf: inout [UInt8]) { + FfiConverterTypeChainIdentifier.write(value.identifier, into: &buf) + FfiConverterTypeBytes32.write(value.genesisHash, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeHostChainEntry_lift(_ buf: RustBuffer) throws -> HostChainEntry { + return try FfiConverterTypeHostChainEntry.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeHostChainEntry_lower(_ value: HostChainEntry) -> RustBuffer { + return FfiConverterTypeHostChainEntry.lower(value) +} + + +/** + * The chain set a host serves: its environment plus one entry per chain role. + */ +public struct HostChainSet: Equatable, Hashable { + /** + * Ecosystem the host is configured for, e.g. "polkadot", "paseo". + */ + public var network: String + /** + * Complete set of chains available through this host. + */ + public var chains: [HostChainEntry] + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Ecosystem the host is configured for, e.g. "polkadot", "paseo". + */network: String, + /** + * Complete set of chains available through this host. + */chains: [HostChainEntry]) { + self.network = network + self.chains = chains + } + + + + +} + +#if compiler(>=6) +extension HostChainSet: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeHostChainSet: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> HostChainSet { + return + try HostChainSet( + network: FfiConverterString.read(from: &buf), + chains: FfiConverterSequenceTypeHostChainEntry.read(from: &buf) + ) + } + + public static func write(_ value: HostChainSet, into buf: inout [UInt8]) { + FfiConverterString.write(value.network, into: &buf) + FfiConverterSequenceTypeHostChainEntry.write(value.chains, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeHostChainSet_lift(_ buf: RustBuffer) throws -> HostChainSet { + return try FfiConverterTypeHostChainSet.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeHostChainSet_lower(_ value: HostChainSet) -> RustBuffer { + return FfiConverterTypeHostChainSet.lower(value) +} + + /** * Review shown before a product learns the user's primary identity. */ @@ -2085,6 +2224,31 @@ fileprivate struct FfiConverterOptionTypeBytes32: FfiConverterRustBuffer { } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeHostChainEntry: FfiConverterRustBuffer { + typealias SwiftType = [HostChainEntry] + + public static func write(_ value: [HostChainEntry], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeHostChainEntry.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [HostChainEntry] { + let len: Int32 = try readInt(&buf) + var seq = [HostChainEntry]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeHostChainEntry.read(from: &buf)) + } + return seq + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif diff --git a/ios/truapi-host/Sources/TrUAPIHost/truapi_server.swift b/ios/truapi-host/Sources/TrUAPIHost/truapi_server.swift index 51ddd36ac..171ea91ff 100644 --- a/ios/truapi-host/Sources/TrUAPIHost/truapi_server.swift +++ b/ios/truapi-host/Sources/TrUAPIHost/truapi_server.swift @@ -723,6 +723,14 @@ public protocol HostCallbacks: AnyObject, Sendable { */ func featureSupported(request: HostFeatureSupportedRequest) async throws -> Bool + /** + * Enumerate the chains this host serves (RFC 0026): its environment plus + * one entry per chain role. The returned set must match exactly what + * `chain_connect` will accept. Invoked on the dispatcher thread; must + * return promptly. + */ + func supportedChains() throws -> HostChainSet + /** * Read a value from the host's scoped key-value store. */ @@ -1079,6 +1087,21 @@ open func featureSupported(request: HostFeatureSupportedRequest)async throws -> ) } + /** + * Enumerate the chains this host serves (RFC 0026): its environment plus + * one entry per chain role. The returned set must match exactly what + * `chain_connect` will accept. Invoked on the dispatcher thread; must + * return promptly. + */ +open func supportedChains()throws -> HostChainSet { + return try FfiConverterTypeHostChainSet_lift(try rustCallWithError(FfiConverterTypeHostRejection_lift) { + uniffiCallStatus in + uniffi_truapi_server_fn_method_hostcallbacks_supported_chains( + self.uniffiCloneHandle(),uniffiCallStatus + ) +}) +} + /** * Read a value from the host's scoped key-value store. */ @@ -1696,6 +1719,29 @@ fileprivate struct UniffiCallbackInterfaceHostCallbacks { droppedCallback: uniffiOutDroppedCallback ) }, + supportedChains: { ( + uniffiHandle: UInt64, + uniffiOutReturn: UnsafeMutablePointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws -> HostChainSet in + guard let uniffiObj = try? FfiConverterTypeHostCallbacks.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return try uniffiObj.supportedChains( + ) + } + + + let writeReturn = { uniffiOutReturn.pointee = FfiConverterTypeHostChainSet_lower($0) } + uniffiTraitInterfaceCallWithError( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn, + lowerError: FfiConverterTypeHostRejection_lower + ) + }, localStorageRead: { ( uniffiHandle: UInt64, key: RustBuffer, @@ -5173,13 +5219,16 @@ private let initializationResult: InitializationResult = { if (uniffi_truapi_server_checksum_method_hostcallbacks_feature_supported() != 46490) { return InitializationResult.apiChecksumMismatch } - if (uniffi_truapi_server_checksum_method_hostcallbacks_local_storage_read() != 54709) { + if (uniffi_truapi_server_checksum_method_hostcallbacks_supported_chains() != 23356) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_truapi_server_checksum_method_hostcallbacks_local_storage_read() != 32804) { return InitializationResult.apiChecksumMismatch } - if (uniffi_truapi_server_checksum_method_hostcallbacks_local_storage_write() != 33044) { + if (uniffi_truapi_server_checksum_method_hostcallbacks_local_storage_write() != 62222) { return InitializationResult.apiChecksumMismatch } - if (uniffi_truapi_server_checksum_method_hostcallbacks_local_storage_clear() != 6971) { + if (uniffi_truapi_server_checksum_method_hostcallbacks_local_storage_clear() != 61208) { return InitializationResult.apiChecksumMismatch } if (uniffi_truapi_server_checksum_method_nativechatcallbacks_create_room() != 15676) { diff --git a/ios/truapi-host/Sources/truapi_serverFFI/include/truapi_serverFFI.h b/ios/truapi-host/Sources/truapi_serverFFI/include/truapi_serverFFI.h index e867eb575..40224ac8a 100644 --- a/ios/truapi-host/Sources/truapi_serverFFI/include/truapi_serverFFI.h +++ b/ios/truapi-host/Sources/truapi_serverFFI/include/truapi_serverFFI.h @@ -371,21 +371,28 @@ typedef void (*UniffiCallbackInterfaceHostCallbacksMethod16)(uint64_t, RustBuffe #endif #ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD17 #define UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD17 -typedef void (*UniffiCallbackInterfaceHostCallbacksMethod17)(uint64_t, RustBuffer, RustBuffer* _Nonnull, +typedef void (*UniffiCallbackInterfaceHostCallbacksMethod17)(uint64_t, RustBuffer* _Nonnull, RustCallStatus *_Nonnull uniffiCallStatus ); #endif #ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD18 #define UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD18 -typedef void (*UniffiCallbackInterfaceHostCallbacksMethod18)(uint64_t, RustBuffer, RustBuffer, void* _Nonnull, +typedef void (*UniffiCallbackInterfaceHostCallbacksMethod18)(uint64_t, RustBuffer, RustBuffer* _Nonnull, RustCallStatus *_Nonnull uniffiCallStatus ); #endif #ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD19 #define UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD19 -typedef void (*UniffiCallbackInterfaceHostCallbacksMethod19)(uint64_t, RustBuffer, void* _Nonnull, +typedef void (*UniffiCallbackInterfaceHostCallbacksMethod19)(uint64_t, RustBuffer, RustBuffer, void* _Nonnull, + RustCallStatus *_Nonnull uniffiCallStatus + ); + +#endif +#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD20 +#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_HOST_CALLBACKS_METHOD20 +typedef void (*UniffiCallbackInterfaceHostCallbacksMethod20)(uint64_t, RustBuffer, void* _Nonnull, RustCallStatus *_Nonnull uniffiCallStatus ); @@ -450,9 +457,10 @@ typedef struct UniffiVTableCallbackInterfaceHostCallbacks { UniffiCallbackInterfaceHostCallbacksMethod14 _Nonnull lookupPreimage; UniffiCallbackInterfaceHostCallbacksMethod15 _Nonnull currentTheme; UniffiCallbackInterfaceHostCallbacksMethod16 _Nonnull featureSupported; - UniffiCallbackInterfaceHostCallbacksMethod17 _Nonnull localStorageRead; - UniffiCallbackInterfaceHostCallbacksMethod18 _Nonnull localStorageWrite; - UniffiCallbackInterfaceHostCallbacksMethod19 _Nonnull localStorageClear; + UniffiCallbackInterfaceHostCallbacksMethod17 _Nonnull supportedChains; + UniffiCallbackInterfaceHostCallbacksMethod18 _Nonnull localStorageRead; + UniffiCallbackInterfaceHostCallbacksMethod19 _Nonnull localStorageWrite; + UniffiCallbackInterfaceHostCallbacksMethod20 _Nonnull localStorageClear; } UniffiVTableCallbackInterfaceHostCallbacks; #endif @@ -568,6 +576,11 @@ RustBuffer uniffi_truapi_server_fn_method_hostcallbacks_current_theme(uint64_t p uint64_t uniffi_truapi_server_fn_method_hostcallbacks_feature_supported(uint64_t ptr, RustBuffer request ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_FN_METHOD_HOSTCALLBACKS_SUPPORTED_CHAINS +#define UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_FN_METHOD_HOSTCALLBACKS_SUPPORTED_CHAINS +RustBuffer uniffi_truapi_server_fn_method_hostcallbacks_supported_chains(uint64_t ptr, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_FN_METHOD_HOSTCALLBACKS_LOCAL_STORAGE_READ #define UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_FN_METHOD_HOSTCALLBACKS_LOCAL_STORAGE_READ RustBuffer uniffi_truapi_server_fn_method_hostcallbacks_local_storage_read(uint64_t ptr, RustBuffer key, RustCallStatus *_Nonnull out_status @@ -1205,6 +1218,12 @@ uint16_t uniffi_truapi_server_checksum_method_hostcallbacks_current_theme(void #define UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_CHECKSUM_METHOD_HOSTCALLBACKS_FEATURE_SUPPORTED uint16_t uniffi_truapi_server_checksum_method_hostcallbacks_feature_supported(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_CHECKSUM_METHOD_HOSTCALLBACKS_SUPPORTED_CHAINS +#define UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_CHECKSUM_METHOD_HOSTCALLBACKS_SUPPORTED_CHAINS +uint16_t uniffi_truapi_server_checksum_method_hostcallbacks_supported_chains(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_TRUAPI_SERVER_CHECKSUM_METHOD_HOSTCALLBACKS_LOCAL_STORAGE_READ diff --git a/js/packages/truapi-host/src/test-support.ts b/js/packages/truapi-host/src/test-support.ts index 6964e2e46..c479cdc25 100644 --- a/js/packages/truapi-host/src/test-support.ts +++ b/js/packages/truapi-host/src/test-support.ts @@ -21,7 +21,10 @@ export function makeHostCallbacks( devicePermission: async () => ({ granted: false }), remotePermission: async () => ({ granted: false }), }, - features: { featureSupported: async () => ({ supported: false }) }, + features: { + featureSupported: async () => ({ supported: false }), + supportedChains: async () => ({ network: "paseo", chains: [] }), + }, productStorage: { read: async () => undefined, write: async () => {}, diff --git a/rust/crates/truapi-codegen/tests/golden/host-callbacks-adapter.ts b/rust/crates/truapi-codegen/tests/golden/host-callbacks-adapter.ts index 4a6ff49d5..54b57927f 100644 --- a/rust/crates/truapi-codegen/tests/golden/host-callbacks-adapter.ts +++ b/rust/crates/truapi-codegen/tests/golden/host-callbacks-adapter.ts @@ -20,6 +20,7 @@ import type { GenericError, NotificationId } from "@parity/truapi"; import { AuthState, CoreStorageKey, + HostChainSet, UserConfirmationReview, } from "./host-callbacks.js"; import type { RequiredHostCallbacks } from "./host-callbacks.js"; @@ -34,6 +35,7 @@ export interface RawCallbacks { writeCoreStorage(key: Uint8Array, value: Uint8Array): Promise; clearCoreStorage(key: Uint8Array): Promise; featureSupported(request: Uint8Array): Promise; + supportedChains(): Promise; navigateTo(url: string): Promise; pushNotification(notification: Uint8Array): Promise; cancelNotification(id: NotificationId): Promise; @@ -77,6 +79,8 @@ export function createWasmRawCallbacks( HostFeatureSupportedRequest.dec(request), ), ), + supportedChains: async () => + HostChainSet.enc(await callbacks.features.supportedChains()), navigateTo: async (url) => await callbacks.navigation.navigateTo(url), pushNotification: async (notification) => HostPushNotificationResponse.enc( diff --git a/rust/crates/truapi-codegen/tests/golden/host-callbacks.ts b/rust/crates/truapi-codegen/tests/golden/host-callbacks.ts index 59d01a548..fb12921f5 100644 --- a/rust/crates/truapi-codegen/tests/golden/host-callbacks.ts +++ b/rust/crates/truapi-codegen/tests/golden/host-callbacks.ts @@ -9,6 +9,7 @@ import * as S from "@parity/truapi/scale"; import { AllocatableResource, Bytes32, + ChainIdentifier, HostAccountSignVrfRequest, HostDevicePermissionRequest, HostSignPayloadRequest, @@ -186,6 +187,37 @@ export type CreateTransactionReview = */ | { tag: "LegacyAccount"; value: LegacyAccountTxPayload }; +/** + * One chain a host serves: a protocol chain role mapped to the concrete + * chain of the host's configured environment. + */ +export interface HostChainEntry { + /** + * Protocol role this entry answers for. + */ + identifier: ChainIdentifier; + + /** + * Genesis hash identifying the chain in all chain-scoped calls. + */ + genesisHash: Bytes32; +} + +/** + * The chain set a host serves: its environment plus one entry per chain role. + */ +export interface HostChainSet { + /** + * Ecosystem the host is configured for, e.g. "polkadot", "paseo". + */ + network: string; + + /** + * Complete set of chains available through this host. + */ + chains: Array; +} + /** * Review shown before a product learns the user's primary identity. */ @@ -510,6 +542,29 @@ export const CreateTransactionReview: S.Codec = S.lazy( }), ); +/** + * One chain a host serves: a protocol chain role mapped to the concrete + * chain of the host's configured environment. + */ +export const HostChainEntry: S.Codec = S.lazy( + (): S.Codec => + S.Struct({ + identifier: ChainIdentifier, + genesisHash: Bytes32, + }) as S.Codec, +); + +/** + * The chain set a host serves: its environment plus one entry per chain role. + */ +export const HostChainSet: S.Codec = S.lazy( + (): S.Codec => + S.Struct({ + network: S.str, + chains: S.Vector(HostChainEntry), + }) as S.Codec, +); + /** * Review shown before a product learns the user's primary identity. */ @@ -801,6 +856,13 @@ export interface Features { featureSupported( request: HostFeatureSupportedRequest, ): Promise; + + /** + * Enumerate the chains this host serves (RFC 0026). The returned set must + * match exactly what `ChainProvider::connect` will accept; the core + * resolves `get_chain_info` requests against it. + */ + supportedChains(): Promise; } /** diff --git a/rust/crates/truapi-codegen/tests/golden/wasm_bridge.rs b/rust/crates/truapi-codegen/tests/golden/wasm_bridge.rs index c08a48688..322f3068e 100644 --- a/rust/crates/truapi-codegen/tests/golden/wasm_bridge.rs +++ b/rust/crates/truapi-codegen/tests/golden/wasm_bridge.rs @@ -27,6 +27,7 @@ pub(super) struct JsBridge { pub(super) write_core_storage: Function, pub(super) clear_core_storage: Function, pub(super) feature_supported: Function, + pub(super) supported_chains: Function, pub(super) navigate_to: Function, pub(super) push_notification: Function, pub(super) cancel_notification: Function, @@ -49,6 +50,7 @@ impl JsBridge { write_core_storage: get_function(callbacks, "writeCoreStorage")?, clear_core_storage: get_function(callbacks, "clearCoreStorage")?, feature_supported: get_function(callbacks, "featureSupported")?, + supported_chains: get_function(callbacks, "supportedChains")?, navigate_to: get_function(callbacks, "navigateTo")?, push_notification: get_function(callbacks, "pushNotification")?, cancel_notification: get_function(callbacks, "cancelNotification")?, @@ -137,6 +139,17 @@ impl truapi_platform::Features for WasmPlatform { ) .map_err(generic) } + + async fn supported_chains(&self) -> Result { + let bytes = invoke_bytes_return(&self.bridge.supported_chains, Vec::new()) + .await + .map_err(generic)?; + decode_bytes::( + bytes, + "supportedChains response did not decode", + ) + .map_err(generic) + } } #[truapi_platform::async_trait] diff --git a/rust/crates/truapi-codegen/tests/golden/worker-callbacks.ts b/rust/crates/truapi-codegen/tests/golden/worker-callbacks.ts index 5ce66c4ae..baa79b3b4 100644 --- a/rust/crates/truapi-codegen/tests/golden/worker-callbacks.ts +++ b/rust/crates/truapi-codegen/tests/golden/worker-callbacks.ts @@ -16,6 +16,7 @@ export const CALLBACK_NAMES = [ "writeCoreStorage", "clearCoreStorage", "featureSupported", + "supportedChains", "navigateTo", "pushNotification", "cancelNotification", @@ -67,6 +68,10 @@ function rawCallbacks( bridge.callbackRequest("featureSupported", [request]) as ReturnType< RawCallbacks["featureSupported"] >, + supportedChains: () => + bridge.callbackRequest("supportedChains", []) as ReturnType< + RawCallbacks["supportedChains"] + >, navigateTo: (url) => bridge.callbackRequest("navigateTo", [url]) as ReturnType< RawCallbacks["navigateTo"] diff --git a/rust/crates/truapi-host-cli/src/platform.rs b/rust/crates/truapi-host-cli/src/platform.rs index 6894e72de..121ac8c52 100644 --- a/rust/crates/truapi-host-cli/src/platform.rs +++ b/rust/crates/truapi-host-cli/src/platform.rs @@ -612,6 +612,12 @@ impl Features for CliPlatform { ) -> Result { Ok(api::HostFeatureSupportedResponse { supported: false }) } + + async fn supported_chains(&self) -> Result { + Err(api::GenericError { + reason: "the CLI host serves no product chains".to_string(), + }) + } } impl truapi_platform::AuthPresenter for CliPlatform { diff --git a/rust/crates/truapi-platform/src/lib.rs b/rust/crates/truapi-platform/src/lib.rs index c5690684a..0f0740406 100644 --- a/rust/crates/truapi-platform/src/lib.rs +++ b/rust/crates/truapi-platform/src/lib.rs @@ -28,16 +28,16 @@ uniffi::use_remote_type!(truapi::Bytes32); use truapi::Bytes32; use truapi::latest::{ - AllocatableResource, GenericError, HostChatCreateRoomError, HostChatCreateRoomRequest, - HostChatCreateRoomResponse, HostChatListSubscribeItem, HostChatPostMessageError, - HostChatPostMessageRequest, HostChatPostMessageResponse, HostDevicePermissionRequest, - HostDevicePermissionResponse, HostFeatureSupportedRequest, HostFeatureSupportedResponse, - HostLocalStorageReadError, HostNavigateToError, HostPushNotificationRequest, - HostPushNotificationResponse, HostSignPayloadRequest, HostSignPayloadWithLegacyAccountRequest, - HostSignRawRequest, HostSignRawWithLegacyAccountRequest, LegacyAccountTxPayload, - NotificationId, ProductAccountId, ProductAccountTxPayload, ProductProofContext, - RemotePermission, RemotePermissionRequest, RemotePermissionResponse, RingLocation, - ThemeVariant, + AllocatableResource, ChainIdentifier, GenericError, HostChatCreateRoomError, + HostChatCreateRoomRequest, HostChatCreateRoomResponse, HostChatListSubscribeItem, + HostChatPostMessageError, HostChatPostMessageRequest, HostChatPostMessageResponse, + HostDevicePermissionRequest, HostDevicePermissionResponse, HostFeatureSupportedRequest, + HostFeatureSupportedResponse, HostLocalStorageReadError, HostNavigateToError, + HostPushNotificationRequest, HostPushNotificationResponse, HostSignPayloadRequest, + HostSignPayloadWithLegacyAccountRequest, HostSignRawRequest, + HostSignRawWithLegacyAccountRequest, LegacyAccountTxPayload, NotificationId, ProductAccountId, + ProductAccountTxPayload, ProductProofContext, RemotePermission, RemotePermissionRequest, + RemotePermissionResponse, RingLocation, ThemeVariant, }; use truapi::v01::HostAccountSignVrfRequest; use url::Url; @@ -502,6 +502,27 @@ pub trait PairingHostAdmin: Send + Sync { fn notify_session_store_changed(&self); } +/// One chain a host serves: a protocol chain role mapped to the concrete +/// chain of the host's configured environment. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct HostChainEntry { + /// Protocol role this entry answers for. + pub identifier: ChainIdentifier, + /// Genesis hash identifying the chain in all chain-scoped calls. + pub genesis_hash: Bytes32, +} + +/// The chain set a host serves: its environment plus one entry per chain role. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct HostChainSet { + /// Ecosystem the host is configured for, e.g. "polkadot", "paseo". + pub network: String, + /// Complete set of chains available through this host. + pub chains: Vec, +} + /// Feature-support probing. The host answers whether it can service a given /// capability (currently scoped to per-chain support). #[async_trait] @@ -511,6 +532,11 @@ pub trait Features: Send + Sync { &self, request: HostFeatureSupportedRequest, ) -> Result; + + /// Enumerate the chains this host serves (RFC 0026). The returned set must + /// match exactly what [`ChainProvider::connect`] will accept; the core + /// resolves `get_chain_info` requests against it. + async fn supported_chains(&self) -> Result; } /// JSON-RPC provider factory for chain access. diff --git a/rust/crates/truapi-server/src/host_logic/features.rs b/rust/crates/truapi-server/src/host_logic/features.rs index a71a106ba..16a73ded5 100644 --- a/rust/crates/truapi-server/src/host_logic/features.rs +++ b/rust/crates/truapi-server/src/host_logic/features.rs @@ -1,11 +1,14 @@ //! Feature-detection delegation. //! -//! `feature_supported` is a platform syscall: each host owns the set of -//! chains it can service. This module is a thin shim that forwards the -//! request through to [`truapi_platform::Features`]. +//! `feature_supported` and `supported_chains` are platform syscalls: each +//! host owns the set of chains it can service. This module is a thin shim +//! that forwards through to [`truapi_platform::Features`], plus the in-core +//! RFC-0026 resolution that answers `get_chain_info` from the host's chain +//! set so per-request semantics (ordering, `NotSupported`) stay core-owned. +use truapi::latest::{RemoteChainInfoError, RemoteChainInfoRequest, RemoteChainInfoResponse}; use truapi::v01::{GenericError, HostFeatureSupportedRequest, HostFeatureSupportedResponse}; -use truapi_platform::Features; +use truapi_platform::{Features, HostChainSet}; /// Forward a feature-support query to the platform implementation. pub async fn feature_supported( @@ -15,9 +18,52 @@ pub async fn feature_supported( platform.feature_supported(request).await } +/// Fetch the host's chain set from the platform implementation. +pub async fn supported_chains( + platform: &P, +) -> Result { + platform.supported_chains().await +} + +/// Resolve a `get_chain_info` request against the host's chain set: the +/// requested identifier's genesis hash plus the host's network, echoing the +/// identifier, or `NotSupported` when the host does not serve it. +pub fn chain_info( + set: &HostChainSet, + request: &RemoteChainInfoRequest, +) -> Result { + set.chains + .iter() + .find(|entry| entry.identifier == request.chain) + .map(|entry| RemoteChainInfoResponse { + network: set.network.clone(), + chain: entry.identifier, + genesis_hash: entry.genesis_hash, + }) + .ok_or(RemoteChainInfoError::NotSupported) +} + #[cfg(test)] mod tests { use super::*; + use truapi::latest::ChainIdentifier; + use truapi_platform::HostChainEntry; + + fn paseo_set() -> HostChainSet { + HostChainSet { + network: "paseo".to_string(), + chains: vec![ + HostChainEntry { + identifier: ChainIdentifier::AssetHub, + genesis_hash: [0xaa; 32], + }, + HostChainEntry { + identifier: ChainIdentifier::People, + genesis_hash: [0xbb; 32], + }, + ], + } + } struct AlwaysSupported; @@ -30,6 +76,10 @@ mod tests { assert!(matches!(request, HostFeatureSupportedRequest::Chain { .. })); Ok(HostFeatureSupportedResponse { supported: true }) } + + async fn supported_chains(&self) -> Result { + Ok(paseo_set()) + } } struct AlwaysUnsupported; @@ -43,6 +93,12 @@ mod tests { assert!(matches!(request, HostFeatureSupportedRequest::Chain { .. })); Ok(HostFeatureSupportedResponse { supported: false }) } + + async fn supported_chains(&self) -> Result { + Err(GenericError { + reason: "no chains".to_string(), + }) + } } fn req() -> HostFeatureSupportedRequest { @@ -63,4 +119,36 @@ mod tests { futures::executor::block_on(feature_supported(&AlwaysUnsupported, req())).unwrap(); assert!(!resp.supported); } + + #[test] + fn delegates_supported_chains_to_platform() { + let set = futures::executor::block_on(supported_chains(&AlwaysSupported)).unwrap(); + assert_eq!(set, paseo_set()); + } + + #[test] + fn surfaces_supported_chains_platform_error() { + let err = futures::executor::block_on(supported_chains(&AlwaysUnsupported)).unwrap_err(); + assert_eq!(err.reason, "no chains"); + } + + #[test] + fn resolves_identifier_and_echoes_it() { + let request = RemoteChainInfoRequest { + chain: ChainIdentifier::People, + }; + let response = chain_info(&paseo_set(), &request).unwrap(); + assert_eq!(response.network, "paseo"); + assert_eq!(response.chain, ChainIdentifier::People); + assert_eq!(response.genesis_hash, [0xbb; 32]); + } + + #[test] + fn unserved_identifier_is_not_supported() { + let request = RemoteChainInfoRequest { + chain: ChainIdentifier::Bulletin, + }; + let err = chain_info(&paseo_set(), &request).unwrap_err(); + assert_eq!(err, RemoteChainInfoError::NotSupported); + } } diff --git a/rust/crates/truapi-server/src/native.rs b/rust/crates/truapi-server/src/native.rs index 5b1ba53d7..4352ec71e 100644 --- a/rust/crates/truapi-server/src/native.rs +++ b/rust/crates/truapi-server/src/native.rs @@ -466,6 +466,12 @@ pub trait HostCallbacks: Send + Sync { request: v01::HostFeatureSupportedRequest, ) -> Result; + /// Enumerate the chains this host serves (RFC 0026): its environment plus + /// one entry per chain role. The returned set must match exactly what + /// `chain_connect` will accept. Invoked on the dispatcher thread; must + /// return promptly. + fn supported_chains(&self) -> Result; + /// Read a value from the host's scoped key-value store. fn local_storage_read(&self, key: String) -> Result>, HostStorageError>; /// Write a value to the host's scoped key-value store. @@ -1289,6 +1295,17 @@ impl Features for CallbackPlatform { .map_err(v01::GenericError::from)?; Ok(v01::HostFeatureSupportedResponse { supported }) } + + async fn supported_chains(&self) -> Result { + self.callbacks.on_core_log( + "truapi.native.callback.supported_chains".to_string(), + String::new(), + ); + + self.callbacks + .supported_chains() + .map_err(v01::GenericError::from) + } } #[async_trait] @@ -1679,6 +1696,12 @@ mod tests { ) -> Result { Ok(false) } + fn supported_chains(&self) -> Result { + Ok(truapi_platform::HostChainSet { + network: "paseo".to_string(), + chains: Vec::new(), + }) + } fn local_storage_read(&self, _key: String) -> Result>, HostStorageError> { Ok(None) } @@ -2303,6 +2326,12 @@ mod tests { ) -> Result { Ok(false) } + fn supported_chains(&self) -> Result { + Ok(truapi_platform::HostChainSet { + network: "paseo".to_string(), + chains: Vec::new(), + }) + } fn local_storage_read( &self, _key: String, @@ -2442,6 +2471,12 @@ mod tests { ) -> Result { Ok(true) } + fn supported_chains(&self) -> Result { + Ok(truapi_platform::HostChainSet { + network: "paseo".to_string(), + chains: Vec::new(), + }) + } fn local_storage_read( &self, _key: String, diff --git a/rust/crates/truapi-server/src/runtime.rs b/rust/crates/truapi-server/src/runtime.rs index 97f68d28e..e1704aa34 100644 --- a/rust/crates/truapi-server/src/runtime.rs +++ b/rust/crates/truapi-server/src/runtime.rs @@ -41,7 +41,7 @@ use web_time::Instant; use crate::chain_runtime::RuntimeFailure; use crate::host_logic::bulletin::preimage_key; use crate::host_logic::dotns::{NavigateDecision, parse_navigate}; -use crate::host_logic::features::feature_supported; +use crate::host_logic::features::{chain_info, feature_supported, supported_chains}; use crate::host_logic::permissions::PermissionsService; #[cfg(test)] use crate::host_logic::product_account::index_bytes; @@ -99,6 +99,7 @@ use truapi::versioned::chain::{ RemoteChainHeadStopOperationRequest, RemoteChainHeadStopOperationResponse, RemoteChainHeadStorageError, RemoteChainHeadStorageRequest, RemoteChainHeadStorageResponse, RemoteChainHeadUnpinError, RemoteChainHeadUnpinRequest, RemoteChainHeadUnpinResponse, + RemoteChainInfoError, RemoteChainInfoRequest, RemoteChainInfoResponse, RemoteChainSpecChainNameError, RemoteChainSpecChainNameRequest, RemoteChainSpecChainNameResponse, RemoteChainSpecGenesisHashError, RemoteChainSpecGenesisHashRequest, RemoteChainSpecGenesisHashResponse, @@ -1866,6 +1867,25 @@ impl Chain for ProductRuntimeHost { .map(|()| RemoteChainTransactionStopResponse::V1) .map_err(runtime_failure_to_call_error) } + + #[instrument(skip_all, fields(runtime.method = "chain.get_chain_info"))] + async fn get_chain_info( + &self, + _cx: &CallContext, + request: RemoteChainInfoRequest, + ) -> Result> { + let RemoteChainInfoRequest::V1(inner) = request; + let set = supported_chains(self.services.platform.as_ref()) + .await + .map_err(|err| { + CallError::Domain(RemoteChainInfoError::V1( + truapi::latest::RemoteChainInfoError::Unknown(err), + )) + })?; + chain_info(&set, &inner) + .map(RemoteChainInfoResponse::V1) + .map_err(|err| CallError::Domain(RemoteChainInfoError::V1(err))) + } } // --------------------------------------------------------------------------- @@ -2460,6 +2480,36 @@ mod tests { assert!(inner.supported); } + #[test] + fn get_chain_info_round_trips_through_runtime() { + let host = ProductRuntimeHost::new_compat(stub_platform(), test_spawner()); + let cx = CallContext::default(); + let request = RemoteChainInfoRequest::V1(v01::RemoteChainInfoRequest { + chain: v01::ChainIdentifier::AssetHub, + }); + let response = futures::executor::block_on(host.get_chain_info(&cx, request)).unwrap(); + let RemoteChainInfoResponse::V1(inner) = response; + assert_eq!(inner.network, "paseo"); + assert_eq!(inner.chain, v01::ChainIdentifier::AssetHub); + assert_eq!(inner.genesis_hash, [0xaa; 32]); + } + + #[test] + fn get_chain_info_unserved_identifier_is_not_supported() { + let host = ProductRuntimeHost::new_compat(stub_platform(), test_spawner()); + let cx = CallContext::default(); + let request = RemoteChainInfoRequest::V1(v01::RemoteChainInfoRequest { + chain: v01::ChainIdentifier::Bulletin, + }); + let error = futures::executor::block_on(host.get_chain_info(&cx, request)).unwrap_err(); + assert_eq!( + error, + CallError::Domain(RemoteChainInfoError::V1( + v01::RemoteChainInfoError::NotSupported + )) + ); + } + #[test] fn chain_follow_ids_are_scoped_per_product_core() { let (host_config, product) = runtime_config("same.dot"); diff --git a/rust/crates/truapi-server/src/test_support.rs b/rust/crates/truapi-server/src/test_support.rs index c1ad04074..1a8ad7cda 100644 --- a/rust/crates/truapi-server/src/test_support.rs +++ b/rust/crates/truapi-server/src/test_support.rs @@ -890,6 +890,16 @@ impl PlatformFeatures for StubPlatform { ) -> Result { Ok(v01::HostFeatureSupportedResponse { supported: true }) } + + async fn supported_chains(&self) -> Result { + Ok(truapi_platform::HostChainSet { + network: "paseo".to_string(), + chains: vec![truapi_platform::HostChainEntry { + identifier: v01::ChainIdentifier::AssetHub, + genesis_hash: [0xaa; 32], + }], + }) + } } struct RecordingConnection { diff --git a/rust/crates/truapi-server/src/wasm/generated_bridge.rs b/rust/crates/truapi-server/src/wasm/generated_bridge.rs index c08a48688..322f3068e 100644 --- a/rust/crates/truapi-server/src/wasm/generated_bridge.rs +++ b/rust/crates/truapi-server/src/wasm/generated_bridge.rs @@ -27,6 +27,7 @@ pub(super) struct JsBridge { pub(super) write_core_storage: Function, pub(super) clear_core_storage: Function, pub(super) feature_supported: Function, + pub(super) supported_chains: Function, pub(super) navigate_to: Function, pub(super) push_notification: Function, pub(super) cancel_notification: Function, @@ -49,6 +50,7 @@ impl JsBridge { write_core_storage: get_function(callbacks, "writeCoreStorage")?, clear_core_storage: get_function(callbacks, "clearCoreStorage")?, feature_supported: get_function(callbacks, "featureSupported")?, + supported_chains: get_function(callbacks, "supportedChains")?, navigate_to: get_function(callbacks, "navigateTo")?, push_notification: get_function(callbacks, "pushNotification")?, cancel_notification: get_function(callbacks, "cancelNotification")?, @@ -137,6 +139,17 @@ impl truapi_platform::Features for WasmPlatform { ) .map_err(generic) } + + async fn supported_chains(&self) -> Result { + let bytes = invoke_bytes_return(&self.bridge.supported_chains, Vec::new()) + .await + .map_err(generic)?; + decode_bytes::( + bytes, + "supportedChains response did not decode", + ) + .map_err(generic) + } } #[truapi_platform::async_trait] diff --git a/rust/crates/truapi-server/tests/common/mod.rs b/rust/crates/truapi-server/tests/common/mod.rs index be868eaf2..e723896a1 100644 --- a/rust/crates/truapi-server/tests/common/mod.rs +++ b/rust/crates/truapi-server/tests/common/mod.rs @@ -131,6 +131,16 @@ impl Features for WireShapePlatform { ) -> Result { Ok(v01::HostFeatureSupportedResponse { supported: true }) } + + async fn supported_chains(&self) -> Result { + Ok(truapi_platform::HostChainSet { + network: "paseo".to_string(), + chains: vec![truapi_platform::HostChainEntry { + identifier: v01::ChainIdentifier::AssetHub, + genesis_hash: [0xaa; 32], + }], + }) + } } struct DeadConnection; diff --git a/rust/crates/truapi-server/tests/wire_result_shape.rs b/rust/crates/truapi-server/tests/wire_result_shape.rs index c9da1b5fa..7bccd5a3c 100644 --- a/rust/crates/truapi-server/tests/wire_result_shape.rs +++ b/rust/crates/truapi-server/tests/wire_result_shape.rs @@ -66,6 +66,63 @@ fn feature_supported_ok_response_uses_ok_discriminant() { assert_eq!(response.payload.value.get(1), Some(&0x00)); } +#[test] +fn get_chain_info_ok_response_round_trips_over_the_wire() { + let core = make_core(); + let request = + truapi::versioned::chain::RemoteChainInfoRequest::V1(v01::RemoteChainInfoRequest { + chain: v01::ChainIdentifier::AssetHub, + }); + let ids = request_ids("chain_get_chain_info").expect("known request method"); + let frame = ProtocolMessage { + request_id: "p:9".into(), + payload: Payload { + id: ids.request_id, + value: request.encode(), + }, + }; + let response = dispatch(&core, frame); + assert_eq!(response.request_id, "p:9"); + assert_eq!(response.payload.id, ids.response_id); + + // Wire payload: [V1 disc=0x00][Ok disc=0x00][encoded response body]. + let mut expected = vec![0x00u8, 0x00u8]; + v01::RemoteChainInfoResponse { + network: "paseo".to_string(), + chain: v01::ChainIdentifier::AssetHub, + genesis_hash: [0xaa; 32], + } + .encode_to(&mut expected); + assert_eq!(response.payload.value, expected); +} + +#[test] +fn get_chain_info_unserved_chain_uses_err_discriminant() { + let core = make_core(); + let request = + truapi::versioned::chain::RemoteChainInfoRequest::V1(v01::RemoteChainInfoRequest { + chain: v01::ChainIdentifier::Bulletin, + }); + let ids = request_ids("chain_get_chain_info").expect("known request method"); + let frame = ProtocolMessage { + request_id: "p:10".into(), + payload: Payload { + id: ids.request_id, + value: request.encode(), + }, + }; + let response = dispatch(&core, frame); + assert_eq!(response.payload.id, ids.response_id); + + // Wire payload: [V1 disc=0x00][Err disc=0x01][encoded domain error]. + let mut expected = vec![0x00u8, 0x01u8]; + CallError::Domain(truapi::versioned::chain::RemoteChainInfoError::V1( + v01::RemoteChainInfoError::NotSupported, + )) + .encode_to(&mut expected); + assert_eq!(response.payload.value, expected); +} + #[test] fn local_storage_read_err_response_uses_err_discriminant() { let core = make_core(); diff --git a/rust/crates/truapi/src/lib.rs b/rust/crates/truapi/src/lib.rs index 0904d66ea..4c197edef 100644 --- a/rust/crates/truapi/src/lib.rs +++ b/rust/crates/truapi/src/lib.rs @@ -51,8 +51,8 @@ pub mod latest { use crate::versioned::{self, Versioned}; pub use crate::v01::{ - AccountId, AllocatableResource, AllocationOutcome, ContextualAlias, DerivationIndex, - GenericError, HostSignPayloadData, NotificationId, OperationStartedResult, + AccountId, AllocatableResource, AllocationOutcome, ChainIdentifier, ContextualAlias, + DerivationIndex, GenericError, HostSignPayloadData, NotificationId, OperationStartedResult, ProductAccountId, ProductProofContext, RawPayload, RemotePermission, RemoteStatementStoreCreateProofError, RemoteStatementStoreCreateProofRequest, RemoteStatementStoreCreateProofResponse, RemoteStatementStoreSubscribeItem, @@ -151,6 +151,12 @@ pub mod latest { pub type ProductAccountTxPayload = LatestOf; /// Chain-head subscription item. pub type RemoteChainHeadFollowItem = LatestOf; + /// Chain-identifier resolution error. + pub type RemoteChainInfoError = LatestOf; + /// Chain-identifier resolution request. + pub type RemoteChainInfoRequest = LatestOf; + /// Chain-identifier resolution result. + pub type RemoteChainInfoResponse = LatestOf; /// Chain-head subscription request. pub type RemoteChainHeadFollowRequest = LatestOf; diff --git a/rust/crates/truapi/src/v01/chain.rs b/rust/crates/truapi/src/v01/chain.rs index 85704960f..589310cf2 100644 --- a/rust/crates/truapi/src/v01/chain.rs +++ b/rust/crates/truapi/src/v01/chain.rs @@ -358,6 +358,7 @@ pub struct RemoteChainTransactionBroadcastResponse { /// Role of a chain within the host's configured environment. #[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] pub enum ChainIdentifier { /// The relay chain. Relay,