# Submit a private searcher bundle

PulseChain, chain ID 369. No enrollment or API key is required.

- POST signed JSON-RPC: `https://rpc.blockferret.win/builders`
- GET fresh duty context: `https://rpc.blockferret.win/v1/builder-context`
- [Guide](https://blockferret.win/docs/searcher-guide)
- [API reference](https://blockferret.win/docs/searcher-api)
- [Local Node.js client](https://blockferret.win/assets/examples/submit-searcher.mjs)

## Authenticate

Keep a stable authentication wallet locally. It can be unfunded and differ from
your transaction sender. Personal-sign the UTF-8 hexadecimal Keccak-256 string
of the exact transmitted body, including `0x`, rather than decoded hash bytes.

```javascript
import { Wallet, id } from 'ethers';
const body = JSON.stringify({jsonrpc:'2.0',id:1,method,params:[params]});
const signature = await wallet.signMessage(id(body));
// X-Flashbots-Signature: `${wallet.address}:${signature}`
```

Call `blockferret_getSearcherTerms` with `{}` for the verified router, chain,
builder wallet, live flags, bridge readiness, fee split and current limits.
GET context supplies `blockNumber`, `parentHash`, `validatorRecipient` and
`expiresAt`. Searchers do not require `templateAvailable: true`. A 503 means
there is no usable current duty; back off.

## Submit and pay

Your JSON params file:

```json
{
  "txs": ["0xSIGNED_ARB", "0xSIGNED_PAYMENT"],
  "blockNumber": "0xTARGET_BLOCK",
  "parentHash": "0xCURRENT_PARENT",
  "replacementUuid": "756e9444-c71f-4b69-aaf5-5b53c992aa65"
}
```

Replace all placeholders. Transactions must be signed on chain 369, in order,
without duplicates, with funded gas. Use 1–16 transactions and at most 256 KiB
of signed bytes. Targets are within 25 blocks; an explicit parent requires the
next block. Optional timestamp bounds are numeric Unix seconds.

Read `paymentRouter` from live terms. Call:

```solidity
pay(bytes32 paymentId, uint256 targetBlock, bytes32 expectedParent,
    address payable proposerRecipient) payable
```

Choose a nonzero application payment ID and a native PLS inclusion fee. Set the
exact context target block, parent and validator recipient. Calling from your
trade contract after its profit checks settles trading and fee atomically.
A separate final payment transaction is also supported. The router verifies
chain/block/parent, pays 60% of this chosen fee to the validator and 40% to
BlockFerret. You keep your remaining trade profit and pay your own gas. Ordinary
tips go to the validator separately. The eligible Vouch fee-depositor proposer
receives half of the builder share through the final payout, effectively 80/20.

The bundle is appended contiguously after the existing execution prefix and
before the final validator payout. Every bundle transaction must succeed.
Preserve your own minimum-profit, repayment and slippage checks at this actual
execution position. Complete independent replay protects retained transaction
outcomes, gas coverage, builder inventory and baseline earnings. There is no
private orderflow feed, arbitrary earlier placement or delayed selling.

## Use the client

```text
npm install ethers@6
# Set SEARCHER_AUTH_KEY locally in your environment.
node submit-searcher.mjs terms
node submit-searcher.mjs context
node submit-searcher.mjs submit bundle.json
node submit-searcher.mjs status 0xSUBMISSION_ID
node submit-searcher.mjs cancel 756e9444-c71f-4b69-aaf5-5b53c992aa65
```

The client authenticates requests. It does not sign your trading transactions,
discover arbs or simulate execution. It never automatically retries an ambiguous
write. `private private.json` uses `eth_sendPrivateTransaction` with `tx`,
optional hex `maxBlockNumber` and `parentHash`; its execution must pay the router.
`cancel-private 0xTX_HASH` cancels a pending single private transaction.

Status, cancellation and replacement require the original signing identity.
Cancellation cannot recall a bid after commitment. Queue acceptance is not
inclusion: check canonical successful receipts, their block and exact order.
Bundles expire within 120 seconds, usually sooner when the target or duty passes.
Single private transactions have a 30-minute intake TTL, but a signed exact-block
payment cannot execute after its target. Queues are held in memory.

Bundle acceptance returns `submissionId` and `bundleHash`. Single private
transaction acceptance returns a transaction hash; use it as `submissionId`
for owner-signed status too. Invalid request authentication returns HTTP 401.

60 requests/minute per identity; 600/minute and two concurrent requests shared
by advanced submissions and context. Searchers are capped at 32 queued entries
and one quarter of total queue bytes, reserving wallet capacity. Back off on
429/503. Private bytes are never automatically broadcast publicly.

No JSON-RPC batch/notifications, `eth_callBundle`, MEV-Share/refunds or allowed
reverts are supported. Unknown fields and nonempty `revertingTxHashes` are
rejected. Request acceptance, execution verification and winning inclusion are
separate steps.
