Skip to content

Commit dd2799d

Browse files
authored
Merge pull request #165 from muun/53.2-release-branch
Apollo: Release source code for 53.2
2 parents 62e09cd + 1bdf9f2 commit dd2799d

19 files changed

+659
-168
lines changed

android/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ follow [https://changelog.md/](https://changelog.md/) guidelines.
66

77
## [Unreleased]
88

9+
## [53.2] - 2025-03-24
10+
11+
### ADDED
12+
13+
- Alternative transactions signing
14+
915
## [53.1] - 2025-02-21
1016

1117
### ADDED

android/apollo/src/main/java/io/muun/apollo/data/net/ApiObjectsMapper.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import io.muun.common.utils.BitcoinUtils;
6464
import io.muun.common.utils.Encodings;
6565
import io.muun.common.utils.Pair;
66+
import io.muun.common.utils.Preconditions;
6667

6768
import android.os.SystemClock;
6869
import androidx.annotation.NonNull;
@@ -144,16 +145,25 @@ private BitcoinAmountJson mapBitcoinAmount(@NotNull BitcoinAmount bitcoinAmount)
144145
public OperationJson mapOperation(
145146
final @NotNull OperationWithMetadata operation,
146147
final List<String> outpoints,
147-
final MusigNonces musigNonces
148+
final MusigNonces musigNonces,
149+
final List<MusigNonces> alternativeTxNonces
148150
) {
149151

150152
final Long outputAmountInSatoshis = mapOutputAmountInSatoshis(operation);
151153

152154
final List<String> userPublicNoncesHex = new LinkedList<>();
153-
for (int i = 0; i < outpoints.size(); i++) {
155+
final long noncesCount = musigNonces.length();
156+
for (int i = 0; i < noncesCount; i++) {
154157
userPublicNoncesHex.add(musigNonces.getPubnonceHex(i));
155158
}
156159

160+
for (final MusigNonces nonces : alternativeTxNonces) {
161+
Preconditions.checkState(noncesCount == nonces.length());
162+
for (int i = 0; i < noncesCount; i++) {
163+
userPublicNoncesHex.add(nonces.getPubnonceHex(i));
164+
}
165+
}
166+
157167
return new OperationJson(
158168
UUID.randomUUID().toString(),
159169
operation.getDirection(),

android/apollo/src/main/java/io/muun/apollo/data/net/HoustonClient.java

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,13 @@
6262
import io.muun.common.api.IntegrityStatus;
6363
import io.muun.common.api.KeySet;
6464
import io.muun.common.api.LinkActionJson;
65+
import io.muun.common.api.OperationJson;
6566
import io.muun.common.api.PasswordSetupJson;
6667
import io.muun.common.api.PhoneConfirmation;
6768
import io.muun.common.api.PlayIntegrityTokenJson;
6869
import io.muun.common.api.PreimageJson;
6970
import io.muun.common.api.PublicKeySetJson;
71+
import io.muun.common.api.PushTransactionsJson;
7072
import io.muun.common.api.RawTransaction;
7173
import io.muun.common.api.SetupChallengeResponse;
7274
import io.muun.common.api.UpdateOperationMetadataJson;
@@ -100,6 +102,7 @@
100102
import rx.Observable;
101103
import rx.Single;
102104

105+
import java.util.ArrayList;
103106
import java.util.List;
104107
import javax.annotation.Nullable;
105108
import javax.inject.Inject;
@@ -603,10 +606,14 @@ public Observable<IntegrityStatus> checkIntegrity(IntegrityCheck integrityCheck)
603606
public Observable<OperationCreated> newOperation(
604607
final OperationWithMetadata operation,
605608
final List<String> outpoints,
606-
final MusigNonces musigNonces
609+
final MusigNonces musigNonces,
610+
final List<MusigNonces> alternativeTxNonces
607611
) {
612+
final OperationJson operationJson =
613+
apiMapper.mapOperation(operation, outpoints, musigNonces, alternativeTxNonces);
614+
608615
return getService()
609-
.newOperation(apiMapper.mapOperation(operation, outpoints, musigNonces))
616+
.newOperation(operationJson)
610617
.map(modelMapper::mapOperationCreated);
611618
}
612619

@@ -623,29 +630,44 @@ public Completable updateOperationMetadata(OperationWithMetadata operation) {
623630

624631
/**
625632
* Pushes a raw transaction to Houston.
626-
*
627-
* @param txHex The bitcoinj's transaction.
628-
* @param operationHid The houston operation id.
629633
*/
630-
public Observable<TransactionPushed> pushTransaction(
634+
public Observable<TransactionPushed> pushTransactions(
631635
@Nullable String txHex,
636+
@Nullable List<String> alternativeTransactionsHex,
632637
long operationHid
633638
) {
639+
final RawTransaction rawTransaction;
640+
final ArrayList<RawTransaction> alternativeTransactions = new ArrayList<RawTransaction>();
641+
634642
if (txHex != null) {
635-
return getService()
636-
.pushTransaction(new RawTransaction(txHex), operationHid)
637-
// This can happen if we determine the payment can't actually be made. If so, we
638-
// fail fast to avoid broadcasting a transaction saving the user on miner fees.
639-
.compose(ObservableFn.replaceHttpException(
640-
ErrorCode.SWAP_FAILED,
641-
SwapFailedException::new
642-
))
643-
.map(modelMapper::mapTransactionPushed);
643+
Preconditions.checkArgument(alternativeTransactionsHex != null);
644+
645+
rawTransaction = new RawTransaction(txHex);
646+
647+
for (var transactionHex : alternativeTransactionsHex) {
648+
alternativeTransactions.add(new RawTransaction(transactionHex));
649+
}
650+
644651
} else {
645-
return getService()
646-
.pushTransaction(operationHid) // empty body when txHex is not given
647-
.map(modelMapper::mapTransactionPushed);
652+
Preconditions.checkArgument(alternativeTransactionsHex == null);
653+
654+
rawTransaction = null;
648655
}
656+
657+
final var json = new PushTransactionsJson(
658+
rawTransaction,
659+
alternativeTransactions
660+
);
661+
662+
return getService()
663+
.pushTransactions(json, operationHid)
664+
// This can happen if we determine the payment can't actually be made. If so, we
665+
// fail fast to avoid broadcasting a transaction saving the user on miner fees.
666+
.compose(ObservableFn.replaceHttpException(
667+
ErrorCode.SWAP_FAILED,
668+
SwapFailedException::new
669+
))
670+
.map(modelMapper::mapTransactionPushed);
649671
}
650672

651673
/**

android/apollo/src/main/java/io/muun/apollo/data/net/ModelObjectsMapper.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import io.muun.common.api.NextTransactionSizeJson;
5454
import io.muun.common.api.OperationCreatedJson;
5555
import io.muun.common.api.OperationJson;
56+
import io.muun.common.api.PartiallySignedTransactionJson;
5657
import io.muun.common.api.PendingChallengeUpdateJson;
5758
import io.muun.common.api.PhoneNumberJson;
5859
import io.muun.common.api.PublicKeySetJson;
@@ -377,10 +378,26 @@ public OperationCreated mapOperationCreated(@NotNull OperationCreatedJson operat
377378
networkParameters
378379
),
379380
mapNextTransactionSize(operationCreated.nextTransactionSize),
380-
MuunAddress.fromJson(operationCreated.changeAddress)
381+
MuunAddress.fromJson(operationCreated.changeAddress),
382+
mapAlternativeTransactions(operationCreated.alternativeTransactions)
381383
);
382384
}
383385

386+
private List<PartiallySignedTransaction> mapAlternativeTransactions(
387+
@Nullable final List<PartiallySignedTransactionJson> txs
388+
) {
389+
if (txs == null) {
390+
return List.of();
391+
}
392+
393+
final var result = new ArrayList<PartiallySignedTransaction>();
394+
for (final var tx : txs) {
395+
result.add(PartiallySignedTransaction.fromJson(tx, networkParameters));
396+
}
397+
398+
return result;
399+
}
400+
384401
/**
385402
* Create a TransactionPushed object.
386403
*/

0 commit comments

Comments
 (0)