js-algorand-sdk
js-algorand-sdk copied to clipboard
Function to write Txn objects to file
Problem
When debugging transactions generated with the JS SDK a function like the Python SDK write_to_file
would be great
https://github.com/algorand/py-algorand-sdk/blob/master/algosdk/transaction.py#L1526
Solution
In a nodejs context this should be straight forward by calling txn.bytesToSign()
for unsigned or stxn.blob
and writing bytes to a file.
In a web context it is a little more difficult, I've been using the following to force a download of a named list of transactions to a file:
export function download_txns(name, txns) {
let b = new Uint8Array(0);
for(const txn in txns){
b = concatTypedArrays(b, txns[txn])
}
var blob = new Blob([b], {type: "application/octet-stream"});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = name;
link.click();
}
export function concatTypedArrays(a, b) { // a, b TypedArray of same type
var c = new (a.constructor)(a.length + b.length);
c.set(a, 0);
c.set(b, a.length);
return c;
}
Have you ever successfully written a txn to a file in a nodejs context? Whenever I do and attempt to sign the txn via goal, I always get the error:
msgpack decode error [pos 1]: only encoded map or array can be decoded into a struct
For completeness, I created a txn following the documentation (changing the addresses to ones in my sandbox) and then wrote that to a file:
// Construct the transaction
let params = await algodClient.getTransactionParams().do();
// comment out the next two lines to use suggested fee
params.fee = 1000;
params.flatFee = true;
const receiver = "RECEIVER...";
const enc = new TextEncoder();
const note = enc.encode("Hello World");
let amount = 1000000; // equals 1 ALGO
let sender = "SENDER...";
let txn = algosdk.makePaymentTxnWithSuggestedParams(sender, receiver, amount, undefined, note, params);
fs.writeFileSync('./test.txn', txn.bytesToSign());
Then attempt to sign it from goal:
goal clerk sign -i test.txn -o signed.txn
If I do the same process using the python SDK, it works no problem. It seems like it should be straight forward, so maybe I'm just missing something?
@AustP the bytesToSign
method does not serialize the transaction to a format recognized by goal; it's used to prepare the raw bytes to for immediate signing.
Instead, use the toByte
method or algosdk.encodeUnsignedTransaction
function to serialize it properly as an unsigned transaction. That should work, but let us know if it doesn't.
@jasonpaulos
Using both toByte
and encodeUnsignedTransaction
gives the following error upon signing:
msgpack decode error [pos 5]: no matching struct field found when decoding stream map with key amt
@jasonpaulos for context this seems to resolve the error https://discord.com/channels/491256308461207573/1103428629624533023/1103428629624533023 but both toByte or encodeUnsignedTransaction aren't working as of now
My mistake before, goal expects a SignedTransaction, while the methods I mentioned above are for encoding unsigned Transactions.
We have since added encodeUnsignedSimulateTransaction
, which will produce an encoded SignedTransaction (without signature of course) that goal is able to consume. We added this primarily for submitting transactions without signatures to the simulate endpoint, but it should work for this use case just as well.
I'm closing this issue now since I believe this function is the solution, but please feel free to comment if this doesn't work and I'll reopen.