Maybe we can back up the discussion a little bit and you guys could help me understand the different formats we are dealing with.
Using 4.0.9 I can choose to "export", and "copy to clipboard". This gives the transaction encoded in base64? And if I choose to "export to file" that is same base64 converted to ASCII?
Not quite correct... Electrum now uses the "Partially Signed Bitcoin Transaction" (aka PSBT) format when exporting "unsigned" transactions. As already noted, this psbt file format is defined
here. The important thing to note is that it is a
binary file format... there is unlikely to be any human readable text contained within it (aside from the "psbt" magic bytes at the the beginning of the file)
As far as the Electrum exports are concerned:
- When you use "copy to clipboard"... Electrum encodes that psbt binary data into Base64 text format (as copy/pasting "binary" data can be somewhat problematic).
- When you use "export to file"... Electrum simply writes the psbt binary data into the file directly.
Is there anyway to take either of these representations of the transaction and convert it to something that is in a human readable form? I thought I could take base64 string from the clipboard and convert it to hex using:
https://cryptii.com/pipes/base64-to-hex Then, take the hex and use a tool like
https://live.blockcypher.com/btc/decodetx/ to decode the hex to a json representation of the transaction. But this does not work. I think the hex is bad, but not sure.
Correct... using that base64-to-hex converter will indeed convert the "Copy to Clipboard" Base64 encoded psbt data from Electrum into the "hex" output...
The problem you have is that this hex is in psbt format...
which is NOT the same format as a standard bitcoin transaction. This is why you get errors when trying to use a Bitcoin Transaction decoder. Having said that, the "raw unsigned transaction is actually contained in the psbt... and, the bonus is that it is included right at the beginning!
So... the basic format of the psbt file is:
4 bytes - Magic Bytes - 0x70736274 (Magic bytes which are ASCII for psbt)
1 byte - separator - 0xff
Then it should be the "global" key-value "map"... this is "variable" length, but the format is:
key length - int specifying number of bytes of the key
key data - the actual key data
value length - int specifying number of bytes of the value data
value data - the actual value data
It
looks quite confusing... but hopefully an example will give you some hope...
Here is a PBST from the "copy to clipboard"... so it's in Base64 format:
cHNidP8BAKACAAAAAo6AHdHDG49pUtMKtxy4zCwK7QY0CtCwfwiV6Lh2yCnLAAAAAAD9////3pHCZunJoabQc89f5IJTdjhVVp/AeJ4l5/H07F4GTPYAAAAAAP3///8CgoOYAAAAAAAZdqkUB/HU3mNuQvFvSZiMjcF+lEMG0mWIrICWmAAAAAAAGXapFFC6xnhio5hP5yg5rw8U4roI5nZkiKyJAh0AAAEA3wIAAAABvezCKQ3mY4LrjFOE8dnESCz7sAxPbbcdtCcQW3+jMI0AAAAAakcwRAIgCgsC9bw0YySu2sgEkK850tLWOeAd7jkfZim5/qnAiR4CIHVOTuA54s1qSDJppXLs8sq67sVda4035Iey5ZL2Yb9yASEDsO+Ka7A1s9cQ+qU9wDR56hP3JKNYs1IIsse9j4NRhvr9////AiKTmAAAAAAAGXapFK69AmfhNVMSEueR6yJVEL5m8Dz+iKwA4fUFAAAAABepFKdL1i+Rxwfqhr1wpPq5plBjnoo4h28xGwAiBgJjb4/vozNp1NLAfAewBDLt5aFVaIx7T8zaf+hF8RnnTAxrFj/5AQAAACIAAAAAAQDiAgAAAAGVl0bY5YaEfpcoXrwvXsL+nklaBPo5bdMcjmXwqcxDwAAAAABrSDBFAiEAh1wXXt69BhgVXQQawnI+zW/Jfk0pzh+N9UFMrR0pUBsCIAdFzlefu+XaKOg47EUzC/5TCR8wdNQK4DcYcMezKdL4ASEDKmFJM+504tv6gZbkwercqdWhPDd2D625GiNlGZ7tWOr9////AlaImAAAAAAAGXapFCkJ7Rj8JufGcxWlejQCZvSMHUVHiKyAlpgAAAAAABl2qRReMpJuA8PCbLIc5Eq8oc23PKd8T4isCQQYACIGAgKXNL1Qs696n22XEACcUvK3QLnuW/IlECDWEmobjYw4DGsWP/kBAAAAFQAAAAAiAgIG2/DJxpZGsYyAQF4QkRbENKVzebjk/AwnOm7OcHeVkwxrFj/5AQAAACsAAAAAIgIDO6NEp2YaMzKa4YHss0Fxy6Wg5W/8A69EChNBZr/7w1EMaxY/+QAAAAAAAAAAAA==
We run that through
the "Base64 to hex" converter (set "Group By" = None), which gives us this:
70736274ff0100a002000000028e801dd1c31b8f6952d30ab71cb8cc2c0aed06340ad0b07f0895e8b876c829cb0000000000fdffffffde91c266e9c9a1a6d073cf5fe48253763855569fc0789e25e7f1f4ec5e064cf60000000000fdffffff0282839800000000001976a91407f1d4de636e42f16f49988c8dc17e944306d26588ac80969800000000001976a91450bac67862a3984fe72839af0f14e2ba08e6766488ac89021d00000100df0200000001bdecc2290de66382eb8c5384f1d9c4482cfbb00c4f6db71db427105b7fa3308d000000006a47304402200a0b02f5bc346324aedac80490af39d2d2d639e01dee391f6629b9fea9c0891e0220754e4ee039e2cd6a483269a572ecf2cabaeec55d6b8d37e487b2e592f661bf72012103b0ef8a6bb035b3d710faa53dc03479ea13f724a358b35208b2c7bd8f835186fafdffffff0222939800000000001976a914aebd0267e135531212e791eb225510be66f03cfe88ac00e1f5050000000017a914a74bd62f91c707ea86bd70a4fab9a650639e8a38876f311b00220602636f8fefa33369d4d2c07c07b00432ede5a155688c7b4fccda7fe845f119e74c0c6b163ff90100000022000000000100e20200000001959746d8e586847e97285ebc2f5ec2fe9e495a04fa396dd31c8e65f0a9cc43c0000000006b483045022100875c175edebd0618155d041ac2723ecd6fc97e4d29ce1f8df5414cad1d29501b02200745ce579fbbe5da28e838ec45330bfe53091f3074d40ae0371870c7b329d2f80121032a614933ee74e2dbfa8196e4c1eadca9d5a13c37760fadb91a2365199eed58eafdffffff0256889800000000001976a9142909ed18fc26e7c67315a57a340266f48c1d454788ac80969800000000001976a9145e32926e03c3c26cb21ce44abca1cdb73ca77c4f88ac09041800220602029734bd50b3af7a9f6d9710009c52f2b740b9ee5bf2251020d6126a1b8d8c380c6b163ff901000000150000000022020206dbf0c9c69646b18c80405e109116c434a57379b8e4fc0c273a6ece707795930c6b163ff9010000002b000000002202033ba344a7661a33329ae181ecb34171cba5a0e56ffc03af440a134166bffbc3510c6b163ff9000000000000000000
Now, looking at the beginning of the file...
70736274ff0100a002000000028e801dd1c31b8f6952d30ab71cb8cc2c0aed06340ad0b07f0895e8b876c829cb00000 00000fdffffffde91c266e9c9a1a6d073cf5fe48253763855569fc0789e25e7f1f4ec5e064cf600 00000000fdffffff0282839800000000001976a91407f1d4de636e42f16f49988c8dc17e944306d 26588ac80969800000000001976a91450bac67862a3984fe72839af0f14e2ba08e6766488ac8902 1d00000100df02000000....
We see:
70736274 == magic bytes
ff == separator
Then the "global key-value map" starts:
01 == length of key == 0x01 == 1 byte
00 == key value = 0x00 == "Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX" <--- This is the "key" we're after!
a0 == length of data = 0xa0 == 160 bytes == 320 chars
02000000028e801dd1c31b8f6952d30ab71cb8cc2c0aed06340ad0b07f0895e8b876c829cb00000 00000fdffffffde91c266e9c9a1a6d073cf5fe48253763855569fc0789e25e7f1f4ec5e064cf600 00000000fdffffff0282839800000000001976a91407f1d4de636e42f16f49988c8dc17e944306d 26588ac80969800000000001976a91450bac67862a3984fe72839af0f14e2ba08e6766488ac8902 1d00 == actual data value == the unsigned transaction hex! SUCCESS!
If we put that hex into
the decodetx utility... we get:
{
"addresses": [
"1j1S6J5Azgju5PtpkwMLd5YMHBDD14BeP",
"18Mroim7a2auG6C9X8QEDAUgUx5hDKMzZj"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"double_spend": false,
"fees": 0,
"hash": "0334ca8de093b635b490ec4480764b8e4a5a0c524ae2825135dd2aa4e2903822",
"inputs": [
{
"age": 0,
"output_index": 0,
"prev_hash": "cb29c876b8e895087fb0d00a3406ed0a2cccb81cb70ad352698f1bc3d11d808e",
"script_type": "empty",
"sequence": 4294967293
},
{
"age": 0,
"output_index": 0,
"prev_hash": "f64c065eecf4f1e7259e78c09f565538765382e45fcf73d0a6a1c9e966c291de",
"script_type": "empty",
"sequence": 4294967293
}
],
"lock_time": 1901193,
"opt_in_rbf": true,
"outputs": [
{
"addresses": [
"1j1S6J5Azgju5PtpkwMLd5YMHBDD14BeP"
],
"script": "76a91407f1d4de636e42f16f49988c8dc17e944306d26588ac",
"script_type": "pay-to-pubkey-hash",
"value": 9995138
},
{
"addresses": [
"18Mroim7a2auG6C9X8QEDAUgUx5hDKMzZj"
],
"script": "76a91450bac67862a3984fe72839af0f14e2ba08e6766488ac",
"script_type": "pay-to-pubkey-hash",
"value": 10000000
}
],
"preference": "low",
"received": "2020-12-29T08:05:12.865990958Z",
"relayed_by": "3.86.86.99",
"size": 160,
"total": 19995138,
"ver": 2,
"vin_sz": 2,
"vout_sz": 2
}
Obviously, it won't always be 160 bytes for every psbt that you create, so you'd need to find and calculate the "data length" value and then extract the appropriate number of following bytes...
Otherwise, another somewhat simpler (and less error-prone) option is to use NodeJS and
the 'psbt' package with it's
decodePsbt() method. We simply pass in the psbt "hex" and it outputs the fully decoded "psbt" with the raw transaction displayed at the end, like so:
> const psbt = require('psbt')
> psbt.decodePsbt({psbt:'70736274ff0100a002000000028e801dd1c31b8f6952d30ab71cb8cc2c0aed06340ad0b07f0895e8b876c829cb0000000000fdffffffde91c266e9c9a1a6d073cf5fe48253763855569fc0789e25e7f1f4ec5e064cf60000000000fdffffff0282839800000000001976a91407f1d4de636e42f16f49988c8dc17e944306d26588ac80969800000000001976a91450bac67862a3984fe72839af0f14e2ba08e6766488ac89021d00000100df0200000001bdecc2290de66382eb8c5384f1d9c4482cfbb00c4f6db71db427105b7fa3308d000000006a47304402200a0b02f5bc346324aedac80490af39d2d2d639e01dee391f6629b9fea9c0891e0220754e4ee039e2cd6a483269a572ecf2cabaeec55d6b8d37e487b2e592f661bf72012103b0ef8a6bb035b3d710faa53dc03479ea13f724a358b35208b2c7bd8f835186fafdffffff0222939800000000001976a914aebd0267e135531212e791eb225510be66f03cfe88ac00e1f5050000000017a914a74bd62f91c707ea86bd70a4fab9a650639e8a38876f311b00220602636f8fefa33369d4d2c07c07b00432ede5a155688c7b4fccda7fe845f119e74c0c6b163ff90100000022000000000100e20200000001959746d8e586847e97285ebc2f5ec2fe9e495a04fa396dd31c8e65f0a9cc43c0000000006b483045022100875c175edebd0618155d041ac2723ecd6fc97e4d29ce1f8df5414cad1d29501b02200745ce579fbbe5da28e838ec45330bfe53091f3074d40ae0371870c7b329d2f80121032a614933ee74e2dbfa8196e4c1eadca9d5a13c37760fadb91a2365199eed58eafdffffff0256889800000000001976a9142909ed18fc26e7c67315a57a340266f48c1d454788ac80969800000000001976a9145e32926e03c3c26cb21ce44abca1cdb73ca77c4f88ac09041800220602029734bd50b3af7a9f6d9710009c52f2b740b9ee5bf2251020d6126a1b8d8c380c6b163ff901000000150000000022020206dbf0c9c69646b18c80405e109116c434a57379b8e4fc0c273a6ece707795930c6b163ff9010000002b000000002202033ba344a7661a33329ae181ecb34171cba5a0e56ffc03af440a134166bffbc3510c6b163ff9000000000000000000'});
{
inputs: [
{
non_witness_utxo: '0200000001bdecc2290de66382eb8c5384f1d9c4482cfbb00c4f6db71db427105b7fa3308d000000006a47304402200a0b02f5bc346324aedac80490af39d2d2d639e01dee391f6629b9fea9c0891e0220754e4ee039e2cd6a483269a572ecf2cabaeec55d6b8d37e487b2e592f661bf72012103b0ef8a6bb035b3d710faa53dc03479ea13f724a358b35208b2c7bd8f835186fafdffffff0222939800000000001976a914aebd0267e135531212e791eb225510be66f03cfe88ac00e1f5050000000017a914a74bd62f91c707ea86bd70a4fab9a650639e8a38876f311b00',
bip32_derivations: [Array]
},
{
non_witness_utxo: '0200000001959746d8e586847e97285ebc2f5ec2fe9e495a04fa396dd31c8e65f0a9cc43c0000000006b483045022100875c175edebd0618155d041ac2723ecd6fc97e4d29ce1f8df5414cad1d29501b02200745ce579fbbe5da28e838ec45330bfe53091f3074d40ae0371870c7b329d2f80121032a614933ee74e2dbfa8196e4c1eadca9d5a13c37760fadb91a2365199eed58eafdffffff0256889800000000001976a9142909ed18fc26e7c67315a57a340266f48c1d454788ac80969800000000001976a9145e32926e03c3c26cb21ce44abca1cdb73ca77c4f88ac09041800',
bip32_derivations: [Array]
}
],
outputs: [ { bip32_derivation: [Object] }, { bip32_derivation: [Object] } ],
pairs: [
{
type: '00',
value: '02000000028e801dd1c31b8f6952d30ab71cb8cc2c0aed06340ad0b07f0895e8b876c829cb0000000000fdffffffde91c266e9c9a1a6d073cf5fe48253763855569fc0789e25e7f1f4ec5e064cf60000000000fdffffff0282839800000000001976a91407f1d4de636e42f16f49988c8dc17e944306d26588ac80969800000000001976a91450bac67862a3984fe72839af0f14e2ba08e6766488ac89021d00'
},
{
type: '00',
value: '0200000001bdecc2290de66382eb8c5384f1d9c4482cfbb00c4f6db71db427105b7fa3308d000000006a47304402200a0b02f5bc346324aedac80490af39d2d2d639e01dee391f6629b9fea9c0891e0220754e4ee039e2cd6a483269a572ecf2cabaeec55d6b8d37e487b2e592f661bf72012103b0ef8a6bb035b3d710faa53dc03479ea13f724a358b35208b2c7bd8f835186fafdffffff0222939800000000001976a914aebd0267e135531212e791eb225510be66f03cfe88ac00e1f5050000000017a914a74bd62f91c707ea86bd70a4fab9a650639e8a38876f311b00'
},
{
type: '0602636f8fefa33369d4d2c07c07b00432ede5a155688c7b4fccda7fe845f119e74c',
value: '6b163ff90100000022000000'
},
{
type: '00',
value: '0200000001959746d8e586847e97285ebc2f5ec2fe9e495a04fa396dd31c8e65f0a9cc43c0000000006b483045022100875c175edebd0618155d041ac2723ecd6fc97e4d29ce1f8df5414cad1d29501b02200745ce579fbbe5da28e838ec45330bfe53091f3074d40ae0371870c7b329d2f80121032a614933ee74e2dbfa8196e4c1eadca9d5a13c37760fadb91a2365199eed58eafdffffff0256889800000000001976a9142909ed18fc26e7c67315a57a340266f48c1d454788ac80969800000000001976a9145e32926e03c3c26cb21ce44abca1cdb73ca77c4f88ac09041800'
},
{
type: '0602029734bd50b3af7a9f6d9710009c52f2b740b9ee5bf2251020d6126a1b8d8c38',
value: '6b163ff90100000015000000'
},
{
type: '020206dbf0c9c69646b18c80405e109116c434a57379b8e4fc0c273a6ece70779593',
value: '6b163ff9010000002b000000'
},
{
type: '02033ba344a7661a33329ae181ecb34171cba5a0e56ffc03af440a134166bffbc351',
value: '6b163ff90000000000000000'
}
],
unsigned_transaction: '02000000028e801dd1c31b8f6952d30ab71cb8cc2c0aed06340ad0b07f0895e8b876c829cb0000000000fdffffffde91c266e9c9a1a6d073cf5fe48253763855569fc0789e25e7f1f4ec5e064cf60000000000fdffffff0282839800000000001976a91407f1d4de636e42f16f49988c8dc17e944306d26588ac80969800000000001976a91450bac67862a3984fe72839af0f14e2ba08e6766488ac89021d00'
}