Skip to content

Commit

Permalink
bech32 dependency, no longer need to compute byte buffer size, moved …
Browse files Browse the repository at this point in the history
…some classes
  • Loading branch information
matthappens committed Aug 16, 2024
1 parent 17e43c6 commit fb64f60
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 171 deletions.
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@ kotlin = "1.9.0"
kotlinCoroutines = "1.6.4"
kotlinxDateTime = "0.4.0"
kotlinSerializationJson = "1.4.1"
kotlinReflect = "2.0.0"
ktlint = "11.3.1"
ktor = "2.2.3"
mavenPublish = "0.25.2"
mockitoCore = "5.5.0"
taskTree = "2.1.1"
junit = "4.13.2"
bitcoinj-core = "0.16.3"

[libraries]
gradleClasspath-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
gradleClasspath-ktlint = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlint" }
gradleClasspath-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
gradleClasspath-mavenPublish = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "mavenPublish" }

bitcoin-core = { module = "org.bitcoinj:bitcoinj-core", version.ref = "bitcoinj-core" }

task-tree = { module = "com.dorongold.plugins:task-tree", version.ref = "taskTree" }

kotlin-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerializationJson" }
Expand Down
1 change: 1 addition & 0 deletions uma-sdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ kotlin {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.ktor.client.core)
implementation(libs.jna)
implementation(libs.bitcoin.core)
}
}
val commonTest by getting {
Expand Down
25 changes: 0 additions & 25 deletions uma-sdk/src/commonMain/kotlin/me/uma/protocol/CounterPartyData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,6 @@ data class CounterPartyDataOption(

typealias CounterPartyDataOptions = Map<String, CounterPartyDataOption>

data class InvoiceCounterPartyDataOptions(
val options: CounterPartyDataOptions
) : ByteCodeable {
override fun toBytes(): ByteArray {
val optionsString = options.map { (key, option) ->
"${key}:${ if (option.mandatory) 1 else 0}"
}.joinToString(",")
return optionsString.toByteArray(Charsets.UTF_8)
}

companion object {
fun fromBytes(bytes: ByteArray): InvoiceCounterPartyDataOptions {
val optionsString = String(bytes)
return InvoiceCounterPartyDataOptions(
optionsString.split(",").mapNotNull {
val options = it.split(':')
if (options.size == 2) {
options[0] to CounterPartyDataOption(options[1] == "1")
} else null
}.toMap()
)
}
}
}

fun createCounterPartyDataOptions(map: Map<String, Boolean>): CounterPartyDataOptions {
return map.mapValues { CounterPartyDataOption(it.value) }
}
Expand Down
125 changes: 79 additions & 46 deletions uma-sdk/src/commonMain/kotlin/me/uma/protocol/Invoice.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package me.uma.protocol

import io.ktor.utils.io.core.toByteArray
import me.uma.utils.ByteCodeable
import me.uma.utils.TLVCodeable
import me.uma.utils.array
import me.uma.utils.getBoolean
import me.uma.utils.getByteCodeable
import me.uma.utils.getNumber
Expand All @@ -14,14 +17,16 @@ import me.uma.utils.putTLVCodeable
import me.uma.utils.putNumber
import me.uma.utils.putString
import me.uma.utils.valueOffset
import java.nio.ByteBuffer
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ByteArraySerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import org.bitcoinj.core.Bech32

private const val UMA_BECH32_PREFIX = "uma"

@Serializable(with = InvoiceCurrencyTLVSerializer::class)
data class InvoiceCurrency(
Expand Down Expand Up @@ -54,20 +59,12 @@ data class InvoiceCurrency(
}
}

override fun toTLV(): ByteArray {
val bytes = ByteBuffer.allocate(
2 + name.length +
2 + code.length +
2 + symbol.length +
3 // for int
)
.putString(0, code)
.putString(1, name)
.putString(2, symbol)
.putNumber(3, decimals)
.array()
return bytes
}
override fun toTLV() = mutableListOf<ByteArray>()
.putString(0, code)
.putString(1, name)
.putString(2, symbol)
.putNumber(3, decimals)
.array()
}

@OptIn(ExperimentalSerializationApi::class)
Expand All @@ -87,23 +84,6 @@ class InvoiceCurrencyTLVSerializer: KSerializer<InvoiceCurrency> {
)
}

@OptIn(ExperimentalSerializationApi::class)
class InvoiceTLVSerializer: KSerializer<Invoice> {
private val delegateSerializer = ByteArraySerializer()
override val descriptor = SerialDescriptor("Invoice", delegateSerializer.descriptor)

override fun serialize(encoder: Encoder, value: Invoice) {
encoder.encodeSerializableValue(
delegateSerializer,
value.toTLV()
)
}

override fun deserialize(decoder: Decoder) = Invoice.fromTLV(
decoder.decodeSerializableValue(delegateSerializer)
)
}

@Serializable(with = InvoiceTLVSerializer::class)
class Invoice(
val receiverUma: String,
Expand Down Expand Up @@ -148,10 +128,8 @@ class Invoice(
// The signature of the UMA invoice
val signature: ByteArray,
) : TLVCodeable {
override fun toTLV(): ByteArray {
val bytes = ByteBuffer.allocate(
256
)

override fun toTLV() = mutableListOf<ByteArray>()
.putString(0, receiverUma)
.putString(1, invoiceUUID)
.putNumber(2, amount)
Expand All @@ -163,16 +141,12 @@ class Invoice(
.putNumber(8, commentCharsAllowed)
.putString(9, senderUma)
.putNumber(10, invoiceLimit)
.putByteCodeable(11, KycStatusWrapper(kycStatus))
.putByteCodeable(11, InvoiceKycStatus(kycStatus))
.putString(12, callback)
.putByteArray(100, signature)
.array()
return bytes
}

fun justForFun() {

}
fun toBech32() = Bech32.encode(Bech32.Encoding.BECH32, UMA_BECH32_PREFIX, this.toTLV())

companion object {
fun fromTLV(bytes: ByteArray): Invoice {
Expand All @@ -194,9 +168,7 @@ class Invoice(
while(offset < bytes.size) {
val length = bytes[offset.lengthOffset()].toInt()
when(bytes[offset].toInt()) {
0 -> {
receiverUma = bytes.getString(offset.valueOffset(), length)
}
0 -> receiverUma = bytes.getString(offset.valueOffset(), length)
1 -> invoiceUUID = bytes.getString(offset.valueOffset(), length)
2 -> amount = bytes.getNumber(offset.valueOffset(), length)
3 -> receivingCurrency = bytes.getTLV(offset.valueOffset(), length, InvoiceCurrency::fromTLV) as InvoiceCurrency
Expand All @@ -211,7 +183,7 @@ class Invoice(
8 -> commentCharsAllowed = bytes.getNumber(offset.valueOffset(), length)
9 -> senderUma = bytes.getString(offset.valueOffset(), length)
10 -> invoiceLimit = bytes.getNumber(offset.valueOffset(), length)
11 -> kycStatus = (bytes.getByteCodeable(offset.valueOffset(), length, KycStatusWrapper::fromBytes) as KycStatusWrapper).status
11 -> kycStatus = (bytes.getByteCodeable(offset.valueOffset(), length, InvoiceKycStatus::fromBytes) as InvoiceKycStatus).status
12 -> callback = bytes.getString(offset.valueOffset(), length)
100 -> signature = bytes.sliceArray(offset.valueOffset()..< offset.valueOffset()+length
)
Expand All @@ -235,5 +207,66 @@ class Invoice(
signature = signature,
)
}

fun fromBech32(bech32String: String): Invoice {
val b32data = Bech32.decode(bech32String)
return fromTLV(b32data.data)
}
}
}

@OptIn(ExperimentalSerializationApi::class)
class InvoiceTLVSerializer: KSerializer<Invoice> {
private val delegateSerializer = ByteArraySerializer()
override val descriptor = SerialDescriptor("Invoice", delegateSerializer.descriptor)

override fun serialize(encoder: Encoder, value: Invoice) {
encoder.encodeSerializableValue(
delegateSerializer,
value.toTLV()
)
}

override fun deserialize(decoder: Decoder) = Invoice.fromTLV(
decoder.decodeSerializableValue(delegateSerializer)
)
}

data class InvoiceCounterPartyDataOptions(
val options: CounterPartyDataOptions
) : ByteCodeable {
override fun toBytes(): ByteArray {
val optionsString = options.map { (key, option) ->
"${key}:${ if (option.mandatory) 1 else 0}"
}.joinToString(",")
return optionsString.toByteArray(Charsets.UTF_8)
}

companion object {
fun fromBytes(bytes: ByteArray): InvoiceCounterPartyDataOptions {
val optionsString = String(bytes)
return InvoiceCounterPartyDataOptions(
optionsString.split(",").mapNotNull {
val options = it.split(':')
if (options.size == 2) {
options[0] to CounterPartyDataOption(options[1] == "1")
} else null
}.toMap()
)
}
}
}

data class InvoiceKycStatus(val status: KycStatus): ByteCodeable {
override fun toBytes(): ByteArray {
return status.rawValue.toByteArray()
}

companion object {
fun fromBytes(bytes: ByteArray): InvoiceKycStatus {
return InvoiceKycStatus(
KycStatus.fromRawValue(bytes.toString(Charsets.UTF_8))
)
}
}
}
15 changes: 0 additions & 15 deletions uma-sdk/src/commonMain/kotlin/me/uma/protocol/KycStatus.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import me.uma.utils.EnumSerializer
import me.uma.utils.serialFormat
import okio.Utf8

@Serializable(with = KycStatusSerializer::class)
enum class KycStatus(val rawValue: String) {
Expand All @@ -31,20 +30,6 @@ enum class KycStatus(val rawValue: String) {
}
}

data class KycStatusWrapper(val status: KycStatus): ByteCodeable {
override fun toBytes(): ByteArray {
return status.rawValue.toByteArray()
}

companion object {
fun fromBytes(bytes: ByteArray): KycStatusWrapper {
return KycStatusWrapper(
KycStatus.fromRawValue(bytes.toString(Charsets.UTF_8))
)
}
}
}

object KycStatusSerializer :
EnumSerializer<KycStatus>(
KycStatus::class,
Expand Down
Loading

0 comments on commit fb64f60

Please sign in to comment.