Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions android/app/src/main/java/org/bitcoinppl/cove/ScanManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ class ScanManager private constructor() {
}
}

is MultiFormat.SatsCard -> {
Log.d(tag, "SATSCARD detected: slot ${multiFormat.v1.slotNumber} state ${multiFormat.v1.state}")
app.alertState = TaggedItem(
AppAlertState.General(
title = "SATSCARD Detected",
message = "SATSCARD support is coming soon. Slot ${multiFormat.v1.slotNumber} was scanned.",
),
)
}

is MultiFormat.Bip329Labels -> {
val selectedWallet = Database().globalConfig().selectedWallet()
if (selectedWallet == null) {
Expand Down
86 changes: 78 additions & 8 deletions android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ import org.bitcoinppl.cove_core.device.FfiConverterTypeKeychainError
import org.bitcoinppl.cove_core.device.KeychainException
import org.bitcoinppl.cove_core.nfc.FfiConverterTypeNfcMessage
import org.bitcoinppl.cove_core.nfc.NfcMessage
import org.bitcoinppl.cove_core.tapcard.FfiConverterTypeSatsCard
import org.bitcoinppl.cove_core.tapcard.FfiConverterTypeTapCardParseError
import org.bitcoinppl.cove_core.tapcard.FfiConverterTypeTapSigner
import org.bitcoinppl.cove_core.tapcard.SatsCard
import org.bitcoinppl.cove_core.tapcard.TapCardParseException
import org.bitcoinppl.cove_core.tapcard.TapSigner
import org.bitcoinppl.cove_core.types.Address
Expand Down Expand Up @@ -115,6 +117,7 @@ import org.bitcoinppl.cove_core.ur.UrException
import org.bitcoinppl.cove_core.device.RustBuffer as RustBufferCloudSyncHealth
import org.bitcoinppl.cove_core.device.RustBuffer as RustBufferKeychainError
import org.bitcoinppl.cove_core.nfc.RustBuffer as RustBufferNfcMessage
import org.bitcoinppl.cove_core.tapcard.RustBuffer as RustBufferSatsCard
import org.bitcoinppl.cove_core.tapcard.RustBuffer as RustBufferTapCardParseError
import org.bitcoinppl.cove_core.tapcard.RustBuffer as RustBufferTapSigner
import org.bitcoinppl.cove_core.types.RustBuffer as RustBufferAddress
Expand Down Expand Up @@ -39689,7 +39692,7 @@ sealed class MultiFormat: Disposable {
}

/**
* TAPSIGNER has not been initialized yet
* TAPSIGNER is initialized and ready to import.
*/
data class TapSignerReady(
val v1: org.bitcoinppl.cove_core.tapcard.TapSigner) : MultiFormat()
Expand All @@ -39711,14 +39714,36 @@ sealed class MultiFormat: Disposable {
}

/**
* TAPSIGNER has not been initialized yet
* TAPSIGNER is uninitialized and still needs setup.
*/
data class TapSignerUnused(
val v1: org.bitcoinppl.cove_core.tapcard.TapSigner) : MultiFormat()

{


// The local Rust `Eq` implementation - only `eq` is used.
override fun equals(other: Any?): Boolean {
if (other !is MultiFormat) return false
return FfiConverterBoolean.lift(
uniffiRustCall() { _status ->
UniffiLib.uniffi_cove_fn_method_multiformat_uniffi_trait_eq_eq(FfiConverterTypeMultiFormat.lower(this),
FfiConverterTypeMultiFormat.lower(`other`),_status)
}
)
}
companion object
}

/**
* SATSCARD detected via NFC/QR
*/
data class SatsCard(
val v1: org.bitcoinppl.cove_core.tapcard.SatsCard) : MultiFormat()

{


// The local Rust `Eq` implementation - only `eq` is used.
override fun equals(other: Any?): Boolean {
if (other !is MultiFormat) return false
Expand Down Expand Up @@ -39803,6 +39828,13 @@ sealed class MultiFormat: Disposable {
}
is MultiFormat.TapSignerUnused -> {

Disposable.destroy(
this.v1
)

}
is MultiFormat.SatsCard -> {

Disposable.destroy(
this.v1
)
Expand Down Expand Up @@ -39863,7 +39895,10 @@ public object FfiConverterTypeMultiFormat : FfiConverterRustBuffer<MultiFormat>{
7 -> MultiFormat.TapSignerUnused(
FfiConverterTypeTapSigner.read(buf),
)
8 -> MultiFormat.SignedPsbt(
8 -> MultiFormat.SatsCard(
FfiConverterTypeSatsCard.read(buf),
)
9 -> MultiFormat.SignedPsbt(
FfiConverterTypePsbt.read(buf),
)
else -> throw RuntimeException("invalid enum value, something is very wrong!!")
Expand Down Expand Up @@ -39920,6 +39955,13 @@ public object FfiConverterTypeMultiFormat : FfiConverterRustBuffer<MultiFormat>{
+ FfiConverterTypeTapSigner.allocationSize(value.v1)
)
}
is MultiFormat.SatsCard -> {
// Add the size for the Int that specifies the variant plus the size needed for all fields
(
4UL
+ FfiConverterTypeSatsCard.allocationSize(value.v1)
)
}
is MultiFormat.SignedPsbt -> {
// Add the size for the Int that specifies the variant plus the size needed for all fields
(
Expand Down Expand Up @@ -39966,8 +40008,13 @@ public object FfiConverterTypeMultiFormat : FfiConverterRustBuffer<MultiFormat>{
FfiConverterTypeTapSigner.write(value.v1, buf)
Unit
}
is MultiFormat.SignedPsbt -> {
is MultiFormat.SatsCard -> {
buf.putInt(8)
FfiConverterTypeSatsCard.write(value.v1, buf)
Unit
}
is MultiFormat.SignedPsbt -> {
buf.putInt(9)
FfiConverterTypePsbt.write(value.v1, buf)
Unit
}
Expand Down Expand Up @@ -40011,6 +40058,14 @@ sealed class MultiFormatException: kotlin.Exception() {
get() = "v1=${ v1 }"
}

class InvalidSatsCard(

val v1: TapCardParseException
) : MultiFormatException() {
override val message
get() = "v1=${ v1 }"
}

class TaprootNotSupported(
) : MultiFormatException() {
override val message
Expand Down Expand Up @@ -40059,8 +40114,11 @@ public object FfiConverterTypeMultiFormatError : FfiConverterRustBuffer<MultiFor
4 -> MultiFormatException.InvalidTapSigner(
FfiConverterTypeTapCardParseError.read(buf),
)
5 -> MultiFormatException.TaprootNotSupported()
6 -> MultiFormatException.PsbtNotSigned()
5 -> MultiFormatException.InvalidSatsCard(
FfiConverterTypeTapCardParseError.read(buf),
)
6 -> MultiFormatException.TaprootNotSupported()
7 -> MultiFormatException.PsbtNotSigned()
else -> throw RuntimeException("invalid error enum value, something is very wrong!!")
}
}
Expand All @@ -40085,6 +40143,11 @@ public object FfiConverterTypeMultiFormatError : FfiConverterRustBuffer<MultiFor
4UL
+ FfiConverterTypeTapCardParseError.allocationSize(value.v1)
)
is MultiFormatException.InvalidSatsCard -> (
// Add the size for the Int that specifies the variant plus the size needed for all fields
4UL
+ FfiConverterTypeTapCardParseError.allocationSize(value.v1)
)
is MultiFormatException.TaprootNotSupported -> (
// Add the size for the Int that specifies the variant plus the size needed for all fields
4UL
Expand Down Expand Up @@ -40116,14 +40179,19 @@ public object FfiConverterTypeMultiFormatError : FfiConverterRustBuffer<MultiFor
FfiConverterTypeTapCardParseError.write(value.v1, buf)
Unit
}
is MultiFormatException.TaprootNotSupported -> {
is MultiFormatException.InvalidSatsCard -> {
buf.putInt(5)
FfiConverterTypeTapCardParseError.write(value.v1, buf)
Unit
}
is MultiFormatException.PsbtNotSigned -> {
is MultiFormatException.TaprootNotSupported -> {
buf.putInt(6)
Unit
}
is MultiFormatException.PsbtNotSigned -> {
buf.putInt(7)
Unit
}
}.let { /* this makes the `when` an expression, which ensures it is exhaustive */ }
}

Expand Down Expand Up @@ -54543,6 +54611,8 @@ public typealias FfiConverterTypeTimestamp = FfiConverterULong








Expand Down
12 changes: 12 additions & 0 deletions ios/Cove/ScanManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ import SwiftUI
} else {
app.alertState = .init(.initializedTapSigner(tapSigner: tapSigner))
}
case let .satsCard(satsCard):
Log.debug("SATSCARD detected: slot \(satsCard.slotNumber) state \(satsCard.state)")
app.alertState = .init(.general(
title: "SATSCARD Detected",
message: "SATSCARD support is coming soon. Slot \(satsCard.slotNumber) was scanned."
))
case let .bip329Labels(labels):
guard let manager = app.walletManager else { return setInvalidLabels() }
guard let selectedWallet = Database().globalConfig().selectedWallet() else {
Expand Down Expand Up @@ -108,6 +114,12 @@ import SwiftUI
)
case let .signedPsbt(psbt):
handleSignedPsbt(psbt)
case let .satsCard(satsCard):
Log.debug("SATSCARD detected via file: slot \(satsCard.slotNumber) state \(satsCard.state)")
app.alertState = .init(.general(
title: "SATSCARD Detected",
message: "SATSCARD support is coming soon. Slot \(satsCard.slotNumber) was scanned."
))
}
} catch {
switch error {
Expand Down
39 changes: 31 additions & 8 deletions ios/CoveCore/Sources/CoveCore/generated/cove.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23365,15 +23365,20 @@ public enum MultiFormat: Equatable {
case bip329Labels(Bip329Labels
)
/**
* TAPSIGNER has not been initialized yet
* TAPSIGNER is initialized and ready to import.
*/
case tapSignerReady(TapSigner
)
/**
* TAPSIGNER has not been initialized yet
* TAPSIGNER is uninitialized and still needs setup.
*/
case tapSignerUnused(TapSigner
)
/**
* SATSCARD detected via NFC/QR
*/
case satsCard(SatsCard
)
/**
* A signed but un-finalized PSBT
*/
Expand Down Expand Up @@ -23432,7 +23437,10 @@ public struct FfiConverterTypeMultiFormat: FfiConverterRustBuffer {
case 7: return .tapSignerUnused(try FfiConverterTypeTapSigner.read(from: &buf)
)

case 8: return .signedPsbt(try FfiConverterTypePsbt.read(from: &buf)
case 8: return .satsCard(try FfiConverterTypeSatsCard.read(from: &buf)
)

case 9: return .signedPsbt(try FfiConverterTypePsbt.read(from: &buf)
)

default: throw UniffiInternalError.unexpectedEnumCase
Expand Down Expand Up @@ -23478,8 +23486,13 @@ public struct FfiConverterTypeMultiFormat: FfiConverterRustBuffer {
FfiConverterTypeTapSigner.write(v1, into: &buf)


case let .signedPsbt(v1):
case let .satsCard(v1):
writeInt(&buf, Int32(8))
FfiConverterTypeSatsCard.write(v1, into: &buf)


case let .signedPsbt(v1):
writeInt(&buf, Int32(9))
FfiConverterTypePsbt.write(v1, into: &buf)

}
Expand Down Expand Up @@ -23514,6 +23527,8 @@ enum MultiFormatError: Swift.Error, Equatable, Hashable, Foundation.LocalizedErr
case UnrecognizedFormat
case InvalidTapSigner(TapCardParseError
)
case InvalidSatsCard(TapCardParseError
)
case TaprootNotSupported
case PsbtNotSigned

Expand Down Expand Up @@ -23563,8 +23578,11 @@ public struct FfiConverterTypeMultiFormatError: FfiConverterRustBuffer {
case 4: return .InvalidTapSigner(
try FfiConverterTypeTapCardParseError.read(from: &buf)
)
case 5: return .TaprootNotSupported
case 6: return .PsbtNotSigned
case 5: return .InvalidSatsCard(
try FfiConverterTypeTapCardParseError.read(from: &buf)
)
case 6: return .TaprootNotSupported
case 7: return .PsbtNotSigned

default: throw UniffiInternalError.unexpectedEnumCase
}
Expand Down Expand Up @@ -23595,12 +23613,17 @@ public struct FfiConverterTypeMultiFormatError: FfiConverterRustBuffer {
FfiConverterTypeTapCardParseError.write(v1, into: &buf)


case .TaprootNotSupported:
case let .InvalidSatsCard(v1):
writeInt(&buf, Int32(5))
FfiConverterTypeTapCardParseError.write(v1, into: &buf)


case .TaprootNotSupported:
writeInt(&buf, Int32(6))


case .PsbtNotSigned:
writeInt(&buf, Int32(6))
writeInt(&buf, Int32(7))

}
}
Expand Down
39 changes: 39 additions & 0 deletions rust/crates/cove-tap-card/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,45 @@ mod tests {
assert_eq!(msg, expected);
}

#[test]
fn test_parses_sats_card_unsealed() {
let card = "https://getsatscard.com/start#u=U&o=3&r=95kesdwq&n=ab78fd50637f8f5a&s=26d1a0684f99fe43b223dca75081bb05bd0233b901139cdd33a4d0a2e61666ed1470d7c53d90f6ae4c60a6cbc7a0f4ded5f13461092b24604ad476bbcf1dd913";
let TapCard::SatsCard(sats_card) = TapCard::parse(card).unwrap() else {
panic!("not a sats card")
};

assert_eq!(sats_card.state, SatsCardState::Unsealed);
assert_eq!(sats_card.slot_number, 3);
assert_eq!(sats_card.address_suffix, "95kesdwq");
}

#[test]
fn test_parses_sats_card_error_state() {
let card = "https://getsatscard.com/start#u=E&o=0&r=95kesdwq&n=ab78fd50637f8f5a&s=26d1a0684f99fe43b223dca75081bb05bd0233b901139cdd33a4d0a2e61666ed1470d7c53d90f6ae4c60a6cbc7a0f4ded5f13461092b24604ad476bbcf1dd913";
let TapCard::SatsCard(sats_card) = TapCard::parse(card).unwrap() else {
panic!("not a sats card")
};

assert_eq!(sats_card.state, SatsCardState::Error);
}

#[test]
fn test_sats_card_not_misidentified_as_tap_signer() {
let card = "https://getsatscard.com/start#u=S&o=0&r=95kesdwq&n=ab78fd50637f8f5a&s=26d1a0684f99fe43b223dca75081bb05bd0233b901139cdd33a4d0a2e61666ed1470d7c53d90f6ae4c60a6cbc7a0f4ded5f13461092b24604ad476bbcf1dd913";
let tap_card = TapCard::parse(card).unwrap();
assert!(
matches!(tap_card, TapCard::SatsCard(_)),
"getsatscard.com URL should never parse as TapSigner"
);
}

#[test]
fn test_invalid_url_domain_errors() {
let url = "https://example.com/start#u=S&o=0&r=95kesdwq&n=abc&s=def";
let err = TapCard::parse(url).unwrap_err();
assert!(matches!(err, Error::InvalidUrl(_)));
}

#[test]
fn test_tap_signer_readable_ident_string() {
let url = "https://tapsigner.com/start#t=1&u=S&c=04d74fb1dfee7a4d&n=8940dc9808088820&s=6bda376546b7074b5a52f3264fe118d38889f49501b591b0b9e90a2ff2e07d26572898aaeb0f963a52cf707e7483203520ce40bdf5071e8f80262d587b41b99f";
Expand Down
Loading
Loading