[indexer]: track fill userop hashes, actual delivered amounts, and placeOrder fee token - #1112
Draft
seunlanlege wants to merge 2 commits into
Draft
[indexer]: track fill userop hashes, actual delivered amounts, and placeOrder fee token#1112seunlanlege wants to merge 2 commits into
seunlanlege wants to merge 2 commits into
Conversation
…r fee token Three pieces of IntentGatewayV3 fill/order data that consumers need were absent from the indexed entities. Solvers fill through the ERC-4337 SolverAccount, so the stored transactionHash is the bundler's EntryPoint transaction rather than the userop the solver tracks. Fills now carry a nullable userOpHash, resolved from the fill receipt's UserOperationEvent whose sender matches the filler; it stays null for plain EOA fills. ExtrinsicIntents.fill() emits outputFills[i].amount = totalRequired, the promised amount, so an overfilled order's event understates what the beneficiary got. Fill output assets now carry amountReceived alongside the promised amount, read from the filler -> beneficiary Transfer logs in the fill receipt. Native outputs emit no Transfer log and stay null. Fees are denominated in the host's fee token, which differs per chain, so IOrderV3.fees was unpriceable without hardcoded per-chain knowledge. Orders now record feeToken, read once per chain from the host contract and cached. Transfer matching is scoped to the log range between the preceding fill event and this one, so a solver batching several fills in one transaction attributes each delivery to the right fill. Beneficiaries come from the indexed order, falling back to recovering the order from the fill calldata and verifying it against the commitment when the order has not been indexed yet, as happens for cross-chain fills.
Knowing which token the fees are denominated in is not enough to render them — consumers still had to resolve the token's decimals themselves. The host fee token is static per chain, so its decimals are fetched once and cached in the same entry as the address.
seunlanlege
force-pushed
the
indexer-fill-userop-amounts-fee-token
branch
from
August 8, 2026 10:25
fac0279 to
671ed97
Compare
seunlanlege
marked this pull request as draft
August 8, 2026 11:49
Member
|
@royvardhan for this PR we'll need to modify subquery to allow us add new fields to schema entities, please look into it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1104.
Adds the three missing pieces of IntentGatewayV3 data to the indexer: the userop hash behind each fill, the amount the beneficiary actually received, and the token
placeOrderfees are denominated in.Schema
IOrderV3Fill,IOrderV3PartialFilluserOpHash: StringIOrderV3FillOutputAsset,IOrderV3PartialFillOutputAssetamountReceived: BigIntIOrderV3feeToken: String!,feeTokenDecimals: Int!All additions are nullable or derivable, so no reindex-incompatible change.
Userop hash
Solvers fill through the ERC-4337
SolverAccount, so the storedtransactionHashis the bundler's EntryPoint transaction, not the userop the solver submitted and tracks. The fill handlers now read the fill transaction's receipt and take theuserOpHashfrom the firstUserOperationEventafter the fill log whosesenderis the filler. The EntryPoint emits that event once an op finishes executing, so within a bundle containing several solvers' ops the sender match plus the log-index ordering picks the right one. Plain EOA fills emit no such event and leave the field null.Amount received
ExtrinsicIntents.fill()emitsoutputFills[i].amount = totalRequired— the order's promised amount (ExtrinsicIntents.sol:134). On an overfill the beneficiary receivestotalRequired + beneficiarySharefrom the surplus split, and the solver's actualsolverAmountnever appears in the event. Since the solver transfers output assets directly to the user,amountReceivedcomes from theTransferlogs (filler → beneficiary) in the fill receipt.Two cases the matching handles:
OrderFilled/PartialFilllog and this one, so each delivery is attributed to the fill it belongs to. Repeated tokens within one fill consume their transfers in log order.fillOrdercalls.Native-token outputs emit no
Transferlog, so they stay null rather than being guessed.Fee token
Fees are paid in the host's fee token (
IDispatcher(host()).feeToken()), which differs per chain, soIOrderV3.feescouldn't be displayed or priced without hardcoded per-chain knowledge.orderPlacedV3now reads it from the host contract resolved throughCHAINS_BY_ISMP_HOST, along with the token'sdecimalssofeesrenders without a second lookup. Both are static per chain and cached together per chain rather than fetched per order.Tests
13 unit tests in
src/utils/__tests__/fill.helpers.test.tscover userop-hash selection (sender mismatch, events before the fill, EOA fills), transfer matching (overfill, repeated tokens, native outputs, wrong-direction and protocol-share transfers, batched fills), andfillOrdercalldata decoding.The indexer build (
ENV=mainnet npm run build:release, including schema codegen) passes. The three failing suites in the wider run —state-commitment,phantom-decode,bridgeTokenSupply— fail identically on a clean tree; they hit live networks.