Skip to main content
AcceptQuote is the onchain entrypoint that settles an RFQ trade. As a taker, it’s the only contract message you call. This page documents every field, every encoding rule, and every validation the contract performs – including the features that aren’t obvious from the other docs.

Message shape

This JSON is the payload of a standard MsgExecuteContract transaction to the TrueCurrent contract address, signed by the taker’s private key.

Three encoding rules you must follow

These encoding rules are relatively common to get wrong. However, they are strictly enforced, as the contract parses the message with strict Rust serde types.

1. rfq_id is a JSON number, not a string

The contract field is u64. JSON encoders that stringify large integers will produce bytes the contract rejects with a deserialization error.
In TypeScript, Date.now() returns a number – use it directly. In Python, cast int(rfq_id) before serializing; if you build the request from a string, convert first.

2. Quote expiry must be wrapped as {"ts": <ms>}

The contract’s Expiry type is an enum with two variants – timestamp or block height. Serde requires the variant tag:
The indexer delivers expiry as a plain integer. You must wrap it before passing to the contract.

3. Quote signature is base64, not hex

Indexers (including TrueCurrent’s) transmit signatures as hex strings ("0xabc123..."). The contract’s signature field is a CosmWasm Binary type, which on the wire is standard base64. You must convert. Python:
TypeScript:
If you skip the conversion, the contract returns a signature verification error that looks like the maker signed badly. However the true cause of the error is encoding. The ContractClient.accept_quote() helper in injective-rfq-toolkit handles all three of these automatically. If you’re building from scratch, apply them yourself.

Field reference

Top-level fields: Per-quote fields:

Single-quote settlement

The simplest case: you collect quotes, pick one, accept it. Python – high-level helper:
Python – manual, no helper:
TypeScript:

Multi-quote aggregation

The quotes field is an array. You can submit multiple quotes from different makers in a single AcceptQuote call, and the contract will consume them sequentially until your quantity is filled. This is the main mechanism for getting size done when no single maker can cover your whole request. Scenario: you want to go long 100 INJ. Three makers respond: Submit all three in one transaction, sorted by price ascending (because you’re a buyer and want the cheapest fills first):
The contract walks the array:
  1. Fill 40 from Alice at 4.90 → remaining 60
  2. Fill 40 from Bob at 4.92 → remaining 20
  3. Fill 20 from Carol at 4.95 → remaining 0 (partial consumption of Carol’s quote – legal and expected)
  4. Done. Your position opens with a volume-weighted entry.
You end up with a single taker position for 100 INJ at a blended entry. Each maker gets a maker-side position for the quantity they actually filled.
Important: quote order matters. The contract processes the quotes array in submission order, not by price. If you submit Carol first, the contract happily takes 50 at 4.95, then Bob’s 40 at 4.92, then only 10 from Alice – you end up with a worse blended price. Therefore, always sort your quotes by price before submitting. For long sort quotes by ascending price. For shorts, sort quotes by descending price.
There is a maximum. The contract enforces quotes.len() <= config.max_quotes. In practice this is approximately 20. Check the current value with a config query to obtain the exact number before submitting very long lists.

Unfilled action

The current TrueCurrent product is RFQ-only. If your submitted quotes don’t cover the full quantity, the quote still settles the portion that was filled — the remainder is simply not traded. If zero quotes fill (e.g. all were rejected by signature or expiry), the quote fails. Pass null for unfilled_action on every call. The contract field exists for future use; non-null values are not exposed in the public product today.

On-chain validation

For each quote in the submitted array, the contract performs the following checks in order. If a quote fails any check, it is skipped (with an entry in quote_results), and the loop continues to the next quote. After the loop, the contract checks:
  • At least some fills happened – if filled_quantity == 0, the whole quote fails with all quotes rejected. If at least one quote filled, the quote settles the filled quantity and the remainder is simply not traded.
  • Taker has enough balance for the aggregate margin used across all filled quotes.
  • quotes.len() <= config.max_quotes – checked at the top of the handler before any iteration.
The full list of per-quote failures is available in the emitted settlement event under quote_results, keyed by maker address. Inspect this list in a failed quote to diagnose exactly which quote was rejected and why.

Post-settlement

After a successful quote:
  • You have a new position in your Injective exchange subaccount. Query it via the standard exchange module APIs – there is no RFQ-specific position state onchain.
  • The settlement event contains the filled quantity, the per-quote quote_results, the taker’s aggregate entry price, and the cid you passed (useful for matching events to your trade log).
  • Fees have been deducted according to the current taker_fee_rate and maker_fee_rate in the contract’s config. Query config for the current values.

Querying the settlement history

The indexer maintains a history of settlements indexed by taker address. Query it via HTTP:
Each entry includes the rfq_id, tx_hash, fill quantities, per-quote results, and timestamps. Use this to reconcile your client-side trade log with onchain reality.

Next

Last modified on June 2, 2026