Skip to content

Instantly share code, notes, and snippets.

@Bambarello
Created December 2, 2018 16:52
Show Gist options
  • Save Bambarello/6d9e88b28c81c0d90ecb67da2156e2f1 to your computer and use it in GitHub Desktop.
Save Bambarello/6d9e88b28c81c0d90ecb67da2156e2f1 to your computer and use it in GitHub Desktop.
how to send spend tx from epoch, for the restless

Get your private key

To send a transaction from an account, you'd need to sign it beforehand. To sign it, you need the private key that corresponds to the account.

If you used bin/epoch keys_gen <password>, then you should have your private key in generated_keys/key and your public key (aka address) in generated_keys/key.pub. Let's read and decipher them.

erl shell detour

But first let's learn the basics of working with erl shell.

Open a remote console to the running erlang node with bin/epoch remote_console, you would see something like

Erlang/OTP 20 [erts-9.3.3] [source] [64-bit] [smp:6:6] [ds:6:6:10] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V9.3.3  (abort with ^G)
(epoch@localhost)1> % you would have your cursor here

This is erl or the erlang shell, each expression which you type in here should be ended with .. Like if you type

io:fwrite("hello, world\n").

and the press ENTER, it would result in

(epoch@localhost)1> io:fwrite("hello, world\n").
hello, world
ok

Ok, that's enough.

reading the keyfiles

The privkey file would probably be at generated_keys/key, let's read it:

(epoch@localhost)2> {ok, EncryptedPrivKeyBin} = file:read_file("generated_keys/key").
{ok,<<184,123,157,23,42,135,50,247,14,52,59,110,96,85,
      196,17,27,81,214,118,143,154,6,37,118,126,242,...>>} % your output would be different
% now let's decode it
(epoch@localhost)3> Password = "my-password". % replace it with your own password
(epoch@localhost)4> DecryptedPrivKeyBin = crypto:block_decrypt(aes_ecb, crypto:hash(sha256, Password), EncryptedPrivKeyBin).
<<..., ..., ...>>

Now we have our private key decrypted DecryptedPrivKeyBin. We can use it to sign spend transactions. We can also export it to python / js sdks.

Let's also read the pubkey, which when base58check encoded and prepended with ak_ becomes our address.

(epoch@localhost)5> {ok, EncryptedPubKeyBin} = file:read_file("generated_keys/key.pub").
(epoch@localhost)6> DecryptedPubKeyBin = crypto:block_decrypt(aes_ecb, crypto:hash(sha256, Password), EncryptedPubKeyBin).

Building spend_tx

Now let's build and sign a spend tx.

 % this is me. you should set it to where you want to send AE to. You can get it from `ak_dashjdfj` strings
(epoch@localhost)7> RecepientPubKey = <<123, 78, 62, 237, 77, 74, 238, 81, 138, 2, 156, 113, 195, 83, 91,
    55, 127, 29, 134, 93, 90, 202, 3, 81, 158, 139, 30, 51, 5, 232, 203, 192>>.
(epoch@localhost)9> Nonce = 1. % should be `prev nonce of the account + 1` to avoid replay attacks
(epoch@localhost)10> {ok, SpendTx} = aec_spend_tx:new(#{
  sender_id => aec_id:create(account, DecryptedPubKeyBin),
  recipient_id => aec_id:create(account, RecepientPubKey),
  amount => 10000, % this is in aeons, I think
  fee => 1,
  ttl => 3000, % this is the block height up to which the spend tx is valid, you can set it to `current block heihgt + 100`
  nonce => Nonce, 
  payload => <<"">> % payload can be any binary, so let's leave it empty
}).

encoding, signing and then encoding spend_tx again

% Now we need to sign it
(epoch@localhost)11> EncodedSpendTx = aetx:serialize_to_binary(SpendTx),
                     EncodedSpendTxForNetwork = aec_governance:add_network_id(EncodedSpendTx),
                     Signature = enacl:sign_detached(EncodedSpendTxForNetwork, DecryptedPrivKeyBin),
                     SignedSpendTx = aetx_sign:new(SpendTx, [Signature]).
% Serialize it
(epoch@localhost)12> EncodedSignedSpendTx = aetx_sign:serialize_to_binary(SignedSpendTx).
% base58check encode it
(epoch@localhost)13> Base58CheckEncodedSignedSpendTx = aehttp_api_encoder:encode(transaction, EncodedSignedSpendTx).
<<"tx_+JkLAfhCuEBRjdPoC+tL3BtLXrDnRIAWZGQO6I2vadofjIR2QmM+Y80YPA2uakpSJ60BIIVxMVredCGZYu6teUXwdOBDmGsLuFH4TwwBoQGsthjeY"...>>

Posting spend tx to the local node

The last step can be done via curl

curl -X POST "http://localhost:3014/v2/transactions" \
     -H "accept: application/json" -H "Content-Type: application/json" \
     -d "{\"tx\": \"tx_asdkufgasudfgasjdfh\"}" # whatever you got in Base58CheckEncodedSignedSpendTx

Hm, seems complicated

There's probably a simpler way without posting the transaction to itself, but I haven't looked into it yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment