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.
2 Answers
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. Sep 3, 2018 at 13:29
-
But the TransactionEnvelopeBuilder has it, and that's what you're going to call. Sep 3, 2018 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? Sep 5, 2018 at 12:38
-
1Maybe the way you mentioned will work when we are building transaction from XDR. Sep 5, 2018 at 12:45
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