Skip to main content

Sending Transactions

info

This flow follows the Construction API Overview from the official Rosetta documentation.

The steps to send a MINA payment:

  1. Derive the account address from a public key
  2. Build the unsigned transaction via preprocess → metadata → payloads
  3. Sign offline with the signer tool
  4. Combine the signature into a signed blob
  5. 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.