Sending Transactions
info
This flow follows the Construction API Overview from the official Rosetta documentation.
The steps to send a MINA payment:
- Derive the account address from a public key
- Build the unsigned transaction via preprocess → metadata → payloads
- Sign offline with the signer tool
- Combine the signature into a signed blob
- Submit the signed transaction
Prerequisites
- A key pair generated with the offline signer tool
- The account must have a balance (send test funds on devnet first)
- Set the shell variables from the Code Samples setup
Set your keys and transfer parameters:
PUBLIC_KEY="YOUR_PUBLIC_KEY_HEX"
SENDER="B62q..."
RECEIVER="B62q..."
TOKEN_ID="wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"
FEE=10000000 # 0.01 MINA in nanomina
VALUE=1000000000 # 1 MINA in nanomina
Step 1: Derive account address
curl -s "$ROSETTA_URL/construction/derive" \
-H 'Content-Type: application/json' \
-d "{
\"network_identifier\":$NETWORK,
\"public_key\":{\"hex_bytes\":\"$PUBLIC_KEY\",\"curve_type\":\"pallas\"}
}" | jq .
Step 2: Build the operations payload
Construct the three operations that represent a MINA transfer (see Requests and Responses for details on the structure):
OPERATIONS='[
{
"operation_identifier":{"index":0},
"type":"fee_payment",
"account":{"address":"'"$SENDER"'","metadata":{"token_id":"'"$TOKEN_ID"'"}},
"amount":{"value":"-'"$FEE"'","currency":{"symbol":"MINA","decimals":9}}
},
{
"operation_identifier":{"index":1},
"type":"payment_source_dec",
"account":{"address":"'"$SENDER"'","metadata":{"token_id":"'"$TOKEN_ID"'"}},
"amount":{"value":"-'"$VALUE"'","currency":{"symbol":"MINA","decimals":9}}
},
{
"operation_identifier":{"index":2},
"related_operations":[{"index":1}],
"type":"payment_receiver_inc",
"account":{"address":"'"$RECEIVER"'","metadata":{"token_id":"'"$TOKEN_ID"'"}},
"amount":{"value":"'"$VALUE"'","currency":{"symbol":"MINA","decimals":9}}
}
]'
Step 3: Preprocess
PREPROCESS=$(curl -s "$ROSETTA_URL/construction/preprocess" \
-H 'Content-Type: application/json' \
-d "{\"network_identifier\":$NETWORK,\"operations\":$OPERATIONS}")
echo "$PREPROCESS" | jq .
Step 4: Metadata
METADATA=$(curl -s "$ROSETTA_URL/construction/metadata" \
-H 'Content-Type: application/json' \
-d "$(echo "$PREPROCESS" | jq -c ". + {
\"network_identifier\":$NETWORK,
\"public_keys\":[{\"hex_bytes\":\"$PUBLIC_KEY\",\"curve_type\":\"pallas\"}]
}")")
echo "$METADATA" | jq .
Step 5: Payloads (unsigned transaction)
PAYLOADS=$(curl -s "$ROSETTA_URL/construction/payloads" \
-H 'Content-Type: application/json' \
-d "$(echo "$METADATA" | jq -c ". + {
\"network_identifier\":$NETWORK,
\"operations\":$OPERATIONS
}")")
echo "$PAYLOADS" | jq .
UNSIGNED_TX=$(echo "$PAYLOADS" | jq -r '.unsigned_transaction')
Step 6: Sign offline
Use the signer CLI tool:
SIGNATURE=$(signer sign --private-key "$PRIVATE_KEY" --unsigned-transaction "$UNSIGNED_TX")
Step 7: Combine
SIGNING_PAYLOAD=$(echo "$PAYLOADS" | jq -c '.payloads[0]')
COMBINE=$(curl -s "$ROSETTA_URL/construction/combine" \
-H 'Content-Type: application/json' \
-d "{
\"network_identifier\":$NETWORK,
\"unsigned_transaction\":\"$UNSIGNED_TX\",
\"signatures\":[{
\"signing_payload\":$SIGNING_PAYLOAD,
\"public_key\":{\"hex_bytes\":\"$PUBLIC_KEY\",\"curve_type\":\"pallas\"},
\"signature_type\":\"schnorr_poseidon\",
\"hex_bytes\":\"$SIGNATURE\"
}]
}")
SIGNED_TX=$(echo "$COMBINE" | jq -r '.signed_transaction')
echo "$COMBINE" | jq .
Step 8: Get transaction hash
curl -s "$ROSETTA_URL/construction/hash" \
-H 'Content-Type: application/json' \
-d "{\"network_identifier\":$NETWORK,\"signed_transaction\":\"$SIGNED_TX\"}" | jq .
Step 9: Submit
curl -s "$ROSETTA_URL/construction/submit" \
-H 'Content-Type: application/json' \
-d "{\"network_identifier\":$NETWORK,\"signed_transaction\":\"$SIGNED_TX\"}" | jq .
After submission, you can monitor for confirmation using the block scanning approach — poll blocks until your transaction hash appears.