Sign and Broadcast Transaction

To complete any staking or withdrawal operation on Story Protocol, sign the unsigned transaction provided by the Staking API and broadcast it to the network.

1. Prepare the unsigned transaction

Obtain the unsignedTransaction object provided by a transaction builder or the relevant Staking API endpoint, e.g., /staking/stake or /staking/withdraw.

2. Sign the transaction

Use any Ethereum-compatible signing method or library to sign the transaction. Here is an example below using ethers.js. Note that for package.json, the 5.7.2 version of ethers is required.

import { Wallet, utils } from 'ethers';

// Your private key (use secure storage in production)
const PRIVATE_KEY = '***';

// Unsigned transaction in hex format
const unsignedTxHex = '***';

const wallet = new Wallet(PRIVATE_KEY);

(async () => {
    try {
        const parsedTx = utils.parseTransaction(unsignedTxHex);
        const signedTx = await wallet.signTransaction({
            to: parsedTx.to,
            value: parsedTx.value,
            data: parsedTx.data,
            gasLimit: parsedTx.gasLimit,
            maxFeePerGas: parsedTx.maxFeePerGas,
            maxPriorityFeePerGas: parsedTx.maxPriorityFeePerGas,
            nonce: parsedTx.nonce,
            type: parsedTx.type || undefined,
            chainId: parsedTx.chainId
        });
        const signedTxBytes = utils.arrayify(signedTx);
        console.log(Buffer.from(signedTxBytes).toString('base64'));
    } catch (error) {
        console.error('Error:', error);
    }
})();

Upon successful execution, the script prints the signed transaction in hexadecimal format, ready to be broadcasted.

3. Broadcast the transaction

Send the signed transaction to the Story network by making a POST request to /api/v1/story/{network}/tx/send.

Example request (for aeneid network):

curl --request POST \
     --url https://api-test.p2p.org/api/v1/story/aeneid/tx/send \
     --header 'Authorization: Bearer <token>' \
     --header 'Content-Type: application/json' \
     --data '{
       "signedTransaction": "<hex_signed_tx>"
     }'
  • signedTransaction — signed transaction in the hexadecimal format.

Example response:

{
  "result": {
    "transactionId": "0xadcba25d1bcedaa2fd17ff5db6b45d5e7060cf3a3c17e263feebf7b460f742c9",
    "signerAccounts": [
      "0x3202B5B0602274197CcB22B8c02CEC9539990c7c"
    ],
    "createdAt": "2025-07-22T14:08:23.456Z"
  }
}
  • transactionId — hash of the transaction included in the Story Protocol chain.
  • signerAccounts — list of account addresses that signed the transaction.
  • createdAt — timestamp of the transaction in the ISO 8601 format.

What's next?