transactionEnvelopeXdrBase64FromTxRep method

String transactionEnvelopeXdrBase64FromTxRep (
  1. String txRep
)

returns a base64 encoded transaction envelope xdr by parsing txRep.

Implementation

static String transactionEnvelopeXdrBase64FromTxRep(String txRep) {
  if (txRep == null) {
    throw Exception('txRep can not be null');
  }
  List<String> lines = txRep.split('\n'); //TODO: handle newline within string
  Map<String, String> map = Map<String, String>();
  for (String line in lines) {
    var parts = line.split(':');
    if (parts.length > 1) {
      String key = parts[0].trim();
      String value = parts.sublist(1).join(':').trim();
      map.addAll({key: value});
    }
  }
  String prefix = 'tx.';
  bool isFeeBump = _removeComment(map['type']) == 'ENVELOPE_TYPE_TX_FEE_BUMP';
  int feeBumpFee;
  String feeBumpSource = _removeComment(map['feeBump.tx.feeSource']);

  if (isFeeBump) {
    prefix = 'feeBump.tx.innerTx.tx.';
    String feeBumpFeeStr = _removeComment(map['feeBump.tx.fee']);
    if (feeBumpFeeStr == null) {
      throw Exception('missing feeBump.tx.fee');
    }
    try {
      feeBumpFee = int.parse(feeBumpFeeStr);
    } catch (e) {
      throw Exception('invalid feeBump.tx.fee');
    }
    if (feeBumpFee == null) {
      throw Exception('invalid feeBump.tx.fee');
    }

    if (feeBumpSource == null) {
      throw Exception('missing feeBump.tx.feeSource');
    }
    KeyPair feeBumpSourceKeyPair;
    try {
      feeBumpSourceKeyPair = KeyPair.fromAccountId(feeBumpSource);
    } catch (e) {
      throw Exception('invalid feeBump.tx.feeSource');
    }
    if (feeBumpSourceKeyPair == null) {
      throw Exception('invalid feeBump.tx.feeSource');
    }
  }

  String sourceAccountId = _removeComment(map['${prefix}sourceAccount']);
  if (sourceAccountId == null) {
    throw Exception('missing ${prefix}sourceAccount');
  }
  String feeStr = _removeComment(map['${prefix}fee']);
  int fee;
  if (feeStr == null) {
    throw Exception('missing ${prefix}fee');
  } else {
    try {
      fee = int.parse(feeStr);
    } catch (e) {
      throw Exception('invalid ${prefix}fee');
    }
  }
  if (fee == null) {
    throw Exception('invalid ${prefix}fee');
  }

  String seqNr = _removeComment(map['${prefix}seqNum']);
  int sequenceNumber;
  if (seqNr == null) {
    throw Exception('missing ${prefix}seqNum');
  } else {
    try {
      sequenceNumber = int.parse(seqNr);
    } catch (e) {
      throw Exception('invalid ${prefix}seqNum');
    }
  }
  if (sequenceNumber == null) {
    throw Exception('invalid ${prefix}seqNum');
  }

  if (sourceAccountId == null) {
    throw Exception('invalid ${prefix}sourceAccount');
  }
  try {
    KeyPair.fromAccountId(sourceAccountId);
  } catch (e) {
    throw Exception('invalid ${prefix}sourceAccount');
  }

  MuxedAccount mux = MuxedAccount.fromAccountId(sourceAccountId);
  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.parse(_removeComment(map['${prefix}timeBounds.minTime']));
      int maxTime =
          int.parse(_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');
  }

  // Memo
  String memoType = _removeComment(map['${prefix}memo.type']);
  if (memoType == null) {
    throw Exception('missing ${prefix}memo.type');
  }
  try {
    if (memoType == 'MEMO_TEXT' && map['${prefix}memo.text'] != null) {
      txBuilder.addMemo(MemoText(
          _removeComment(map['${prefix}memo.text']).replaceAll('"', '')));
    } else if (memoType == 'MEMO_ID' && map['${prefix}memo.id'] != null) {
      txBuilder.addMemo(
          MemoId(int.parse(_removeComment(map['${prefix}memo.id']))));
    } else if (memoType == 'MEMO_HASH' && map['${prefix}memo.hash'] != null) {
      txBuilder.addMemo(MemoHash(
          Util.hexToBytes(_removeComment(map['${prefix}memo.hash']))));
    } else if (memoType == 'MEMO_RETURN' &&
        map['${prefix}memo.return'] != null) {
      txBuilder.addMemo(
          MemoReturnHash.string(_removeComment(map['${prefix}memo.return'])));
    } else {
      txBuilder.addMemo(MemoNone());
    }
  } catch (e) {
    throw Exception('invalid ${prefix}memo');
  }

  // Operations
  String operationsLen = _removeComment(map['${prefix}operations.len']);
  if (operationsLen == null) {
    throw Exception('missing ${prefix}operations.len');
  }
  int nrOfOperations;
  try {
    nrOfOperations = int.parse(operationsLen);
  } catch (e) {
    throw Exception('invalid ${prefix}operations.len');
  }
  if (nrOfOperations > 100) {
    throw Exception('invalid ${prefix}operations.len - greater than 100');
  }

  for (int i = 0; i < nrOfOperations; i++) {
    Operation operation = _getOperation(i, map, prefix);
    if (operation != null) {
      txBuilder.addOperation(operation);
    }
  }
  int maxOperationFee = (fee.toDouble() / nrOfOperations.toDouble()).round();
  txBuilder.setMaxOperationFee(maxOperationFee);
  AbstractTransaction transaction = txBuilder.build();

  // Signatures
  prefix = isFeeBump ? 'feeBump.tx.innerTx.' : "";
  String signaturesLen = _removeComment(map['${prefix}signatures.len']);
  if (signaturesLen != null) {
    int nrOfSignatures;
    try {
      nrOfSignatures = int.parse(signaturesLen);
    } catch (e) {
      throw Exception('invalid ${prefix}signatures.len');
    }
    if (nrOfSignatures > 20) {
      throw Exception('invalid ${prefix}signatures.len - greater than 20');
    }
    List<XdrDecoratedSignature> signatures = List<XdrDecoratedSignature>();
    for (int i = 0; i < nrOfSignatures; i++) {
      XdrDecoratedSignature signature = _getSignature(i, map, prefix);
      if (signature != null) {
        signatures.add(signature);
      }
    }
    transaction.signatures = signatures;
  }
  if (isFeeBump) {
    FeeBumpTransactionBuilder builder =
        FeeBumpTransactionBuilder(transaction);
    int baseFee =
        (feeBumpFee.toDouble() / (nrOfOperations + 1).toDouble()).round();
    builder.setBaseFee(baseFee);
    builder.setMuxedFeeAccount(MuxedAccount.fromAccountId(feeBumpSource));
    FeeBumpTransaction feeBumpTransaction = builder.build();
    String fbSignaturesLen = _removeComment(map['feeBump.signatures.len']);
    if (fbSignaturesLen != null) {
      int nrOfFbSignatures;
      try {
        nrOfFbSignatures = int.parse(fbSignaturesLen);
      } catch (e) {
        throw Exception('invalid feeBump.signatures.len');
      }
      if (nrOfFbSignatures > 20) {
        throw Exception('invalid feeBump.signatures.len - greater than 20');
      }
      List<XdrDecoratedSignature> fbSignatures =
          List<XdrDecoratedSignature>();
      for (int i = 0; i < nrOfFbSignatures; i++) {
        XdrDecoratedSignature fbSignature = _getSignature(i, map, 'feeBump.');
        if (fbSignature != null) {
          fbSignatures.add(fbSignature);
        }
      }
      feeBumpTransaction.signatures = fbSignatures;
      return feeBumpTransaction.toEnvelopeXdrBase64();
    }
  }
  return transaction.toEnvelopeXdrBase64();
}