From 2a69085af1cd813dca4a43a3e926d7477e5c3eee Mon Sep 17 00:00:00 2001 From: Christian Rogobete Date: Tue, 2 Aug 2022 11:47:18 +0200 Subject: [PATCH] add txrep support for protocol 19 --- CHANGELOG.md | 3 + README.md | 2 +- documentation/sdk_examples/sep-0011-txrep.md | 18 +- lib/src/key_pair.dart | 12 + lib/src/sep/0011/txrep.dart | 264 +++++++++++++++++-- lib/src/stellar_sdk.dart | 2 +- pubspec.yaml | 2 +- test/sep0011_test.dart | 86 +++--- 8 files changed, 323 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35e68cd..feb3750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [1.3.5] - 02.Aug.2022. +- extend txrep to support protocol 19 + ## [1.3.4] - 28.July.2022. - add SEP-0007 implementation diff --git a/README.md b/README.md index 2d1f526..7b605fe 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Soneso open source Stellar SDK for Flutter is build with Dart and provides A 1. Add the dependency to your pubspec.yaml file: ``` dependencies: - stellar_flutter_sdk: ^1.3.4 + stellar_flutter_sdk: ^1.3.5 ``` 2. Install it (command line or IDE): ``` diff --git a/documentation/sdk_examples/sep-0011-txrep.md b/documentation/sdk_examples/sep-0011-txrep.md index 52e5dbb..b10ceef 100644 --- a/documentation/sdk_examples/sep-0011-txrep.md +++ b/documentation/sdk_examples/sep-0011-txrep.md @@ -22,9 +22,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GAVRMS4QIOCC4QMOSKILOOOHCSO4FEKOXZPNLKFFN6W7SD2KUB7NBPLN tx.fee: 100 tx.seqNum: 46489056724385793 -tx.timeBounds._present: true -tx.timeBounds.minTime: 1535756672 -tx.timeBounds.maxTime: 1567292672 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 1535756672 +tx.cond.timeBounds.maxTime: 1567292672 tx.memo.type: MEMO_TEXT tx.memo.text: "Enjoy this transaction" tx.operations.len: 1 @@ -58,9 +58,9 @@ feeBump.tx.innerTx.type: ENVELOPE_TYPE_TX feeBump.tx.innerTx.tx.sourceAccount: GAY6KB56YBPGGJU54RRLHGO3GBHEBZYTDY5VCBXEP4NLAUZNRSO4SSMH feeBump.tx.innerTx.tx.fee: 100 feeBump.tx.innerTx.tx.seqNum: 379748123410433 -feeBump.tx.innerTx.tx.timeBounds._present: true -feeBump.tx.innerTx.tx.timeBounds.minTime: 0 -feeBump.tx.innerTx.tx.timeBounds.maxTime: 0 +feeBump.tx.innerTx.tx.cond.type: PRECOND_TIME +feeBump.tx.innerTx.tx.cond.timeBounds.minTime: 0 +feeBump.tx.innerTx.tx.cond.timeBounds.maxTime: 0 feeBump.tx.innerTx.tx.memo.type: MEMO_TEXT feeBump.tx.innerTx.tx.memo.text: "hello" feeBump.tx.innerTx.tx.operations.len: 1 @@ -86,9 +86,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GAVRMS4QIOCC4QMOSKILOOOHCSO4FEKOXZPNLKFFN6W7SD2KUB7NBPLN tx.fee: 100 tx.seqNum: 46489056724385793 -tx.timeBounds._present: true -tx.timeBounds.minTime: 1535756672 (Fri Aug 31 16:04:32 PDT 2018) -tx.timeBounds.maxTime: 1567292672 (Sat Aug 31 16:04:32 PDT 2019) +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 1535756672 (Fri Aug 31 16:04:32 PDT 2018) +tx.cond.timeBounds.maxTime: 1567292672 (Sat Aug 31 16:04:32 PDT 2019) tx.memo.type: MEMO_TEXT tx.memo.text: "Enjoy this transaction" tx.operations.len: 1 diff --git a/lib/src/key_pair.dart b/lib/src/key_pair.dart index ff48308..82a83bd 100644 --- a/lib/src/key_pair.dart +++ b/lib/src/key_pair.dart @@ -91,6 +91,13 @@ class StrKey { VersionByte.SIGNED_PAYLOAD, xdrOutputStream.data.toUint8List()); } + static String encodeXdrSignedPayload(XdrSignedPayload xdrPayloadSigner) { + var xdrOutputStream = XdrDataOutputStream(); + XdrSignedPayload.encode(xdrOutputStream, xdrPayloadSigner); + return encodeCheck( + VersionByte.SIGNED_PAYLOAD, xdrOutputStream.data.toUint8List()); + } + static SignedPayloadSigner decodeSignedPayload(String data) { Uint8List signedPayloadRaw = decodeCheck(VersionByte.SIGNED_PAYLOAD, data); XdrSignedPayload xdrPayloadSigner = @@ -101,6 +108,11 @@ class StrKey { return result; } + static XdrSignedPayload decodeXdrSignedPayload(String data) { + Uint8List signedPayloadRaw = decodeCheck(VersionByte.SIGNED_PAYLOAD, data); + return XdrSignedPayload.decode(XdrDataInputStream(signedPayloadRaw));; + } + static String encodeCheck(VersionByte versionByte, Uint8List data) { List output = []; output.add(versionByte.getValue()); diff --git a/lib/src/sep/0011/txrep.dart b/lib/src/sep/0011/txrep.dart index a60f926..ae1b24f 100644 --- a/lib/src/sep/0011/txrep.dart +++ b/lib/src/sep/0011/txrep.dart @@ -57,7 +57,7 @@ class TxRep { _addLine('${prefix}fee', tx.fee.toString(), lines); _addLine('${prefix}seqNum', tx.sequenceNumber.toString(), lines); - _addTimeBounds(tx.preconditions?.timeBounds, lines, prefix); + _addPreconditions(tx.preconditions!, lines, prefix); _addMemo(tx.memo, lines, prefix); _addOperations(tx.operations, lines, prefix); _addLine('${prefix}ext.v', '0', lines); @@ -166,24 +166,7 @@ class TxRep { Account sourceAccount = Account(mux!.ed25519AccountId, sequenceNumber - 1, muxedAccountMed25519Id: mux.id); TransactionBuilder txBuilder = TransactionBuilder(sourceAccount); - - // TimeBounds - if (_removeComment(map['${prefix}timeBounds._present']) == 'true' && - map['${prefix}timeBounds.minTime'] != null && - map['${prefix}timeBounds.maxTime'] != null) { - try { - int? minTime = - int.tryParse(_removeComment(map['${prefix}timeBounds.minTime'])!); - int? maxTime = - int.tryParse(_removeComment(map['${prefix}timeBounds.maxTime'])!); - TimeBounds timeBounds = TimeBounds(minTime!, maxTime!); - txBuilder.addTimeBounds(timeBounds); - } catch (e) { - throw Exception('invalid ${prefix}timeBounds'); - } - } else if (_removeComment(map['${prefix}timeBounds._present']) == 'true') { - throw Exception('invalid ${prefix}timeBounds'); - } + txBuilder.addPreconditions(_getPreconditions(map, prefix)); // Memo String? memoType = _removeComment(map['${prefix}memo.type']); @@ -293,6 +276,177 @@ class TxRep { return transaction.toEnvelopeXdrBase64(); } + static TransactionPreconditions _getPreconditions(Map map, String prefix) { + // Preconditions + TransactionPreconditions cond = TransactionPreconditions(); + String? preonditionsType = _removeComment(map['${prefix}cond.type']); + if (preonditionsType != null && preonditionsType == "PRECOND_TIME") { + String precondPrefix = '${prefix}cond.'; + if (map['${precondPrefix}timeBounds.minTime'] != null && + map['${precondPrefix}timeBounds.maxTime'] != null) { + try { + int? minTime = int.tryParse( + _removeComment(map['${precondPrefix}timeBounds.minTime'])!); + int? maxTime = int.tryParse( + _removeComment(map['${precondPrefix}timeBounds.maxTime'])!); + TimeBounds timeBounds = TimeBounds(minTime!, maxTime!); + cond.timeBounds = timeBounds; + return cond; + } catch (e) { + throw Exception('invalid ${precondPrefix}timeBounds'); + } + } + } else if (preonditionsType != null && preonditionsType == "PRECOND_V2") { + String precondPrefix = '${prefix}cond.v2.'; + cond.timeBounds = _getTimeBounds(map, precondPrefix); + cond.ledgerBounds = _getLedgerBounds(map, precondPrefix); + + if (_removeComment(map['${precondPrefix}minSeqNum._present']) == 'true' && + map['${precondPrefix}minSeqNum'] != null) { + int? minSeqNum = + int.tryParse(_removeComment(map['${precondPrefix}minSeqNum'])!); + if (minSeqNum == null) { + throw Exception('invalid ${precondPrefix}minSeqNum'); + } + cond.minSeqNumber = minSeqNum; + } else if (_removeComment(map['${precondPrefix}minSeqNum._present']) == + 'true') { + throw Exception('missing ${prefix}minSeqNum'); + } + + int? minSeqAge; + if (map['${precondPrefix}minSeqAge'] != null) { + minSeqAge = + int.tryParse(_removeComment(map['${precondPrefix}minSeqAge'])!); + } + if (minSeqAge == null) { + throw Exception('missing ${precondPrefix}minSeqAge'); + } + cond.minSeqAge = minSeqAge; + + int? minSeqLedgerGap; + if (map['${precondPrefix}minSeqLedgerGap'] != null) { + minSeqLedgerGap = int.tryParse( + _removeComment(map['${precondPrefix}minSeqLedgerGap'])!); + } + if (minSeqLedgerGap == null) { + throw Exception('missing ${precondPrefix}minSeqLedgerGap'); + } + cond.minSeqLedgerGap = minSeqLedgerGap; + + List? extraSigners; + String? extraSignersLen = + _removeComment(map['${precondPrefix}extraSigners.len']); + if (extraSignersLen == null) { + throw Exception('missing ${precondPrefix}extraSigners.len'); + } + int nrOfExtraSigners; + try { + nrOfExtraSigners = int.parse(extraSignersLen); + } catch (e) { + throw Exception('invalid ${precondPrefix}extraSigners.len'); + } + if (nrOfExtraSigners > 2) { + throw Exception('invalid ${prefix}extraSigners.len- greater than 2'); + } + if (nrOfExtraSigners > 0) { + extraSigners = []; + for (int i = 0; i < nrOfExtraSigners; i++) { + String? key = _removeComment( + map[precondPrefix + 'extraSigners[' + i.toString() + ']']); + if (key == null) { + throw Exception('missing $precondPrefix' + + 'extraSigners[' + + i.toString() + + ']'); + } + try { + if (key.startsWith('G')) { + XdrSignerKey signer = XdrSignerKey(); + signer.discriminant = XdrSignerKeyType.SIGNER_KEY_TYPE_ED25519; + signer.ed25519 = XdrUint256(); + signer.ed25519!.uint256 = StrKey.decodeStellarAccountId(key); + extraSigners.add(signer); + } else if (key.startsWith('T')) { + XdrSignerKey signer = XdrSignerKey(); + signer.discriminant = + XdrSignerKeyType.SIGNER_KEY_TYPE_PRE_AUTH_TX; + signer.preAuthTx = XdrUint256(); + signer.preAuthTx!.uint256 = StrKey.decodePreAuthTx(key); + extraSigners.add(signer); + } else if (key.startsWith('X')) { + XdrSignerKey signer = XdrSignerKey(); + signer.discriminant = XdrSignerKeyType.SIGNER_KEY_TYPE_HASH_X; + signer.hashX = XdrUint256(); + signer.hashX!.uint256 = StrKey.decodeSha256Hash(key); + extraSigners.add(signer); + } else if (key.startsWith('P')) { + XdrSignerKey signer = XdrSignerKey(); + signer.discriminant = + XdrSignerKeyType.KEY_TYPE_ED25519_SIGNED_PAYLOAD; + XdrSignedPayload payload = StrKey.decodeXdrSignedPayload(key); + signer.signedPayload = payload; + extraSigners.add(signer); + } else { + throw Exception('invalid $precondPrefix' + + 'extraSigners[' + + i.toString() + + ']'); + } + } catch (e) { + throw Exception('invalid $precondPrefix' + + 'extraSigners[' + + i.toString() + + ']'); + } + } + } + cond.extraSigners = extraSigners; + return cond; + } + + cond.timeBounds = _getTimeBounds(map, prefix); + return cond; + } + + static TimeBounds? _getTimeBounds(Map map, String prefix) { + if (_removeComment(map['${prefix}timeBounds._present']) == 'true' && + map['${prefix}timeBounds.minTime'] != null && + map['${prefix}timeBounds.maxTime'] != null) { + try { + int? minTime = + int.tryParse(_removeComment(map['${prefix}timeBounds.minTime'])!); + int? maxTime = + int.tryParse(_removeComment(map['${prefix}timeBounds.maxTime'])!); + return TimeBounds(minTime!, maxTime!); + } catch (e) { + throw Exception('invalid ${prefix}timeBounds'); + } + } else if (_removeComment(map['${prefix}timeBounds._present']) == 'true') { + throw Exception('invalid ${prefix}timeBounds'); + } + } + + static LedgerBounds? _getLedgerBounds( + Map map, String prefix) { + if (_removeComment(map['${prefix}ledgerBounds._present']) == 'true' && + map['${prefix}ledgerBounds.minLedger'] != null && + map['${prefix}ledgerBounds.maxLedger'] != null) { + try { + int? minLedger = int.tryParse( + _removeComment(map['${prefix}ledgerBounds.minLedger'])!); + int? maxLedger = int.tryParse( + _removeComment(map['${prefix}ledgerBounds.maxLedger'])!); + return LedgerBounds(minLedger!, maxLedger!); + } catch (e) { + throw Exception('invalid ${prefix}ledgerBounds'); + } + } else if (_removeComment(map['${prefix}ledgerBounds._present']) == + 'true') { + throw Exception('invalid ${prefix}ledgerBounds'); + } + } + static XdrDecoratedSignature? _getSignature( int index, Map map, String prefix) { String? hintStr = _removeComment(map['${prefix}signatures[$index].hint']); @@ -2074,6 +2228,58 @@ class TxRep { lines.add('$key: $value'); } + static _addPreconditions( + TransactionPreconditions? cond, List? lines, String prefix) { + if (lines == null) return; + if (cond == null || (!cond.hasV2() && cond.timeBounds == null)) { + _addLine('${prefix}cond.type', 'PRECOND_NONE', lines); + return; + } + if (cond.hasV2()) { + _addLine('${prefix}cond.type', 'PRECOND_V2', lines); + String precondPrefix = prefix + "cond.v2."; + _addTimeBounds(cond.timeBounds, lines, precondPrefix); + _addLedgerBounds(cond.ledgerBounds, lines, precondPrefix); + + if (cond.minSeqNumber != null) { + _addLine('${precondPrefix}minSeqNum._present', 'true', lines); + _addLine( + '${precondPrefix}minSeqNum', cond.minSeqNumber.toString(), lines); + } else { + _addLine('${precondPrefix}minSeqNum._present', 'false', lines); + } + _addLine('${precondPrefix}minSeqAge', cond.minSeqAge.toString(), lines); + _addLine('${precondPrefix}minSeqLedgerGap', + cond.minSeqLedgerGap.toString(), lines); + + _addLine('${precondPrefix}extraSigners.len', + cond.extraSigners!.length.toString(), lines); + int index = 0; + for (XdrSignerKey? key in cond.extraSigners!) { + if (key?.ed25519 != null) { + _addLine('${precondPrefix}extraSigners[${index.toString()}]', + StrKey.encodeStellarAccountId(key!.ed25519!.uint256!), lines); + } else if (key?.preAuthTx != null) { + _addLine('${precondPrefix}extraSigners[${index.toString()}]', + StrKey.encodePreAuthTx(key!.preAuthTx!.uint256!), lines); + } else if (key?.hashX != null) { + _addLine('${precondPrefix}extraSigners[${index.toString()}]', + StrKey.encodeSha256Hash(key!.hashX!.uint256!), lines); + } else if (key?.signedPayload != null) { + _addLine('${precondPrefix}extraSigners[${index.toString()}]', + StrKey.encodeXdrSignedPayload(key!.signedPayload!), lines); + } + index++; + } + } else if (cond.timeBounds != null) { + _addLine('${prefix}cond.type', 'PRECOND_TIME', lines); + _addLine('${prefix}cond.timeBounds.minTime', + cond.timeBounds!.minTime.toString(), lines); + _addLine('${prefix}cond.timeBounds.maxTime', + cond.timeBounds!.maxTime.toString(), lines); + } + } + static _addTimeBounds( TimeBounds? timeBounds, List? lines, String prefix) { if (lines == null) return; @@ -2088,6 +2294,20 @@ class TxRep { } } + static _addLedgerBounds( + LedgerBounds? ledgerBounds, List? lines, String prefix) { + if (lines == null) return; + if (ledgerBounds == null) { + _addLine('${prefix}ledgerBounds._present', 'false', lines); + } else { + _addLine('${prefix}ledgerBounds._present', 'true', lines); + _addLine('${prefix}ledgerBounds.minLedger', + ledgerBounds.minLedger.toString(), lines); + _addLine('${prefix}ledgerBounds.maxLedger', + ledgerBounds.maxLedger.toString(), lines); + } + } + static _addMemo(Memo? memo, List? lines, String prefix) { if (lines == null || memo == null) return; if (memo is MemoNone) { @@ -2263,8 +2483,12 @@ class TxRep { '$prefix.signer.key', StrKey.encodeSha256Hash(operation.signer!.hashX!.uint256!), lines); + } else if (operation.signer?.signedPayload != null) { + _addLine( + '$prefix.signer.key', + StrKey.encodeXdrSignedPayload(operation.signer!.signedPayload!), + lines); } - _addLine( '$prefix.signer.weight', operation.signerWeight.toString(), lines); } else { diff --git a/lib/src/stellar_sdk.dart b/lib/src/stellar_sdk.dart index b232757..fe19dca 100644 --- a/lib/src/stellar_sdk.dart +++ b/lib/src/stellar_sdk.dart @@ -29,7 +29,7 @@ import 'requests/liquidity_pools_request_builder.dart'; /// Main class of the flutter stellar sdk. class StellarSDK { - static const versionNumber = "1.3.4"; + static const versionNumber = "1.3.5"; static final StellarSDK PUBLIC = StellarSDK("https://horizon.stellar.org"); static final StellarSDK TESTNET = diff --git a/pubspec.yaml b/pubspec.yaml index 232e3e7..21e9ec6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: stellar_flutter_sdk description: A stellar blockchain sdk that query's horizon, build, signs and submits transactions to the stellar network. -version: 1.3.4 +version: 1.3.5 homepage: https://github.com/Soneso/stellar_flutter_sdk environment: diff --git a/test/sep0011_test.dart b/test/sep0011_test.dart index 71948bc..be920a8 100644 --- a/test/sep0011_test.dart +++ b/test/sep0011_test.dart @@ -13,9 +13,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GDICQ4HZOFVPJF7QNLHOUFUBNAH3TN4AJSRHZKFQH25I465VDVQE4ZS2 tx.fee: 1400 tx.seqNum: 1102902109202 -tx.timeBounds._present: true -tx.timeBounds.minTime: 1595282368 -tx.timeBounds.maxTime: 1595284000 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 1595282368 +tx.cond.timeBounds.maxTime: 1595284000 tx.memo.type: MEMO_TEXT tx.memo.text: "Enjoy this transaction" tx.operations.len: 14 @@ -271,9 +271,9 @@ feeBump.tx.innerTx.type: ENVELOPE_TYPE_TX feeBump.tx.innerTx.tx.sourceAccount: GDXLKEY5TR4IDEV7FZWYFG6MA6M24YDCX5HENQ7DTESBE233EHT6HHGK feeBump.tx.innerTx.tx.fee: 1400 feeBump.tx.innerTx.tx.seqNum: 1102902109202 -feeBump.tx.innerTx.tx.timeBounds._present: true -feeBump.tx.innerTx.tx.timeBounds.minTime: 1595282368 (Mon Jul 20 23:59:28 CEST 2020) -feeBump.tx.innerTx.tx.timeBounds.maxTime: 1595284000 (Tue Jul 21 00:26:40 CEST 2020) +feeBump.tx.innerTx.tx.cond.type: PRECOND_TIME +feeBump.tx.innerTx.tx.cond.timeBounds.minTime: 1595282368 (Mon Jul 20 23:59:28 CEST 2020) +feeBump.tx.innerTx.tx.cond.timeBounds.maxTime: 1595284000 (Tue Jul 21 00:26:40 CEST 2020) feeBump.tx.innerTx.tx.memo.type: MEMO_TEXT feeBump.tx.innerTx.tx.memo.text: "Enjoy this transaction" feeBump.tx.innerTx.tx.operations.len: 14 @@ -394,9 +394,9 @@ feeBump.tx.innerTx.type: ENVELOPE_TYPE_TX feeBump.tx.innerTx.tx.sourceAccount: GDXLKEY5TR4IDEV7FZWYFG6MA6M24YDCX5HENQ7DTESBE233EHT6HHGK feeBump.tx.innerTx.tx.fee: 1400 feeBump.tx.innerTx.tx.seqNum: 1102902109202 -feeBump.tx.innerTx.tx.timeBounds._present: true -feeBump.tx.innerTx.tx.timeBounds.minTime: 1595282368 -feeBump.tx.innerTx.tx.timeBounds.maxTime: 1595284000 +feeBump.tx.innerTx.tx.cond.type: PRECOND_TIME +feeBump.tx.innerTx.tx.cond.timeBounds.minTime: 1595282368 +feeBump.tx.innerTx.tx.cond.timeBounds.maxTime: 1595284000 feeBump.tx.innerTx.tx.memo.type: MEMO_TEXT feeBump.tx.innerTx.tx.memo.text: "Enjoy this transaction" feeBump.tx.innerTx.tx.operations.len: 14 @@ -669,9 +669,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 100 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 1 tx.operations[0].sourceAccount._present: true @@ -735,9 +735,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 100 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 1 tx.operations[0].sourceAccount._present: false @@ -764,9 +764,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 200 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 2 tx.operations[0].sourceAccount._present: true @@ -787,6 +787,7 @@ signatures[0].signature: 194a962d2f51ae1af1c4bfa3e8eeca7aa2b6654a84ac03de37d1738 String xdr = TxRep.transactionEnvelopeXdrBase64FromTxRep(txRep); assert(expected == xdr); String txRepResult = TxRep.fromTransactionEnvelopeXdrBase64(xdr); + print(txRepResult); assert(txRepResult == txRep); }); @@ -796,9 +797,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 800 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 8 tx.operations[0].sourceAccount._present: false @@ -866,9 +867,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 100 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 1 tx.operations[0].sourceAccount._present: true @@ -897,9 +898,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 100 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 1 tx.operations[0].sourceAccount._present: false @@ -926,9 +927,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 200 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 2 tx.operations[0].sourceAccount._present: true @@ -955,7 +956,6 @@ signatures[0].signature: 5d4569d07068fd4824c87bf531061cf962a820d9ac5d4fdda0a2728 String xdr = TxRep.transactionEnvelopeXdrBase64FromTxRep(txRep); assert(expected == xdr); String txRepResult = TxRep.fromTransactionEnvelopeXdrBase64(xdr); - print(txRepResult); assert(txRepResult == txRep); }); @@ -965,9 +965,9 @@ type: ENVELOPE_TYPE_TX tx.sourceAccount: GBCJLPKHE2QTXTYZNZG6K3OBRPHJHABT2MG6JLAMM5FOARHM2GL67VCW tx.fee: 200 tx.seqNum: 2916609211498497 -tx.timeBounds._present: true -tx.timeBounds.minTime: 0 -tx.timeBounds.maxTime: 0 +tx.cond.type: PRECOND_TIME +tx.cond.timeBounds.minTime: 0 +tx.cond.timeBounds.maxTime: 0 tx.memo.type: MEMO_NONE tx.operations.len: 2 tx.operations[0].sourceAccount._present: true @@ -1000,4 +1000,22 @@ signatures[0].signature: ed97d0d018a671c5a914a15346c1b38912d6695d1d152ffe976b8c9 print(txRepResult); assert(txRepResult == txRep); }); + + test('xdr preconditions 1', () { + String xdr = + 'AAAAAgAAAQAAAAAAABODoXOW2Y6q7AdenusH1X8NBxVPFXEW+/PQFDiBQV05qf4DAAAAZAAKAJMAAAACAAAAAgAAAAEAAAAAYnk1lQAAAABobxaVAAAAAQANnJQAHN7UAAAAAQAKAJMAAAABAAAAAAAAAAEAAAABAAAAAgAAAACUkeBPpCcGYCoqeszK1YjZ1Ww1qY6fRI02d2hKG1nqvwAAAAHW9EEhELfDtkfmtBrXuEgEpTBlO8E/iQ2ZI/uNXLDV9AAAAAEAAAAEdGVzdAAAAAEAAAABAAABAAAAAAAAE4Ohc5bZjqrsB16e6wfVfw0HFU8VcRb789AUOIFBXTmp/gMAAAABAAABAAAAAAJPOttvlJHgT6QnBmAqKnrMytWI2dVsNamOn0SNNndoShtZ6r8AAAAAAAAAAADk4cAAAAAAAAAAATmp/gMAAABAvm+8CxO9sj4KEDwSS6hDxZAiUGdpIN2l+KOxTIkdI2joBFjT9B1U9YaORVDx4LTrLd4QM2taUuzXB51QtDQYDA=='; + String txrep = TxRep.fromTransactionEnvelopeXdrBase64(xdr); + print(txrep); + String xdr2 = TxRep.transactionEnvelopeXdrBase64FromTxRep(txrep); + assert(xdr == xdr2); + }); + + test('xdr preconditions 2', () { + String xdr = + 'AAAAAgAAAQAAAAAAABODoa9e0m5apwHpUf3/HzJOJeQ5q7+CwSWrnHXENS8XoAfmAAAAZAAJ/s4AAAACAAAAAgAAAAEAAAAAYnk1lQAAAABobxaVAAAAAQANnJQAHN7UAAAAAQAJ/s4AAAABAAAAAAAAAAEAAAABAAAAAgAAAAJulGoyRpAB8JhKT+ffEiXh8Kgd8qrEXfiG3aK69JgQlAAAAAM/DDS/k60NmXHQTMyQ9wVRHIOKrZc0pKL7DXoD/H/omgAAACABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fIAAAAAEAAAAEdGVzdAAAAAEAAAABAAABAAAAAAAAE4Ohr17SblqnAelR/f8fMk4l5Dmrv4LBJaucdcQ1LxegB+YAAAABAAABAAAAAAJPOttvipEw04NyfzwAhgQlf2S77YVGYbytcXKVNuM46+sMNAYAAAAAAAAAAADk4cAAAAAAAAAAARegB+YAAABAJG8wTpECV0rpq3TV9d26UL0MULmDxXKXGmKSJLiy9NCNJW3WMcrvrA6wiBsLHuCN7sIurD3o1/AKgntagup3Cw=='; + String txrep = TxRep.fromTransactionEnvelopeXdrBase64(xdr); + print(txrep); + String xdr2 = TxRep.transactionEnvelopeXdrBase64FromTxRep(txrep); + assert(xdr == xdr2); + }); }