Sending transactions
info
This flow is also described in the Construction API Overview article in the official Rosetta documentation.
The steps needed to send payment in MINA token are following:
- Given a key pair, derive the account indentifier using
/construction/derive
endpoint - Call
/construction/preprocess
and/construction/metadata
to construct parameters for/construction/payloads
request - Create an unsigned transaction blob using
construction/payloads
endpoint - Call
construction/parse
(optional) to check if the unsigned transaction does what you expect - Use detached signer to sign the transaction
- Call
construction/combine
to generate signed blob to be sent via/construction/submit
endpoint - Call
construction/parse
again (optional) to confirm correctness of the signed transaction - Get a future transaction hash using
/construction/hash
enpoint - Submit the signed transaction blob via
/construction/submit
endpoint
For ease of readability, this sample implementation skips the sanity checks (steps 4 and 7) and combines steps 2 and 3 in a single tx_payloads
function call.
Before running this sample:
- Make sure you followed Offline signer tool article and generated a key pair
- Send some test funds on the account you've generated.
The implementation is as follows:
- TypeScript
- Python
async function send(privateKey: string, to: string, valueNano: number, feeNano: number) {
const publicKey = mina.derivePublicKey(privateKey)
const publicKeyRaw = mina.publicKeyToRaw(publicKey)
// get transfer payload to sign
const payloadsResponse = await txPayloads(
publicKeyRaw,
publicKey,
to,
feeNano,
valueNano,
)
// sign and combine transfer payload
const combineResponse = await txCombine(payloadsResponse, privateKey)
const blob = combineResponse.signed_transaction
// // get future transaction hash
const txHashResponse = await txHash(blob)
const hash = txHashResponse.transaction_identifier.hash
// submit transaction. this call will fail if tx is not in mempool
await txSubmit(blob)
// wait for transaction confirmation:
// for that, track blocks until we meet our transaction in the last one
let latestBlock = (await networkStatus()).current_block_identifier.index
while (true) {
// check if our transaction exists in the latest block
const txs = (await waitForBlock(latestBlock)).block.transactions
const hashes = txs.map((tx: any) => tx.transaction_identifier.hash)
if (hashes.includes(hash)) {
break
}
latestBlock += 1
}
return hash
}
def withdrawal_flow(vault_keypair, dest_address, value_nano, fee_nano=None):
"""
Full withdrawal flow example (without sanity check)
If fee_nano is None - fee will be suggested by Rosetta API response
"""
vault_pubkey = vault_keypair["public"]
vault_private_key = vault_keypair["private"]
# derive vault address
derive_response = derive_account_identifier(vault_pubkey)
vault_address = derive_response["account_identifier"]["address"]
# get transfer payload to sign
payloads_response = tx_payloads(
vault_pubkey, vault_address, dest_address, fee_nano, value_nano)
# sign transfer payload
signature = sign_transaction(
SIGNER_PATH,
vault_private_key,
payloads_response["unsigned_transaction"])
# get signed transaction blob
combine_response = tx_combine(vault_pubkey, payloads_response, signature)
signed_transaction_blob = combine_response['signed_transaction']
# sanity check may be performed here
# for that - use tx_parse function output
# to doublecheck it corresponds what you want to do
# parsed_tx = tx_parse(signed_transaction_blob, True)
# get future transaction hash
tx_hash_response = tx_hash(signed_transaction_blob)
future_tx_hash = tx_hash_response['transaction_identifier']['hash']
# submit transaction. this call will fail if tx is not in mempool
tx_submit(signed_transaction_blob)
# wait for transaction confirmation:
# for that, track blocks until we meet our transaction in the last one
latest_block = network_status()["current_block_identifier"]["index"]
while True:
# check if our transaction exists in the latest block
txs = wait_for_block(latest_block)['block']['transactions']
hashes = [tx['transaction_identifier']['hash'] for tx in txs]
if future_tx_hash in hashes:
break
latest_block += 1
return future_tx_hash