Skip to content

Commit

Permalink
add txrep support for protocol 19
Browse files Browse the repository at this point in the history
  • Loading branch information
christian-rogobete committed Aug 2, 2022
1 parent 95555ea commit 2a69085
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 66 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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):
```
Expand Down
18 changes: 9 additions & 9 deletions documentation/sdk_examples/sep-0011-txrep.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
12 changes: 12 additions & 0 deletions lib/src/key_pair.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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<int> output = [];
output.add(versionByte.getValue());
Expand Down
264 changes: 244 additions & 20 deletions lib/src/sep/0011/txrep.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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']);
Expand Down Expand Up @@ -293,6 +276,177 @@ class TxRep {
return transaction.toEnvelopeXdrBase64();
}

static TransactionPreconditions _getPreconditions(Map<String, String> 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<XdrSignerKey>? 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<String, String> 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<String, String> 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<String, String> map, String prefix) {
String? hintStr = _removeComment(map['${prefix}signatures[$index].hint']);
Expand Down Expand Up @@ -2074,6 +2228,58 @@ class TxRep {
lines.add('$key: $value');
}

static _addPreconditions(
TransactionPreconditions? cond, List<String>? 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<String>? lines, String prefix) {
if (lines == null) return;
Expand All @@ -2088,6 +2294,20 @@ class TxRep {
}
}

static _addLedgerBounds(
LedgerBounds? ledgerBounds, List<String>? 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<String>? lines, String prefix) {
if (lines == null || memo == null) return;
if (memo is MemoNone) {
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/stellar_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Loading

0 comments on commit 2a69085

Please sign in to comment.