Skip to main content
This page walks you through the full lifecycle of a single RFQ trade as a programmatic taker. By the end, you will have submitted a request, received signed quotes, and settled onchain on Injective testnet. Working code lives in InjectiveLabs/injective-rfq-toolkit:

Prerequisites

  • An Injective wallet (a 32-byte secp256k1 private key)
  • A small amount of INJ for gas on injective-888 (testnet) – testnet faucet
  • USDC in the wallet’s exchange subaccount to cover your margin
  • Network connectivity to wss://testnet.rfq.ws.injective.network/injective_rfq_rpc.InjectiveRfqRPC/TakerStream
  • Python 3.11+ or Node.js 18+

1. Install

Python – clone the toolkit repo and install the library:
TypeScript – install the Injective SDK and the example deps:

2. Configure environment

Create a .env file at the repo root:
The testnet config (configs/testnet.yaml) already points at: TakerStream supports an optional v1 challenge-response handshake that proves control of the request address. Authentication failure is currently informational and does not block RFQ requests, but integrations should authenticate and check the result before submitting requests. The toolkit handles the handshake when you provide the taker or authorized autosigner key and the RFQ contract address.

3. Grant authz permissions (once)

Before you can accept any quotes, you must grant the TrueCurrent contract three message types via Injective’s authz module. See Authorization setup for the full explanation. Python:
RETAIL_AUTHZ_GRANTS expands to three message types:
  1. /injective.exchange.v2.MsgPrivilegedExecuteContract
  2. /injective.exchange.v2.MsgBatchUpdateOrders
  3. /cosmos.bank.v1beta1.MsgSend
Each grant is a separate transaction. Wait for all three to confirm before continuing.

4. Submit a request

Open a TakerStream WebSocket and send an RFQ request. Python:
Always use the ACK’s rfq_id for quote collection and settlement. The request uses a client UUID for correlation; the indexer assigns the RFQ id that makers quote against. TypeScript: The native gRPC retail example shows the complete TypeScript flow: open TakerStream with request_address and auth_version: v1, sign TakerChallenge, check TakerAuthResult, then submit the request. If you use the lower-level WebSocket transport below, complete the same handshake before sending RFQs.
For TypeScript, parse the request ACK and use the returned rfq_id for quote filtering and settlement. Do not use Date.now() as the settlement rfq_id. See TakerStream for the full request schema, the gRPC-web framing details, and the rfq_id correlation patterns.

5. Collect quotes

Quotes stream in over the same WebSocket. Open a collection window, gather every quote matching your taker stream and rfq_id, and pick the best one (or several – see Accepting quotes for multi-quote aggregation). Python:
TypeScript:
Keep the collection window short. TrueCurrent currently uses 500 ms, but the value can vary by frontend and protocol configuration, and API takers can tune it. Waiting near the full live quote expiry window leaves little time for settlement. See Best practices for tuning.

6. Accept onchain

Now submit AcceptQuote to the TrueCurrent contract. This is where the three encoding gotchas bite – read Accepting quotes for the full story. Python (the ContractClient.accept_quote helper handles encoding for you):
TypeScript – because no high-level helper exists yet, you build the execute message yourself. The raw JSON shape with every gotcha applied:
If the transaction succeeds, your position is open. Query it via the standard Injective exchange APIs – there is no RFQ-specific position state.

What happens on failure

See Best practices for reconnection and error handling patterns.

Next

Last modified on August 21, 2026