transactionEnvelopeXdrBase64FromTxRep static method

String transactionEnvelopeXdrBase64FromTxRep(
  1. String txRep
)

returns a base64 encoded transaction envelope xdr by parsing txRep.

Implementation

static String transactionEnvelopeXdrBase64FromTxRep(String txRep) {
  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.tryParse(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');
    }
  }

  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.tryParse(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.tryParse(seqNr);
    } catch (e) {
      throw Exception('invalid ${prefix}seqNum');
    }
  }
  if (sequenceNumber == null) {
    throw Exception('invalid ${prefix}seqNum');
  }

  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);
  txBuilder.addPreconditions(_getPreconditions(map, prefix));

  // 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.tryParse(_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();
  Transaction 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>.empty(growable: true);
    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>.empty(growable: true);
      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();
}