# Solana and Other SVM Raw Transactions Solana Messages The `solana_raw_transaction` is a low-level format that is rarely the right choice for most applications. Instead, you should first try to use the [`solana_serialized_transaction_message`](/developers/transaction-types/solana-new) format, which simplifies the integration with common Solana SDKs. The `solana_raw_transaction` format is a low-level format, allowing you to explicitly provide the following: - The version (Fordefi supports both legacy and v0 versions) - An array of instructions - The interacted accounts list - An address table, if relevant Any transaction must have at least one instruction. The following example creates a transaction request that adds liquidity to [Marinade Finance](https://marinade.finance/app/staking/). The request should be signed, as demonstrated [here](/developers/authentication#request-signing). ```json { "signer_type": "api_signer", "type": "solana_transaction", "details": { "type": "solana_raw_transaction", "chain": "solana_mainnet", "version": "legacy", "instructions": [{ "program_index": 8, "data": "tZ1ZQ4+2NEjwSQIAAAAAAA==", "account_indexes": [1, 3, 7, 6, 4, 0, 2, 5, 9] }], "accounts": [{ "address": "8TpGoWWzx9Q7rR7UizToMQ7K3G8TPncHjkJiBBfxwBC4", "writable": true, "signer": true }, { "address": "8szGkuLTAux9XMgZ2vtY39jVSowEcpBfFfD8hXSEqdGC", "writable": true, "signer": false }, { "address": "De2cHMWmygZ6Ss8HDaBXovesoniXBFs5B4MKQVthaVM2", "writable": true, "signer": false }, { "address": "LPmSozJJ8Jh69ut2WP3XmVohTjL4ipR18yiCzxrUmVj", "writable": true, "signer": false }, { "address": "UefNb6z6yvArqe4cJHTXCqStRsKmWhGxnZzuHbikP5Q", "writable": true, "signer": false }, { "address": "11111111111111111111111111111111", "writable": false, "signer": false }, { "address": "7GgPYjS5Dza89wV6FpZ23kUJRG5vbQ1GM25ezspYFSoE", "writable": false, "signer": false }, { "address": "HZsepB79dnpvH6qfVgvMpS738EndHw3qSHo4Gv5WX1KA", "writable": false, "signer": false }, { "address": "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD", "writable": false, "signer": false }, { "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "writable": false, "signer": false } ], "address_table_lookups":[] }, "note": "Adding liquidity to Marinade Finance", "vault_id": "8988893a-cf29-4a02-acc7-5bb723c74f47" } ``` For a better understanding, visit the [Solana blockchain explorer](https://solscan.io/tx/4WsAk9RP7wDY5S8e6n1BDfzKhnyppFALSk15b1bv9jbWZfeQYWxC7AocFh7MR7vf8rNHYtzfSTgCtS2XMJRX5jBY) to view the transaction that was created by this code. ## solana-program-library for building transaction raw data Building the transaction raw data from scratch can be challenging. Short-circuit the process by using any of several packages that can help to build Solana transactions with high-level API. One example is the `solana-program-library` Python package repository. The following example demonstrates how to create a staking transaction on Solana and sign it partially before sending it to Fordefi. First, clone `solana-program-library` and install the Solana Python package. ```BASH git clone git@github.com:solana-labs/solana-program-library.git pip install solana==0.18.1 ``` Create a `main.py` file inside the `solana-stake-pool/stake-pool/py` directory, with the content: ```python import base64 import json import uuid import base58 import stake.constants import stake.instructions import stake.state import solana.system_program import solana.publickey import solana.transaction import solana.blockhash import solana.keypair import requests class RpcClient: def __init__(self, rpc_url: str): self._rpc_url = rpc_url def get_recent_blockhash(self) -> solana.blockhash.Blockhash: body = { "jsonrpc": "2.0", "id": 1, "method": "getRecentBlockhash", "params": [{"commitment": "finalized"}], } response = requests.post(self._rpc_url, json=body) response.raise_for_status() return solana.blockhash.Blockhash( response.json()["result"]["value"]["blockhash"] ) def generate_stake_instructions( vault_id: uuid.UUID, payer_account: str, lamports: int, staker_account: str, withdrawer_account: str, custodian_account: str, ): client = RpcClient("https://api.mainnet-beta.solana.com") stake_account_key_pair = solana.keypair.Keypair() tx = solana.transaction.Transaction() tx.fee_payer = solana.publickey.PublicKey(payer_account) tx.recent_blockhash = client.get_recent_blockhash() # Add create account instruction. tx.add( solana.system_program.create_account( params=solana.system_program.CreateAccountParams( from_pubkey=solana.publickey.PublicKey(payer_account), new_account_pubkey=stake_account_key_pair.public_key, lamports=lamports, space=stake.constants.STAKE_LEN, program_id=stake.constants.STAKE_PROGRAM_ID, ), ) ) # Add initialize instruction. tx.add( stake.instructions.initialize( params=stake.instructions.InitializeParams( stake=stake_account_key_pair.public_key, authorized=stake.state.Authorized( staker=solana.publickey.PublicKey(staker_account), withdrawer=solana.publickey.PublicKey(withdrawer_account), ), lockup=stake.state.Lockup( epoch=0, unix_timestamp=0, custodian=solana.publickey.PublicKey(custodian_account), ), ), ) ) # Sign transaction by the stake account only. tx.sign_partial(stake_account_key_pair) message = tx.compile_message() signers = message.account_keys[: message.header.num_required_signatures] signatures: list[dict[str, str | None]] = [] for account in signers: for signature in tx.signatures: if signature.pubkey == account and signature.signature is not None: signatures.append( {"data": base64.b64encode(signature.signature).decode()} ) else: signatures.append({"data": None}) account_keys: list[dict[str, str | bool]] = [] for account in message.account_keys: account_keys.append( { "address": str(account), "writable": False, "signer": False, } ) for account_key in account_keys[: message.header.num_required_signatures]: account_key["signer"] = True for account_key in account_keys[ : message.header.num_required_signatures - message.header.num_readonly_signed_accounts ]: account_key["writable"] = True for account_key in account_keys[ message.header.num_required_signatures : -message.header.num_readonly_unsigned_accounts ]: account_key["writable"] = True # Build create_transaction_request_details. create_transaction_request = { "vault_id": str(vault_id), "type": "solana_transaction", "signer_type": "api_signer", "details": { "version": "legacy", "type": "solana_raw_transaction", "recent_blockhash": str(tx.recent_blockhash), "instructions": [ { "program_index": instruction.program_id_index, "data": base64.b64encode( base58.b58decode(instruction.data) ).decode(), "account_indexes": instruction.accounts, } for instruction in message.instructions ], "accounts": account_keys, "address_table_lookups": [], "signatures": signatures if any(signatures) else None, "chain": "solana_mainnet", }, } print(json.dumps(create_transaction_request, indent=4)) if __name__ == "__main__": generate_stake_instructions( vault_id=uuid.UUID("54fe3e56-0abd-4fe4-acdc-4cffa38a964f"), payer_account="BdW9dN3DmaNUFPGrNwS4TzDVQ8Yn3aXB8AAFBhHLPBKm", lamports=10**9, staker_account="AC6MBbSTmxVpLcNWnHfxoT12Q5tV3PsX2ofuqepoTjTe", withdrawer_account="97sdixZoEQ9WZijPBMovrAPtKnX63JSXcRxfVCsDvPz4", custodian_account="9iNcEjWvwHUe2UpenLdtVjNGvymYxd2gZk1B75torfMM", ) ``` Running this script will output a staking Create Transaction request body to POST to the Fordefi API. For example: ```json { "details": { "version": "legacy", "type": "solana_raw_transaction", "recent_blockhash": "DewqCx36Z59gfWJS7h8qeErAV3Yhv5zxWNoHPmecmDf3", "instructions": [ { "program_index": 3, "data": "AAAAAADKmjsAAAAAyAAAAAAAAAAGodgXkTdUKpg0N73+KnqyVX9TXIp4citopJ3AAAAAAA==", "account_indexes": [ 0, 1 ] }, { "program_index": 4, "data": "AAAAAIiQnkM+zinC1MWbWiZFIfvsN+2HH1v+KpvSDfd8/BaBeKA7OrLOtDIw6EoMn9Gwsu2tWpFRUToFx2T9QxOWjQ0AAAAAAAAAAAAAAAAAAAAAgXa9hARP3ZqDnrHuEkjSfKPw3wBLFLFUCb4Oy37hn1w=", "account_indexes": [ 1, 2 ] } ], "accounts": [ { "address": "BdW9dN3DmaNUFPGrNwS4TzDVQ8Yn3aXB8AAFBhHLPBKm", "writable": true, "signer": true }, { "address": "AZRBfyAto1KAEu8nKP5SXecZqzMXhdW3psmw8Ajj2JCB", "writable": true, "signer": true }, { "address": "SysvarRent111111111111111111111111111111111", "writable": false, "signer": false }, { "address": "11111111111111111111111111111111", "writable": false, "signer": false }, { "address": "Stake11111111111111111111111111111111111111", "writable": false, "signer": false } ], "address_table_lookups": [], "signatures": [ { "data": null }, { "data": "1a8x6y6Sr6kt8eBnXjvt82KtoYFGNxoWrrH8QGUa0xyX66sVglc6bTS1aa2GLThYvHIFt51EM0ptaM3EgOzcDQ==" } ], "chain": "solana_mainnet" } } ```