Skip to content

Commit de7a010

Browse files
committed
Harden stable SDK parity and release contracts
1 parent e6da3df commit de7a010

51 files changed

Lines changed: 2763 additions & 1536 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ The current source/static parity pass compares this repository with:
1515
- `@utexo/rgb-sdk-core` `1.0.0-beta.7`
1616
- RGB Lightning Node `0.10.0-beta.3`
1717

18-
The source baseline now targets those exact versions, and the pinned native
19-
artifact remains unchanged from the RN package. The SDK still has confirmed
20-
packaging, code-quality, supply-chain, and exact runtime evidence gaps, so
21-
baseline alignment must not be mistaken for release readiness.
18+
The source baseline targets those exact versions, and the pinned native
19+
artifact remains unchanged from the RN package. Repository-owned API, model,
20+
lifecycle, code-quality, and packaging findings are closed; the final source
21+
still requires its exact clean-candidate local runtime rerun. Production
22+
remains blocked by `PKG-006`: the upstream
23+
native artifacts do not yet have the required verified signatures, trusted-key
24+
policy, and reproducible-build/source attestations. Baseline alignment and
25+
internal-beta evidence must not be mistaken for production readiness.
2226

2327
The authoritative verdict and issue ledger are in the
2428
[Release Readiness Tracker](doc/RELEASE_READINESS_TRACKER.md). Do not infer
@@ -81,7 +85,7 @@ await wallet.unlock(
8185
bitcoindRpcHost: '127.0.0.1',
8286
bitcoindRpcPort: 18444,
8387
indexerUrl: '127.0.0.1:50002',
84-
proxyEndpoint: 'rpc://127.0.0.1:3003/json-rpc',
88+
proxyEndpoint: 'rpc://127.0.0.1:3013/json-rpc',
8589
),
8690
);
8791
```
@@ -95,7 +99,7 @@ toolchain and must fail when required local gates are skipped.
9599
flutter --version
96100
dart --version
97101
flutter pub get
98-
dart format --output=none --set-exit-if-changed lib test pigeons tool
102+
dart format --output=none --set-exit-if-changed lib test example/integration_test pigeons tool
99103
dart run tool/validate_release_governance.dart
100104
dart run tool/validate_codebase_hardening.dart
101105
dart run tool/validate_public_api_docs.dart

‎android/src/main/kotlin/com/utexo/rgb_sdk_flutter/RgbSdkFlutterPlugin.kt‎

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,6 @@ class RgbSdkFlutterPlugin :
3434
)
3535
}
3636

37-
private fun unsupported(operation: String): Nothing {
38-
throw FlutterError(
39-
code = "unsupported",
40-
message = "$operation is not implemented yet.",
41-
details = bridgeErrorDetails(
42-
operation = operation,
43-
category = "unsupported",
44-
retryable = false,
45-
extra = mapOf("phase" to "rln-parity", "feature" to operation)
46-
)
47-
)
48-
}
49-
5037
private fun <T> runRln(operation: String, block: () -> T): T {
5138
try {
5239
@Suppress("UNCHECKED_CAST")

‎doc/API_COMPATIBILITY_AND_DIVERGENCE.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ ship.
3131
| `createBackup` / `rlnBackup` | Native artifact owner plus Flutter maintainer | `API-019`, `G-11` | Keep native-blocked and fail before claiming recovery support. | `test/utexo_wallet_test.dart::keeps local backup explicitly native-blocked`; Android/iOS native backup-blocked bridge cases. | Pinned native RLN exposes a working backup/recovery implementation and cross-platform funded recovery tests pass. |
3232
| `sendRgb(skipSync: true)` | Flutter maintainer | `API-006` | Fail fast instead of accepting and silently discarding the value. | `test/rln_client_contract_test.dart::sendRgb rejects skipSync true before native call`; Android/iOS native skip-sync rejection cases. | Pinned native RLN exposes a real skip-sync request field and RN/core define semantics. |
3333
| `gossipRgsServerUrl` unlock field | Flutter maintainer | `API-030` | Reject non-empty values because native signer unlock currently ignores the field. | `test/utexo_wallet_test.dart::rejects no-op gossip RGS unlock configuration`. | Pinned native RLN signer unlock consumes the field end to end. |
34+
| Fractional native fee rates | Flutter maintainer | `MODEL-014` | Require integer-equivalent sats/vbyte and reject fractional values before native execution. RN currently defaults some calls to `1.5`, then truncates through the UInt64 bridge; Flutter does not reproduce that data-loss bug. | Dart wallet validation plus mirrored Android/iOS bridge numeric vectors. | Native/core adopt an exact fractional fee-rate representation end to end. |
3435
| High-level CFA/UDA issuance | Flutter maintainer | `API-017` | Expose only through low-level RN-parity `RlnClient`/`RLNBinding`, not the stable wallet facade. | Wallet matrix excludes `issueAssetCfa`/`issueAssetUda`; low-level matrix keeps the RN methods. | RN adds wallet-level CFA/UDA methods or product approves a Flutter-only extension library. |
3536
| Standalone account-key Schnorr signing default | Flutter maintainer plus release security owner | `SEC-007` | Fail closed by default and require `SchnorrSigningMode.experimentalDart` for the pure-Dart signer, even though RN's top-level core `signMessage` is callable by default. Wallet/node-key signing remains native RLN-backed and RN-aligned. | `test/crypto_bip340_vectors_test.dart::standalone Schnorr signing fails closed without explicit opt in`; `test/utexo_wallet_test.dart::signs and verifies RN-core compatible Schnorr messages`; `tool/validate_codebase_hardening.dart`. | Replace the pure-Dart implementation with a vetted/native signing primitive or complete a formal crypto review proving production suitability, then update public docs and parity tests before changing the default. |
3637
| Durable credential storage | Consuming app owner plus Flutter maintainer | `SEC-009` | App-owned storage boundary; SDK owns only in-memory minimization and diagnostics. | `doc/INTEGRATION_SECURITY_AND_RELEASE.md`; release package validation requires `SECURITY.md`. | SDK product scope expands to include a native secure-storage subsystem. |
@@ -48,7 +49,7 @@ carrier. Raw RN/native parity symbols must live behind
4849
| --- | --- | --- | --- |
4950
| Stable facade | App-facing APIs intended to survive release. | `RgbSdkFlutter`, `UtexoWallet`, signer config, domain wallet DTOs. | Breaking changes require a tracker row, migration note, API snapshot update, and semver plan. |
5051
| Advanced parity | RN/native-shaped APIs for parity testing, diagnostics, migration tooling, and explicit escape hatches. | `RlnClient`, `RLNBinding`, `RLNManager`, `IRLN*`, raw `Rln*` models, native bridge mapper. | Can change when RN/native changes, but changes must cite the RN baseline and update parity tests. |
51-
| Compatibility shim | Legacy or transitional exports kept to avoid abrupt local breakage. | Old aliases, core-shaped helpers, raw status helpers. | Must be deprecated or quarantined before production release. |
52+
| Compatibility shim | A narrowly documented RN spelling kept outside the stable root. | Advanced `decodeRGBInvoice`. | Must remain advanced-only and is removable when migration consumers no longer need it. |
5253
| Unsupported/native-blocked | Public names that exist only to fail honestly. | `createBackup` while native backup is blocked. | Must fail before native side effects and must be documented as not release-ready. |
5354
| Internal | Implementation details. | Native stores, bridge error mapper internals, LSP implementation helpers. | Must not be exported from the stable facade once `CODE-001` is closed. |
5455

@@ -93,6 +94,9 @@ semantics and the adaptation is tested.
9394
| On-chain receive/send requests | Core uses domain request/response models; RN often passes object literals. | Flutter uses typed request classes. | Typed request classes are allowed if units, optionality, defaults, and native field names are documented. | `MODEL-016`, `API-014`, and `test/utexo_wallet_test.dart::documents and preserves timestamp and amount units at model boundaries`. |
9495
| Raw request DTOs | RN/native bridge sends loose JS objects and maps. | Low-level `RlnClient` still exposes raw maps through `rgb_sdk_flutter_advanced.dart`. | Raw map APIs stay advanced-only; stable facade must return domain models. | `CODE-001`, `CODE-005`, and API snapshot gate. |
9596
| Wallet facade return shapes | RN/native names may surface bridge DTOs. | Canonical `UtexoWallet` methods return stable domain DTOs; native `Rln*` models are reachable through explicit `Raw` methods. | Flutter app code should not consume bridge wire shapes by default. Raw access remains available for parity debugging and advanced native integration. | `API-007`, `API-010`, `test/utexo_wallet_test.dart::maps Bitcoin list methods to domain DTOs and raw escape hatches`, `test/utexo_wallet_test.dart::maps Lightning, peer, and channel methods to stable DTOs`. |
97+
| Lightning payment and status DTOs | Core beta.7 defines `LightningPayment`, `LightningSendRequest`, `ListLightningPaymentsResponse`, `SendPaymentResult`, and canonical string statuses. | Flutter exposes the same domain fields with Dart nullability, immutable list wrappers, and `Rln*StatusValue` string aliases. | Stable methods normalize statuses to PascalCase, preserve optional list status/consignment fields, derive `inbound`, and fail closed when required native payment identifiers are absent. Raw bridge responses remain advanced-only. | `API-037`, `CODE-017`, wallet malformed-success and Lightning mapping tests, and the complete wallet return-shape parity gate. |
98+
| Wallet facade input shapes | RN uses request objects for many operations and hides low-level sync/filter controls from canonical reads. | Dart uses typed request DTOs or named parameters with the same units, optionality, defaults, and domain names. | Stable methods do not expose raw bridge-only controls or duplicate sats/msats aliases. Advanced `Raw` methods retain native controls. Channel inputs use core names, and `RgbInvoiceRequest.witness` preserves RN on-chain receive behavior. | `API-038`, stable-wallet API snapshot, high-risk input-contract parity checks, wallet tests, and integration smokes. |
99+
| VSS fence recovery lifecycle | RN documents `vssClearFence` for a locked node before unlock. | Flutter requires `init()` and deliberately does not require `unlock()`. | This is the same lifecycle point expressed through Flutter's explicit state machine. Calling before init or after disposal fails with the SDK taxonomy. | `LIFE-016`, `test/utexo_wallet_test.dart::clears a stale VSS fence after init and before unlock`. |
96100

97101
## Deprecation and Breaking-Change Plan
98102

‎doc/PUBLIC_API_REFERENCE.md‎

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,51 @@ The release verdict remains controlled by
1010
| Tier | Symbols | Contract |
1111
| --- | --- | --- |
1212
| Stable wallet facade | `package:rgb_sdk_flutter/rgb_sdk_flutter.dart`: `RgbSdkFlutter`, `UtexoWallet`, wallet config/request/response types, signer strategies, domain DTOs, public wallet errors | Intended for app code, subject to documented breaking-change policy. |
13-
| Advanced/native bridge | `package:rgb_sdk_flutter/rgb_sdk_flutter_advanced.dart`: `RlnClient`, `RLNBinding`, `RLNManager`, `IRLN*`, raw `Rln*` native models, native bridge error mapper, logger, and RN compatibility extensions | Available for RN/native parity, diagnostics, migration tools, and explicit escape hatches; shape follows the pinned RN/native baseline. |
13+
| Advanced/native bridge | `package:rgb_sdk_flutter/rgb_sdk_flutter_advanced.dart`: `RlnClient`, `RLNBinding`, `RLNManager`, `IRLN*`, raw `Rln*` native models, `createAdvancedUtexoWallet`, native bridge error mapper, logger, and RN/raw compatibility extensions | Available for RN/native parity, diagnostics, migration tools, and explicit escape hatches; shape follows the pinned RN/native baseline. |
1414
| Core/domain adapters | Stable domain `Core*`/`Lightning*` DTOs are root-exported; raw mapper extensions remain advanced-only | Flutter domain adaptation of current RN/core concepts. |
15-
| Compatibility stubs | PSBT and backup/recovery-related symbols | Present for compatibility only when the tracker marks the feature unsupported or native-blocked. |
15+
| Capability and blocked boundaries | Absent PSBT/begin-end carriers and native-blocked backup/recovery | Optional carriers are `null`; backup fails explicitly while the tracker marks it native-blocked. |
1616

1717
Canonical `UtexoWallet` methods return stable wallet/domain DTOs, not raw
1818
native wire DTOs. Advanced callers that need the pinned native shape for parity
1919
debugging must use the matching explicit `Raw` method, for example
2020
`listChannelsRaw()`, `getBtcBalanceRaw()`, `decodeLnInvoiceRaw()`, or
21-
`listTransfersRaw()`. Import `rgb_sdk_flutter_advanced.dart` for raw bridge
22-
classes, RN-uppercase compatibility spellings such as `decodeRGBInvoice`, or
23-
RN-style managers. The root import intentionally does not export those names.
21+
`listTransfersRaw()`. Those methods are members of the advanced-only
22+
`UtexoWalletRawApi` extension; importing the stable root alone cannot resolve
23+
them. Import `rgb_sdk_flutter_advanced.dart` for raw bridge classes,
24+
dependency-injected test wallets, RN-uppercase compatibility spellings such as
25+
`decodeRGBInvoice`, or RN-style managers. The root import intentionally does
26+
not export those names or expose `RlnClient`/`RLNBinding` in the stable wallet
27+
constructor.
28+
29+
Custom signer strategies implement `RlnSigner` against the stable
30+
`RlnSignerHost` protocol. The wallet supplies that host and retains native
31+
client ownership; signer implementations must not retain it after an
32+
operation. `IUtexoLspClient` is likewise a stable transport protocol because
33+
RN exports that contract and `UtexoLsp` accepts injected implementations. The
34+
concrete HTTP client and raw native client remain advanced-only.
35+
36+
Asset issuance returns `CoreAssetNia`/`CoreAssetIfa`, `inflate()` returns
37+
`InflateAssetIfaResponse`, `estimateFeeRate()` returns
38+
`FeeEstimationResponse`, and `checkIndexerUrl()` returns
39+
`IndexerCheckResponse`. Their native `Rln*` equivalents are available only
40+
through the advanced raw extension.
41+
42+
Canonical wallet inputs follow RN/core semantics with Dart named parameters or
43+
typed requests. Read/list/refresh methods do not expose raw bridge sync/filter
44+
knobs. Lightning invoice creation accepts sats plus an optional
45+
`LightningAsset`; payment accepts required `lnInvoice` plus optional sats and
46+
asset fields. Channel opening uses `peerPubkey`, `isPublic`, and
47+
`assetLocalAmount`. `RgbInvoiceRequest.witness` selects the `onchainReceive`
48+
mode; the dedicated blind/witness methods enforce their named mode.
49+
50+
Lightning methods use the core beta.7 domain shapes. `listPayments()` returns
51+
`LightningPayment` records with a required canonical PascalCase status and
52+
optional Unix-second timestamps. `listLightningPayments()` wraps
53+
`LightningSendRequest` records, whose status and RGB consignment endpoint are
54+
optional. `keysend()` returns `SendPaymentResult`. Missing required native
55+
identifiers and malformed boolean/string success fields throw
56+
`NativeProtocolException`; the facade never substitutes an empty identifier or
57+
silently treats malformed data as `false`.
2458

2559
## Lifecycle Prerequisites
2660

@@ -30,6 +64,11 @@ need a running native node. After `shutdown()`, regular operations fail until
3064
`reinit()` succeeds. After `destroy()`, the wallet is disposed and cannot be
3165
reused.
3266

67+
`vssClearFence(password)` is the deliberate exception to the general unlock
68+
rule: call it after `init()` but before `unlock()` when recovering a stale VSS
69+
single-writer fence. It fails before initialization and does not require an
70+
unlocked node. `backupNow()` still requires an unlocked node.
71+
3372
Internally, the wallet facade routes native node operations through its binding
3473
owner so app-facing calls share one serialized lifecycle/operation queue. Signer
3574
strategies may still use the same underlying native client for their private
@@ -74,8 +113,8 @@ example `RlnNodeInfo.channelAssetMaxAmount` is `BigInt?`.
74113

75114
`NetworkEndpoints` and `getNetworkDefaults()` are stable root helpers for
76115
app-facing network defaults. They expose the selected indexer URL and RGB proxy
77-
endpoint after SDK network normalization; lower-level UTEXO preset maps remain
78-
advanced/internal compatibility surface.
116+
endpoint after SDK network normalization. Removed UTEXO bridge/network preset
117+
maps are not retained as dead compatibility code.
79118

80119
`UtexoWallet.listTransfers()` calls the native unfiltered listing path. If the
81120
pinned native artifact rejects that call, the SDK throws
@@ -161,15 +200,18 @@ root checklist and are snapshotted by `tool/api_snapshot.json`.
161200
- `ApayNewResponse`, `Assignment`, `BadRequestError`, `BeginEndWalletCarrier`
162201
- `ChannelReadyInfo`, `ClaimResult`, `ConfigurationError`, `ConflictError`
163202
- `CoreAsset`, `CoreAssetBalance`, `CoreAssetCfa`, `CoreAssetIfa`
164-
- `CoreAssetNia`, `CoreAssetUda`, `CoreBalance`, `CoreBtcBalance`
165-
- `CoreInvoiceData`, `CoreInvoiceReceiveData`, `CoreListAssets`, `CoreRgbAllocation`
166-
- `CoreTransaction`, `CoreTransfer`, `CoreTransferStatus`, `CoreTransferStatuses`
203+
- `CoreAssetNia`, `CoreAssetToken`, `CoreAssetUda`, `CoreBalance`, `CoreBlockTime`
204+
- `CoreBtcBalance`, `CoreInvoiceData`, `CoreInvoiceReceiveData`, `CoreListAssets`, `CoreMedia`
205+
- `CoreRgbAllocation`, `CoreTokenAttachment`, `CoreTransaction`, `CoreTransfer`
206+
- `CoreTransferStatus`, `CoreTransferStatuses`, `CoreTransferTransportEndpoint`
167207
- `CoreUnspent`, `CoreUtxo`, `CreateHodlInvoiceParams`, `CryptoError`
168208
- `DecodedLightningInvoice`, `GeneratedKeys`, `HodlInvoice`, `HodlInvoiceResult`
169209
- `ExperimentalCryptoException`
170-
- `InflateAssetIfaRequest`, `LightningAddressInfo`, `LightningAsset`, `LightningChannel`
171-
- `LightningChannelOpenResult`, `LightningInvoiceStatus`, `LightningPayment`, `LightningPaymentResult`
172-
- `LightningPaymentSummary`, `LightningPeer`, `LightningReceiveRequest`, `LightningSendRequest`
210+
- `FeeEstimationResponse`, `IndexerCheckResponse`, `InflateAssetIfaRequest`, `InflateAssetIfaResponse`
211+
- `IUtexoLspClient`
212+
- `LightningAddressInfo`, `LightningAsset`, `LightningChannel`
213+
- `LightningChannelOpenResult`, `LightningPayment`, `LightningPeer`
214+
- `LightningReceiveRequest`, `LightningSendRequest`, `SendPaymentResult`
173215
- `ListLightningPaymentsResponse`, `LspAmountOutOfRangeException`, `LspApayInvoiceProofWire`, `LspChannelTimeoutException`
174216
- `LspClientConfig`, `LspError`, `LspGetInfoResponse`, `LspLightningAddressByPubkeyResponse`
175217
- `LspLightningReceiveRequest`, `LspLightningReceiveResponse`, `LspLiquidityTimeoutException`, `LspLnParams`
@@ -184,7 +226,7 @@ root checklist and are snapshotted by `tool/api_snapshot.json`.
184226
- `RgbNodeError`, `RgbSdkException`, `RgbSdkFlutter`, `RgbSendRequest`
185227
- `RlnInvoiceStatusValue`, `RlnInvoiceStatuses`, `RlnKeyMaterial`, `RlnMnemonicKeyMaterial`
186228
- `RlnOperationTimeoutException`, `RlnOperationTimeoutPolicy`, `RlnPaymentStatusValue`, `RlnPaymentStatuses`
187-
- `RlnSeedBytesKeyMaterial`, `RlnSeedHexKeyMaterial`, `RlnSigner`, `SDKError`
229+
- `RlnSeedBytesKeyMaterial`, `RlnSeedHexKeyMaterial`, `RlnSigner`, `RlnSignerHost`, `SDKError`
188230
- `SchnorrSigningMode`, `SendAssetOptions`, `SendAssetResult`, `SignMessageParams`
189231
- `UnsupportedWalletFeatureException`
190232
- `UtexoLsp`, `UtexoLspConfig`, `UtexoUnlockConfig`, `UtexoWallet`
@@ -198,7 +240,7 @@ root checklist and are snapshotted by `tool/api_snapshot.json`.
198240
- `isSameLspHost`, `isTerminalPaymentStatus`, `isUmaAddress`, `lnurlDiscoveryUri`
199241
- `normalizeInvoiceStatus`, `normalizeLightningAddress`, `normalizeNetwork`, `normalizePaymentStatus`
200242
- `normalizeReceiveStatus`, `normalizeSeedInput`, `parseCoreAssignment`, `parseCoreOutpoint`
201-
- `parseLightningAddress`, `peerUri`, `redactSupportText`, `resolveUnlockConfig`
243+
- `parseLightningAddress`, `peerUri`, `redactSupportText`
202244
- `resolveUnlockParams`, `restoreKeys`, `seedFromMnemonic`, `signMessage`
203245
- `signSchnorr`, `toUnitsNumber`, `tryNormalizeInvoiceStatus`, `tryNormalizePaymentStatus`
204246
- `validateBase64`, `validateBip39Mnemonic`, `validateHex`, `validateMnemonic`

0 commit comments

Comments
 (0)