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
6 changes: 3 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ android {
applicationId = "com.lobstr.stellar.vault"
minSdk = 24
targetSdk = 36
versionCode = 57
versionName = "3.6.4"
versionCode = 58
versionName = "3.6.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

Expand Down Expand Up @@ -186,7 +186,7 @@ val androidx_legacy_support_v4 by extra("1.0.0")
val junit by extra("4.13.2")
val runner by extra("1.3.0")
val espresso_core by extra("3.7.0")
val stellar_sdk by extra("3.0.0")
val stellar_sdk by extra("4.0.0")
val mnemonic by extra("0.1.1")
val work_manager by extra("2.11.2")
val biometric by extra("1.1.0")
Expand Down
2 changes: 1 addition & 1 deletion tsmapper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ android {
namespace = "com.lobstr.stellar.tsmapper"
}

val stellar_sdk by extra("3.0.0")
val stellar_sdk by extra("4.0.0")
val gson by extra("2.14.0")
val firebase_bom by extra("34.12.0")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.s
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanAuthorizedFunction
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanAuthorizedInvocation
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanCredentials
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanDelegateSignature
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.contract.ContractExecutable
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.contract.ContractIDPreimage
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.contract.CreateContractArgs
Expand Down Expand Up @@ -109,8 +110,33 @@ class InvokeHostFunctionMapper(val assetMapper: AssetMapper = AssetMapper(), val
credentials.address.signatureExpirationLedger.uint32.number.toString(),
scMapper.mapScVal(credentials.address.signature)
)
// CAP-71 (Protocol 27): same SorobanAddressCredentials payload as ADDRESS.
org.stellar.sdk.xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2 -> SorobanCredentials.AddressV2(
scMapper.mapScAddress(Address.fromSCAddress(credentials.addressV2.address)),
credentials.addressV2.nonce.int64.toString(),
credentials.addressV2.signatureExpirationLedger.uint32.number.toString(),
scMapper.mapScVal(credentials.addressV2.signature)
)
// CAP-71 (Protocol 27): base address credentials + recursive delegate-signature tree.
org.stellar.sdk.xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES -> {
val addressCredentials = credentials.addressWithDelegates.addressCredentials
SorobanCredentials.AddressWithDelegates(
scMapper.mapScAddress(Address.fromSCAddress(addressCredentials.address)),
addressCredentials.nonce.int64.toString(),
addressCredentials.signatureExpirationLedger.uint32.number.toString(),
scMapper.mapScVal(addressCredentials.signature),
credentials.addressWithDelegates.delegates.map { mapSorobanDelegateSignature(it) }
)
}
}

private fun mapSorobanDelegateSignature(delegate: org.stellar.sdk.xdr.SorobanDelegateSignature): SorobanDelegateSignature =
SorobanDelegateSignature(
scMapper.mapScAddress(Address.fromSCAddress(delegate.address)),
scMapper.mapScVal(delegate.signature),
delegate.nestedDelegates.map { mapSorobanDelegateSignature(it) }
)

private fun mapSorobanAuthorizedInvocation(invocation: org.stellar.sdk.xdr.SorobanAuthorizedInvocation) : SorobanAuthorizedInvocation =
SorobanAuthorizedInvocation(mapSorobanAuthorizationFunction(invocation.function), mutableListOf<SorobanAuthorizedInvocation>().apply {
invocation.subInvocations.forEach {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.s
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanAuthorizedFunction
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanAuthorizedInvocation
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanCredentials
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth.SorobanDelegateSignature
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.contract.ContractExecutable
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.contract.ContractIDPreimage
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.contract.CreateContractArgs
Expand Down Expand Up @@ -432,31 +433,74 @@ data class InvokeHostFunctionOperation(
)
)

is SorobanCredentials.Address -> {
fields.add(OperationField(
context.getString(R.string.op_field_credentials),
context.getString(R.string.op_value_address)
))

getScAddressFields(context, fields, credentials.address)

fields.add(OperationField(
context.getString(R.string.op_field_nonce),
credentials.nonce
))
is SorobanCredentials.Address -> addAddressCredentialFields(
context, fields, credentials.address, credentials.nonce,
credentials.signatureExpirationLedger, credentials.signature, amountFormatter
)

fields.add(OperationField(
context.getString(R.string.op_field_signature_expiration_ledger),
credentials.signatureExpirationLedger
))
// CAP-71 (Protocol 27): same payload as Address.
is SorobanCredentials.AddressV2 -> addAddressCredentialFields(
context, fields, credentials.address, credentials.nonce,
credentials.signatureExpirationLedger, credentials.signature, amountFormatter
)

getScValFields(context, fields, credentials.signature, amountFormatter)
// CAP-71 (Protocol 27): base address credentials + recursive delegate-signature tree.
is SorobanCredentials.AddressWithDelegates -> {
addAddressCredentialFields(
context, fields, credentials.address, credentials.nonce,
credentials.signatureExpirationLedger, credentials.signature, amountFormatter
)
credentials.delegates.forEach { getDelegateFields(context, fields, it, amountFormatter) }
}
}

return fields
}

private fun addAddressCredentialFields(
context: Context,
fields: MutableList<OperationField>,
address: SCAddress,
nonce: String,
signatureExpirationLedger: String,
signature: SCVal,
amountFormatter: (value: String) -> String
): MutableList<OperationField> {
fields.add(OperationField(
context.getString(R.string.op_field_credentials),
context.getString(R.string.op_value_address)
))

getScAddressFields(context, fields, address)

fields.add(OperationField(
context.getString(R.string.op_field_nonce),
nonce
))

fields.add(OperationField(
context.getString(R.string.op_field_signature_expiration_ledger),
signatureExpirationLedger
))

getScValFields(context, fields, signature, amountFormatter)

return fields
}

private fun getDelegateFields(
context: Context,
fields: MutableList<OperationField>,
delegate: SorobanDelegateSignature,
amountFormatter: (value: String) -> String
): MutableList<OperationField> {
getScAddressFields(context, fields, delegate.address)
getScValFields(context, fields, delegate.signature, amountFormatter)
delegate.nestedDelegates.forEach { getDelegateFields(context, fields, it, amountFormatter) }

return fields
}

private fun getAuthorizedInvocationFields(
context: Context,
fields: MutableList<OperationField>, invocation: SorobanAuthorizedInvocation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,23 @@ sealed class SorobanCredentials : Parcelable {
val signatureExpirationLedger: String,
val signature: SCVal
) : SorobanCredentials()

// CAP-71 (Protocol 27): address-bound signature variant. Same payload shape as [Address];
// kept as a distinct type so the auth scheme (discriminant) is never conflated with V1.
data class AddressV2(
val address: SCAddress,
val nonce: String,
val signatureExpirationLedger: String,
val signature: SCVal
) : SorobanCredentials()

// CAP-71 (Protocol 27): delegated / multi-party signing. Base address credentials plus a
// (recursive) tree of delegate signatures.
data class AddressWithDelegates(
val address: SCAddress,
val nonce: String,
val signatureExpirationLedger: String,
val signature: SCVal,
val delegates: List<SorobanDelegateSignature>
) : SorobanCredentials()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.auth

import android.os.Parcelable
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.other.SCAddress
import com.lobstr.stellar.tsmapper.presentation.entities.transaction.operation.soroban.other.SCVal
import kotlinx.parcelize.Parcelize

// CAP-71 (Protocol 27): a single delegate's signature inside an ADDRESS_WITH_DELEGATES
// credential. Delegates form a recursive tree via [nestedDelegates].
@Parcelize
data class SorobanDelegateSignature(
val address: SCAddress,
val signature: SCVal,
val nestedDelegates: List<SorobanDelegateSignature>
) : Parcelable