[intent-coprocessor]: Price Discovery Protocol#684
Conversation
…in the ProxyModule to passively build a VerifiedFillers map, enabling a third price submission path that requires only an EVM signature instead of full ISMP state proofs.
| Ok(entries) => Ok(entries | ||
| .into_iter() | ||
| .map(|(range_start, range_end, price, timestamp)| RpcPriceEntry { | ||
| range_start: range_start.to_string(), |
There was a problem hiding this comment.
Let's divide the prices by 10**18 here to cnvert it to human readable value before returning
There was a problem hiding this comment.
Preserve the decimals during this conversion
| <T as Config>::Currency::reserve(&submitter, deposit_amount) | ||
| .map_err(|_| Error::<T>::InsufficientBalance)?; | ||
|
|
||
| PriceDeposits::<T>::insert(&submitter, &pair_id, (deposit_amount, now)); |
There was a problem hiding this comment.
The deposit lock duration is only relevant to withdrawals.
When a Filler wants to withdraw, they submit an extrinsic to initiate it, then we note the block at which the tokens can be unreserved using the configured pricelockduration, The filler can complete the withdrawal only after that block has elapsed
|
|
||
| Submissions are batched. Each call accepts up to `MaxPriceEntries` entries (a compile-time constant configurable per runtime), where each entry specifies a base token amount range and the corresponding price of the base token in terms of the quote token. This makes it possible to quote different rates for different order sizes in a single transaction. For example, a submitter might quote USDC/CNGN at 1414 for orders between 0 and 999, and 1420 for orders between 1000 and 5000. | ||
|
|
||
| Each price entry contains three fields. The `range_start` field is the lower bound of the base token amount range (inclusive). The `range_end` field is the upper bound (also inclusive). The `price` field is the price of the base token in terms of the quote token. The pallet validates that `range_start` is less than or equal to `range_end` for every entry and rejects empty submissions. When stored on-chain, each entry becomes a `PriceEntry` that also includes the submission timestamp. |
There was a problem hiding this comment.
| Each price entry contains three fields. The `range_start` field is the lower bound of the base token amount range (inclusive). The `range_end` field is the upper bound (also inclusive). The `price` field is the price of the base token in terms of the quote token. The pallet validates that `range_start` is less than or equal to `range_end` for every entry and rejects empty submissions. When stored on-chain, each entry becomes a `PriceEntry` that also includes the submission timestamp. | |
| Each price entry contains three fields. The `range_start` field is the lower bound of the base token amount range (inclusive). The `range_end` field is the upper bound (also inclusive). The `price` field is the cost of one unit of the base token in terms of the quote token. The pallet validates that `range_start` is less than or equal to `range_end` for every entry and rejects empty submissions. When stored on-chain, each entry becomes a `PriceEntry` that also includes the submission timestamp. |
| Price updates are configured by adding a `[priceUpdates]` section to the filler TOML configuration file. | ||
|
|
||
| ```toml | ||
| [priceUpdates] |
There was a problem hiding this comment.
We do not need this, the fx strategy config already has a price policy, we should just use the values specified there to submit price updates
…linear benchmarking
…om:polytope-labs/hyperbridge into dami/filler-price-pair-update
|
We should support different prices for bids/asks. Also no reason to restrict pairs to governance |
remove governance pairs
Yeah we do, the pairId for bids is keccak256("[stable]/[exotic]") while that for asks is keccak256("[excotic]/[stable]") FIllers submit prices for both |
Would you rather people pay to add recognized pairs? We don't want spam because we need to clear the pair prices at intervals, we can't have it growing endlessly. |
…/filler-price-pair-update # Conflicts: # sdk/packages/simplex/src/core/filler.ts
Wizdave97
left a comment
There was a problem hiding this comment.
Much Simpler @seunlanlege take another look.
| * @returns Array of Quote objects, one per filler who has price entries for this pair | ||
| */ | ||
| async getQuotes(pairId: HexString, amount: number): Promise<Quote[]> { | ||
| const entries: RpcPriceEntry[] = await (this.api as any)._rpcCore.provider.send( |
There was a problem hiding this comment.
We should filter out price entries that are older than 24 hours
Overview
This PR introduces a deposit-based price submission protocol for the intents coprocessor. The intents system needs on-chain price data for token pairs to function correctly. Rather than depending on external oracles, this protocol allows anyone to submit prices for governance-approved token pairs by putting up a one-time deposit. Subsequent updates to the same pair are free, and the deposit can be reclaimed through a two-phase withdrawal process.
The implementation spans the pallet, RPC, SDK, and simplex filler.
Pallet
The
submit_pair_priceextrinsic accepts price submissions for governance-approved token pairs. Each submission contains one or more price entries specifying a base token amount range and the corresponding price (all encoded as U256 scaled by 10^18). On the first submission per (account, pair), a configurable deposit is reserved from the submitter's balance. Further updates to the same pair are free.Deposits are withdrawn through a two-phase process via
withdraw_price_deposit. The first call records the unlock block (current block + governance-configured lock duration in blocks). The second call, after the unlock block is reached, unreserves the tokens and removes the deposit record. Calling too early fails withDepositStillLocked.Prices are organized into time-based windows. When a window expires, existing price data is lazily cleared on the first new submission rather than in
on_initialize.Governance extrinsics control recognized token pairs, deposit amounts, lock duration, and window duration.
RPC
The
intents_getPairPrices(pair_id)endpoint returns all price entries for a given pair. On-chain U256 values (scaled by 10^18) are converted to human-readable decimal strings with fractional precision preserved (e.g.1414500000000000000000becomes"1414.5").SDK
IntentsCoprocessorin@hyperbridge/sdkexposessubmitPairPrice(pairId, entries)andwithdrawPriceDeposit(pairId)for interacting with the pallet from TypeScript. ThesignAndSendExtrinsichelper checks for dispatch errors within theisInBlock/isFinalizedstatus handler so that on-chain failures are correctly reported.Simplex filler integration
A
PriceUpdateServicein@hyperbridge/simplexhandles periodic price submission on a configurable interval (default 5 minutes). It iterates through all configured pairs and callssubmitPairPricefor each one. TheIntentFillerstarts this service automatically when a[priceUpdates]section is present in the TOML config, with human-readable amounts converted to 18-decimal format at parse time.