{"service_id":"range-doctor","name":"Range Keeper","category":"rebalancing","category_job":"Keep LP earning","what_you_get":"A persistent watch over one PancakeSwap v3 liquidity position, and the read-only diagnosis it is built on. Each cycle Docket reads the position and its pool at one BSC block and states whether the current tick sits inside the range, where in that range it sits, and the pool's gross and protocol-adjusted net 24h fee rates when its reported figures clear a plausibility gate. Declare the position's USD value and a BNB price to add fixed-notional dollar effects, cost-only break-even, and the reset arithmetic below; both are labelled as the caller's rather than derived from an unverified price feed. When the position has been observed outside its range for longer than your policy waits, you get an alert carrying that arithmetic in full: how long it has been out, the fee recovery projected over a stated window against the whole cost of acting — gas ceilings at the observed gas price, and the swap a recentred range needs — and the multiple between them. If that multiple clears the one you set, the whole reset is prepared as exact calls, in the order they have to land: close the position, collect what it holds, rebalance the inventory through one exact-input swap, and mint a replacement whose position NFT is issued to your own address and never to Docket. The swap is there because a position that left its range holds one token and a range drawn around the current tick needs both. Its venue is chosen rather than assumed: PancakeSwap V2 is quoted first and used only when its quote is within your slippage bound of the price your own pool is trading at, because a pair that exists on V2 in name can be thin enough there to lose most of a position; where it falls short the leg goes through PancakeSwap's v3 router into the very pool your position was minted in. Either way the minimum output is enforced by the router, and the mint is sized against that minimum rather than a quote, so the amounts the position manager is asked to pull are amounts the swap was obliged to deliver. An inventory already balanced within your bound is minted without a swap and the record says so. Every token approval in the bundle is for an exact amount and never unlimited. Each call is put to the chain as an eth_call and a gas estimate before it is offered where its preconditions already hold; the swap and the mint spend tokens the collect has not released yet, so they are marked as waiting on it rather than tested against a state that does not exist — and every call is simulated again from its real sender immediately before it is sent. A batch the chain refuses comes back as an alert rather than reaching a signer. One call is never in the bundle: the ERC-721 approval that lets Docket touch your position NFT can only be made by the wallet holding it, so Docket reads whether you have made it and asks rather than drafting it. You sign the rest yourself, or grant a bounded session — a contract allowlist, a per-token cap, a gas ceiling and an expiry, all checked by Docket before every send rather than enforced by a chain, so what really bounds your exposure is how much you fund the session with. Pause the watch or revoke the session whenever you choose; revoking sweeps the session balance back to you, including fee residue and any swap surplus left above the mint. Every finding carries the numbers it was computed from, so you can check it against the chain yourself.","price_display":"0.50 USDT","price_atomic":"500000000000000000","asset":"0x55d398326f99059fF775485246999027B3197955","paid_stock":false,"stock_status":"candidate","admission":{"fresh_paired_benchmark":false,"cold_canary":false,"decision_grade_presenter":true,"true_settlement":true},"admission_evidence":{"fresh_paired_benchmark":"no v3 family registered for range-doctor is in a terminal state among ['complete_unscored', 'refuted', 'not_refuted']; v1 experiment 01-liquidity is paired and complete but its agent arm was delivered at 2026-08-08T16:51:34.801161+00:00, outside the disclosed 30-day window","cold_canary":"the latest passed canary run 18 finished at '2026-08-30T11:23:45.200371+00:00', which is absent, malformed, not UTC, future-dated, or older than the 129600-second limit","decision_grade_presenter":"stated for this service in docket/hire/catalogue.py: it is a property of how a result is written, which nothing in the store observes","true_settlement":"hire payment 0xcaafa68fef0e0b0691b1afcd7d7dd8a0827d04a897e8a01fa193d67bf6338fcb settled 500000000000000000 of 0x55d398326f99059fF775485246999027B3197955 at 2026-08-30T11:23:45.151192+00:00 in transaction 0x0a036066db0ccbde6eeb8d333e5747e549a61f251935fe8abceaf13b681a1258 — payer 0x4821b5445f1cE8328806f83bAfBdBE7D668E6fd3, which is not Docket's published operator address","window":"a paired benchmark stays fresh for 30 days from its own observation date; a canary for 129600 seconds from its finish"},"typical_seconds":30,"activation":"policy_action","activation_means":"One-shot activations return read-only reports. Funded sessions are separate: the runner checks your policy in software before submitting actions. The policy is not enforced by the session account on chain.","evidence_modality":"live_read","metrics":[{"name":"Position NFTs read","unit":"position NFTs the wallet held","window":"one recorded run against one wallet","observed_at":"2026-08-08","method":"advantage task 01, agent arm: positions_examined against positions_held, both carried in the result the hire returned","value":null,"numerator":14,"denominator":14,"display":"14 of 14 position NFTs the wallet held"},{"name":"Positions counted but not detailed","unit":"position NFTs read","window":"the same recorded run","observed_at":"2026-08-08","method":"advantage task 01, agent arm: closed_skipped against positions_examined. Closed positions are counted and no detail is returned for them, and there is no way to ask for it","value":null,"numerator":13,"denominator":14,"display":"13 of 14 position NFTs read"},{"name":"Elapsed","unit":"seconds","window":"one recorded run, a single observation and not a mean","observed_at":"2026-08-08","method":"advantage task 01, agent arm; the same question answered by hand in the manual arm took 528.31 seconds","value":43.063,"numerator":null,"denominator":null,"display":"43.063 seconds"}],"agent_id":"56:0x8004a169fb4a3325136eb29fa0ceb6d2e539a432:311253","identity":"Bound to the BSC ERC-8004 agent 56:0x8004a169fb4a3325136eb29fa0ceb6d2e539a432:311253. This registration is not an endorsement, evidence of paid stock, or evidence that the service produced a result.","hire_method":"POST","hire_path":"/hire/range-doctor","registration_uri":"https://docket.gudman.xyz/registrations/range-doctor.json","input_schema":{"wallet":{"type":"string","required":true,"default":"0xe55816904796341bf8535e25f6c8b647927fc946","example_note":"Docket's own controlled position — replace with your address","description":"the 0x-prefixed BSC address whose v3 positions to read"},"limit":{"type":"integer","required":false,"description":"how many open positions to return. It bounds the answer, not the reading: closed positions no longer consume it, so a wallet whose older positions are all closed still gets its open ones back. Up to 30 position NFTs are read in one call whatever this is set to; the response carries positions_held, positions_examined, closed_skipped and scan_complete, so a bounded read always says what it did not reach"},"token_id":{"type":"integer","required":false,"default":7141050,"description":"one exact PancakeSwap v3 position NFT to diagnose. The wallet is still enumerated for coverage, the selected NFT is returned even when closed, and this cannot be combined with limit"},"declared_position_value_usd":{"type":"number","required":false,"default":50.55,"description":"the positive caller-declared USD value of the exact token_id, used for fixed-notional dollar effects. Requires token_id; it is not derived from a token price feed"},"estimated_recenter_cost_usd":{"type":"number","required":false,"default":1.0,"description":"the caller-declared non-negative USD cost of recentering the exact token_id, including every gas, swap fee and price-impact component the caller wants counted. Requires token_id and is not derived by Docket"},"bnb_usd":{"type":"number","required":false,"required_for_watch":true,"description":"the caller-declared USD price of BNB, used only to convert the gas ceilings of a reset into dollars. A one-off diagnosis never needs it. A persistent watch cannot act without it and reports every reset instead — and it is never defaulted, because Docket derives no token price and a default here would be Docket quietly supplying the one number it says it does not have"},"out_of_range_minutes":{"type":"integer","required":false,"default":60,"description":"how long the position has to be OBSERVED outside its range before a reset is priced. Only time between observations counts: a position that was inside at the last read and outside at this one has been out for no observed time, and no departure moment is invented between them"},"min_net_benefit_multiple":{"type":"number","required":false,"default":2.0,"description":"how many times the projected fee recovery has to exceed the whole cost of the reset before one is offered. Below 1 the policy would authorise a reset whose projection does not cover its own cost, and it is refused"},"band_width_ticks":{"type":"integer","required":false,"description":"the half-width in ticks of the new range, so the band spans twice it. Omit it to keep the width the position already has. The bounds are snapped outward to the pool's own tick spacing, so the band is never returned narrower than asked for"},"max_notional_usd":{"type":"number","required":false,"default":1000.0,"description":"the largest declared position value a reset may be prepared for. A position above it is reported rather than acted on"},"observation_block":{"type":"integer","required":false,"advanced":true,"description":"read the position and its pool at this BSC block instead of the latest one. Both are read at the same block either way, so a diagnosis never compares a position from one moment against a price from another. Give it when the answer has to be reproducible — two readers at different times get the same result only if they name the same block. Public dataseeds prune, so an older block may return a stated read failure naming an archive node as the remedy rather than an empty result"},"position_manager":{"type":"string","required":false,"advanced":true,"description":"the PancakeSwap v3 NPM address; required with frozen source snapshots"},"decision_horizon_days":{"type":"integer","required":false,"default":30,"description":"the positive horizon for the cost-only break-even comparison"},"pool_snapshot":{"type":"object","required":false,"advanced":true,"description":"exact top-pools HTTP response bytes as base64 with URL, observation time and bare SHA-256; supplied with token_list_snapshot and source_refs"},"token_list_snapshot":{"type":"object","required":false,"advanced":true,"description":"exact token-list HTTP response bytes as base64 with URL, observation time and bare SHA-256; supplied with pool_snapshot and source_refs"},"source_refs":{"type":"array","items":{"type":"object"},"required":false,"advanced":true,"description":"the frozen typed source references bound to this position"}},"limitations":"PancakeSwap v3 on BSC only. Docket never holds a key to your wallet and cannot sign for it. A one-off hire reads and states what it read; a persistent watch adds prepared calls, and those calls are yours to sign unless you grant a session key. That key is created by Docket and bounded by a contract allowlist, a per-token cap, a gas ceiling and an expiry you set — but be exact about what those bounds are: they are checks Docket runs in front of every send, not rules a chain enforces, so what actually caps your exposure is how much you fund the session with. Fund it with what you are willing to lose to a bug. Revoking it sweeps its balance back to you at any time. The ERC-721 approval over your position NFT is yours to make because only its holder can, Docket asks for it rather than drafting it, the replacement position is minted to your address, and no position NFT is ever transferred to Docket. The session holds the two tokens between closing the old position and minting the new one; fee residue swept by the collect and any surplus the swap leaves above the mint's floor stay there until you revoke. Each call is put to the chain before it is offered where its preconditions already hold; the swap and the mint spend tokens the collect has not released yet, so they are marked as waiting on it rather than simulated against a state that does not exist — and every call is simulated again from its real sender immediately before it is sent. Resetting a range realises impermanent loss that was unrealised while the position sat still, and that loss is not in the figures the decision was made on. It reads ticks rather than prices, and a position's uncollected fees come from tokensOwed, which is stale until something touches the position — so that figure can read low. Time outside a range is only ever the time between observations that saw it outside; a departure between two reads is not dated. Fee projections annualise one pool-wide 24-hour observation and are not a forecast or this position's measured earnings. A confirmed transaction shows the reset executed as it was authorised and shows nothing about whether it was worth taking. A staked position cannot be reset at all: MasterChefV3 holds its NFT. One read covers a bounded slice of a wallet's positions, newest first, and returns positions_held beside positions_examined so a truncated read announces itself; closed positions are counted and not detailed. A single recorded read; no paired run against a person stands behind the metrics on this card.","evidence":[{"kind":"advantage_task","url":"/advantage#01-liquidity","label":"Task 01 — the same wallet read by hiring and by hand, both outputs in full with the hashes that bind them"}],"agent_path":null,"identity_note":"The snapshot Docket serves does not hold this agent, so there is no /agents record to open for it here. Docket's default sweep covers the agents carrying at least one feedback record, which is a small slice of the registry — an identity outside that slice is registered on chain and is simply not in what Docket indexed."}