Skip to content

[runtime/simplex]]: add phantom order support for passive price and liquidity indexing#983

Draft
dharjeezy wants to merge 12 commits into
mainfrom
dami/phantom-order
Draft

[runtime/simplex]]: add phantom order support for passive price and liquidity indexing#983
dharjeezy wants to merge 12 commits into
mainfrom
dami/phantom-order

Conversation

@dharjeezy

Copy link
Copy Markdown
Contributor

Adds phantom order price and liquidity indexing to the intent coprocessor. The pallet gains two new extrinsics — register_phantom_order (permissionless) and set_phantom_bid_window (governance) — along with the CurrentPhantomOrder and PhantomBidWindow storage items and a phantom_bid_window() helper that mirrors the existing storage_deposit_fee() fallback pattern.

The SubQuery indexer is extended with handlePhantomOrderRegistered and handlePhantomBidPlaced handlers that decode each filler's user operation, extract proposed output amounts, and run a lightweight ERC-20 transfer simulation via state overrides to produce a simulationSuccess signal indexed alongside each bid.

closes #977

/// registered phantom order. Called by the intent coprocessor service.
#[pallet::call_index(7)]
#[pallet::weight(T::WeightInfo::register_phantom_order())]
pub fn register_phantom_order(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct, the phantom order should be generated by the runtime in the pallet hooks


Ok(())
}

@Wizdave97 Wizdave97 Jun 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no extrinsic to setup the phantom order details, like token pairs, chain for the order?

import { timestampToDate } from "@/utils/date.helpers"
import { PhantomOrder } from "@/configs/src/types"

export const handlePhantomOrderRegistered = wrap(async (event: SubstrateEvent): Promise<void> => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to index the phantom order

* one reverts, and `null` when the simulation could not be run (e.g. RPC error,
* unsupported node).
*/
async function simulateTokenTransfers(

@Wizdave97 Wizdave97 Jun 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct, simulate the bid as is, don't change the solver's balance, only state override needed is the block number so the order is not expired when simulating

@dharjeezy dharjeezy requested a review from Wizdave97 June 22, 2026 16:56
chain: &[u8],
pair: &PhantomTokenPair,
) -> H256 {
let mut preimage = Vec::new();

@Wizdave97 Wizdave97 Jun 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phantom order should be an actual intent gateway order.

Comment thread sdk/packages/simplex/src/services/ContractInteractionService.ts
beneficiary: FixedBytes::from([0u8; 32]),
assets: vec![sol_types::TokenInfo {
token: FixedBytes::from(token_b_bytes),
amount: AlloyU256::from(min_output),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output should be zero

let mut token_b_bytes = [0u8; 32];
token_b_bytes[12..].copy_from_slice(token_b.as_bytes());

let order = sol_types::Order {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This order is not added to offchain storage

Comment thread parachain/runtimes/nexus/src/ismp.rs Outdated

parameter_types! {
pub const IntentsStorageDepositFee: Balance = EXISTENTIAL_DEPOSIT * 10;
pub const IntentsPhantomOrderBidWindow: u32 = 15;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 hour in terms of blocks

params: [
{ from: solver, to: solver, data: callData },
"latest",
{ [gatewayAddress]: { code: "0x" } },

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong, the bid should be validated against intent gatway's code.
the override required is inserting the phantom order commitment into the intent gateway's contract state

deadline: AlloyU256::ZERO,
nonce: AlloyU256::from(block),
fees: AlloyU256::ZERO,
session: Address::ZERO,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't use a zero session key, generate a static key with a known private key that would always be used for all phantom orders.
Please refer to the sdk for how bid simulation works.

if (!simOk) continue

const tokenAddress = bytes32ToBytes20(output.token)
const balance = await getTokenBalance(evmUrl, tokenAddress, solver)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to fetch the filler's balance from the Aave's USDC/USDT vault and cngn yield vault also


const tokenAddress = bytes32ToBytes20(output.token)
const balance = await getTokenBalance(evmUrl, tokenAddress, solver)
if (balance === null || balance < outputAmount) continue

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we not storing the LP's balance?


const tokenAddress = bytes32ToBytes20(output.token)
const balance = await getTokenBalance(evmUrl, tokenAddress, solver)
if (balance === null || balance < outputAmount) continue

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is not necessary, if the simulation succeeded the filler must have some balance somewhere

Suggested change
if (balance === null || balance < outputAmount) continue

… and gateway state override for phantom order simulation
@dharjeezy dharjeezy requested a review from Wizdave97 June 23, 2026 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[runtime/simplex]: Intent Coprocessor Price and Liquidity indexing

2 participants