4

I want to build a transaction and convert that as XDR before sign that transaction. As i found we need to build adn sign the transaction before convert that as XDR specially in java and GO SDK. Is there any way yo build it and convert that as XDR without a single signature.

3

I'm just going to guess here, since I don't do golang, but if you look at what Sign does, can't you just copy that implementation yourself, and skip the signing part?

I.e.,

func (b *TransactionBuilder) Sign(signers ...string) 
(TransactionEnvelopeBuilder, error) {
    var result TransactionEnvelopeBuilder
    err := result.Mutate(b)
    if err != nil {
        return result, err

    ...
    skip the signing
    ...

    return result, nil
}

So, create a TransactionEnvelopeBuilder, and call it with the TransactionBuilder.

  • I tried that earlier but i got this error "tx.Base64 undefined (type *build.TransactionBuilder has no field or method Base64)". that's why i posted the question. I tried TransactionMutator as well but i got the same error message. – Sharmilan Sep 3 '18 at 13:29
  • But the TransactionEnvelopeBuilder has it, and that's what you're going to call. – Johan Stén Sep 3 '18 at 13:38
  • In all the places that i checked, they build the base64 XDR after sign the transaction only. I am still confused how to build a XDR before sign it? – Sharmilan Sep 5 '18 at 12:38
  • 1
    Maybe the way you mentioned will work when we are building transaction from XDR. – Sharmilan Sep 5 '18 at 12:45
1

I have some examples for that in my kotlin library that wraps the java sdk.

data class PreparedTransaction(val transactionHash: String, val transactionEnvelopeXdr: String)

fun preparePaymentTransaction(
    sender: KeyPair,
    receiver: KeyPair,
    amount: TokenAmount,
    asset: Asset = amount.asset ?: nativeXlmAsset,
    memo: String? = null
): PreparedTransaction {
    val txBuilder = Transaction.Builder(server.accounts().account(sender))
        .addOperation(PaymentOperation.Builder(receiver, asset, amount.toString()).build())
    if (StringUtils.isNotBlank(memo)) {
        if (memo!!.toByteArray(StandardCharsets.UTF_8).size > 28) {
            throw IllegalStateException("Memo exceeds limit of 28 bytes")
        }
        txBuilder.addMemo(Memo.text(memo))
    }
    val tx = txBuilder.build()
    val transactionEnvelope = TransactionEnvelope()
    transactionEnvelope.tx = tx.toXdr()
    transactionEnvelope.signatures = arrayOf()
    return PreparedTransaction(tx.hash().toString(StandardCharsets.UTF_8), xdrEncode(transactionEnvelope))
}

This returns a pair of the transaction hash and the base64 xdr for the transaction envelope.

To sign you can decode the xdr, add a signature, and re-export the xdr the same way.

val envelope = Transaction.fromEnvelopeXdr(xdrDecodeString(xdr, TransactionEnvelope::class))
envelope.sign(hash.toByteArray(StandardCharsets.UTF_8))
envelope.sign(alice)

The xdr decode (and a corresponding encode function as well) come from my library as well:

inline fun <reified T : Any> xdrDecodeString(encoded: String, clazz: KClass<T>): T {
    val bytes = Base64.getDecoder().decode(encoded)
    val xdr = XdrDataInputStream(ByteArrayInputStream(bytes))

    val callable = clazz.members.find { it.name == "decode" }
    if (callable != null) {
        val result = callable.call(xdr)
        return clazz.cast(result)
    } else {
        throw IllegalStateException("cannot call decode(XdrDataInputStream)")
    }
}

See full code here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.