Post
Share your knowledge.
Gas-Efficient Oracle Aggregation
What’s the most efficient way to encode oracle aggregation logic on Sui to prevent manipulation while minimizing gas costs for data consumers?
- Sui
- Architecture
- Transaction Processing
- Security Protocols
- NFT Ecosystem
Answers
5I’ve built oracle stacks for production chains before — on Sui I try to balance three things at once: manipulation resistance, low gas for consumers, and practical economics for reporters. Below I give the architecture I use, why each piece matters, full Move-style patterns (runnable-looking, with placeholders where runtime natives are required), and an operational checklist + tests you should run.
I’ll keep this practical and in first person.
Short summary — the architecture I use
- Off-chain aggregator(s) collect signed reports from a small, rotating committee of oracles.
- Aggregator publishes a compact epoch commitment on-chain (Merkle root or aggregated signature) — not every report. This keeps consumer gas tiny.
- Consumers read the latest finalized epoch root and verify a Merkle proof (leaf → value) or the aggregated signature for the value they need.
- A challenge / dispute window lets anyone post fraud proofs after an epoch root is published; if challenge succeeds the aggregator’s bond is slashed.
- Reporter nodes are backed by staking / deposit + reputation and must stake to participate. Slashing + rotation prevents long-term manipulation.
This approach gives consumers O(1) on-chain cost (read root + present small proof) and pushes heavy aggregation costs off-chain (cheap off-chain CPU). Manipulation is discouraged by economic stakes and contestability.
Why these pieces (short rationale)
- Publish roots, not full lists: writing everything on-chain is expensive. A Merkle root (32 bytes) is cheap and verifiable with a log-proof.
- Off-chain aggregation lets you run robust aggregation (trimmed mean, weighted median) with large sample sets; only the compact commitment goes on-chain.
- Dispute window + slashing turns economic deterrence into practical security: bad roots get challenged or the aggregator loses stake.
- Light on-chain sanity checks (bounds, monotonicity) catch gross manipulation cheaply before consumers rely on values.
- Threshold sigs / aggregated signatures (BLS/Schnorr) provide a single on-chain signature verifying that N-of-M oracles attested a single aggregate, without storing a Merkle tree.
Aggregation methods I recommend
- Median — robust to outliers; cheap to compute off-chain.
- Trimmed mean — remove top/bottom X% then average; good vs collusion but slightly costlier.
- Weighted median — weight by stake/reputation; thwarts sybil with minimal extra complexity. For production I use weighted median where weights are oracle stake * reputation score.
Move patterns — on-chain contract sketches
Below are simplified Move modules showing how I store epoch roots, let aggregators publish them, allow consumers to claim a value with a proof, and enable disputes/slashing. Replace native
placeholders with your Sui runtime primitives (BLS verification or merkle verify).
Notes:
verify_agg_sig
andverify_merkle_proof
arenative
placeholders — your Sui binary can/should provide efficient crypto ops as natives.- These are runnable-looking skeletons: adapt object/UID APIs and gas accounting to your toolchain.
1) Oracle registry + root publish + dispute
module oracle::registry {
use sui::object::{UID};
use sui::tx_context::{TxContext};
use sui::event;
/// Epoch commitment stored on-chain
struct EpochRoot has key {
id: UID,
epoch: u64,
root: vector<u8>, // merkle root OR encoded (value|meta)
aggregator: address, // who published
agg_sig: option::Option<vector<u8>>, // optional aggregated signature
published_ts: u64,
finalized: bool,
bond: u128, // aggregator's posted bond (optional)
}
struct Dispute has key {
id: UID,
epoch: u64,
challenger: address,
proof_hash: vector<u8>, // hash of dispute evidence
resolved: bool,
}
// Events
struct RootPublishedEvent has store { epoch: u64, root_hash: vector<u8>, by: address, ts: u64 }
struct RootFinalizedEvent has store { epoch: u64, root_hash: vector<u8>, ts: u64 }
struct SlashedEvent has store { aggregator: address, amount: u128 }
// native verification helpers (must be provided/implemented efficiently)
native public fun verify_agg_sig(pubkeys: vector<vector<u8>>, agg_sig: vector<u8>, message: vector<u8>) : bool;
native public fun verify_merkle_proof(leaf: vector<u8>, proof: vector<vector<u8>>, root: vector<u8>) : bool;
/// Publisher posts a compact commitment for an epoch
public(entry) fun publish_root(
epoch: u64,
root: vector<u8>,
agg_sig: option::Option<vector<u8>>,
pubkeys_hash: vector<u8>, // optional compact identifier of signers
bond: u128,
ctx: &mut TxContext
) : EpochRoot {
let id = object::new(ctx);
let r = EpochRoot {
id,
epoch,
root,
aggregator: tx_context::sender(ctx),
agg_sig,
published_ts: tx_context::epoch(ctx),
finalized: false,
bond
};
event::emit(RootPublishedEvent { epoch: r.epoch, root_hash: r.root, by: r.aggregator, ts: r.published_ts });
r
}
/// Finalize after dispute window
public(entry) fun finalize(root_obj: &mut EpochRoot, now: u64, dispute_window: u64) {
assert!(now >= root_obj.published_ts + dispute_window, 1);
root_obj.finalized = true;
event::emit(RootFinalizedEvent { epoch: root_obj.epoch, root_hash: root_obj.root, ts: now });
}
/// Anyone can post a dispute against an epoch root
public(entry) fun dispute(root_obj: &mut EpochRoot, proof_hash: vector<u8>, ctx: &mut TxContext): Dispute {
// challenge registrant must include on-chain evidence off-chain later
let id = object::new(ctx);
let d = Dispute { id, epoch: root_obj.epoch, challenger: tx_context::sender(ctx), proof_hash, resolved: false };
// optionally hold a small challenger bond to avoid spam
d
}
/// On successful dispute (off-chain proof verified by governance or prover),
/// slash aggregator bond. This function assumes an off-chain fraud-proof was validated by governance or a native prover.
public(entry) fun slash(root_obj: &mut EpochRoot, amount: u128, treasury: &mut account::Treasury) {
assert!(root_obj.bond >= amount, 2);
root_obj.bond = root_obj.bond - amount;
// transfer to treasury (pseudocode)
// account::credit(treasury, amount)
event::emit(SlashedEvent { aggregator: root_obj.aggregator, amount });
}
}
2) Consumer-side verification pattern (proof + leaf)
Consumers should be able to read a finalized epoch root and verify a Merkle proof for a single value:
module oracle::consumer_api {
use oracle::registry;
use sui::tx_context::TxContext;
// Consumer provides: epoch root id, value leaf, merkle proof (vector of hashes)
public(entry) fun consume_with_proof(
root_obj: ®istry::EpochRoot,
leaf: vector<u8>,
proof: vector<vector<u8>>,
) {
// inexpensive sanity checks
assert!(root_obj.finalized, 100); // only rely on finalized roots
assert!(registry::verify_merkle_proof(leaf, proof, root_obj.root), 101);
// decode value from leaf and use it
// e.g., let value = decode_value(leaf);
// apply on-chain logic using 'value'
}
}
3) Optional: aggregated-signature path (single sig verifies N reporters)
If you use BLS threshold signatures, aggregator posts agg_sig
and message
(e.g., epoch|root|policy
), consumers can verify verify_agg_sig(pubkeys, agg_sig, message)
with a single native op — extremely gas efficient.
Gas-minimization tips I always follow
- Store only the root and a small header (epoch, timestamp, aggregator). Consumers supply tiny Merkle proofs (log N).
- Finalized roots only: consumers should rely only on
finalized=true
roots — finalization happens after dispute window to avoid paying for rollbacks. - Use aggregated signatures if your committee supports BLS — a single signature check is far cheaper than multiple signature checks or writing many pubkeys on-chain.
- Pack values tightly in leaves (integer encodings) to reduce Merkle leaf sizes and proof sizes.
- Cache frequent values: for high-value data (e.g., price tick) keep a small on-chain cached value with timestamp + root reference so simple consumers can skip proofs if they trust the finality window.
Economic & operational controls I enforce
- Minimum stake to be an oracle; stake scales vote weight.
- Rotation & random selection: pick signers per epoch by weighted randomness to reduce collusion windows.
- Slashing: aggregator or individual signers lose stake if fraud proof valid.
- Reputation scoring cheaper than burning stake — lower-rep oracles get less weight.
- Quorum rules: require at least K of M signers for aggregated sig or weighted sum > threshold.
Anti-manipulation techniques I use off-chain & on-chain combined
- Weighted median instead of mean for aggregation (robust to outliers).
- Timestamp sequencing & staleness checks — consumers should drop values older than X seconds.
- Sanity checks on-chain (cheap): reject values > factor * previous_value, or negative. This prevents silly spikes from being used by naive consumers.
- Replay protection — include epoch and chain-specific domain separation in signed messages and roots.
Dispute & fraud proof flow I implement
- Aggregator publishes root + short metadata + bond.
- Dispute window opens (e.g., 30s–5min depending on asset). Anyone can submit a fraud proof referencing the epoch (on-chain claim with proof hash).
- Off-chain fraud-proof verification (heavy crypto) is either handled by a light client / verifier or by governance committee. If fraud valid → call
slash()
and mark root invalid. If no dispute within window → finalization allowed. - Consumers only read
finalized
roots.
This keeps on-chain lightweight but still contestable.
Tests & attack simulations I always run
- Single-oracle takeover: simulate one oracle delivering extreme values; measure damage with weighted median vs mean.
- Aggregator equivocation: duplicate publishing different roots for same epoch — ensure dispute detection & slashing prevents profit.
- Sybil attack: low-weight fake reporters flood data — ensure stake-weighting disincentivizes.
- Replay attacks: replay old root — ensure epoch/domain prevents reuse.
- Proof verification fuzzing: random Merkle proofs (invalid length, malformed) — ensure contract rejects and costs are bounded.
Example consumer flow (what I implement in SDK)
- Fetch latest
EpochRoot
object id and checkfinalized == true
. - If final, request Merkle proof from aggregator/indexer for desired datapoint.
- Submit a transaction or just verify off-chain (if consumer only reads) using
verify_merkle_proof(leaf, proof, root)
. If consumer needs on-chain verification (e.g., to settle), calloracle::consumer_api::consume_with_proof
with proof. - If root not finalized, either wait or use additional risk controls (slippage guard).
I don’t let raw oracle submissions flood the chain. Instead, I build a two-layer model:
- Off-chain aggregation — oracles sign their data, an aggregator computes the median or weighted median, then posts only a compact digest.
- On-chain verification — the contract stores only
(epoch, digest, agg_sig)
and allows consumers to verify inclusion proofs.
The efficiency comes from pushing heavy math off-chain while providing lightweight verifiability on-chain. Consumers only need to verify one of:
- a Merkle proof of a value against the root, or
- a BLS aggregated signature over the median.
To prevent manipulation, I enforce:
- Quorum threshold: require N-of-M signatures.
- Stake-weighted voting: large oracles with more stake carry more weight.
- Slashing bonds: aggregators who post bad digests get slashed if fraud-proof submitted.
Move-style snippet:
struct OracleDigest has key {
id: UID,
epoch: u64,
root: vector<u8>, // Merkle root
agg_sig: vector<u8>, // aggregated sig of oracles
finalized: bool,
}
public entry fun submit_digest(
epoch: u64, root: vector<u8>, sig: vector<u8>, ctx: &mut TxContext
): OracleDigest {
let id = object::new(ctx);
OracleDigest { id, epoch, root, agg_sig: sig, finalized: false }
}
Gas cost is minimized because consumers only read the latest finalized digest and verify a small proof. Instead of looping over all oracle submissions, they deal with one root or one aggregated sig.
This makes oracle data secure (manipulation-resistant) and cheap to consume at scale.
Practical design I’d use if I were building an oracle stack on Sui today — focused on manipulation resistance, low per-consumer gas, and operational simplicity. I’ll explain the architecture, why it’s safe, trade-offs, a Move sketch for on-chain anchors + consumer verification (Merkle + optional aggregated signature), and a short TypeScript snippet showing how I build a Merkle root and a proof off-chain. I’ll also include the tests/audit checks I always run.
Executive summary — the design I use
- Collect many off-chain signed reports from a committee of reporters.
- Compute a robust aggregate off-chain (weighted median or trimmed mean).
- Publish one compact commitment on-chain per epoch: either a Merkle root of reports or an aggregated signature over the aggregate (BLS). Store a tiny header (
epoch, root, aggregator, finalized
) on-chain. - Consumers prove a single value by supplying a logarithmic Merkle proof (cheap on chain) or verify a single aggregated signature (cheaper if native BLS is available).
- Enforce a dispute window + slashing so bad aggregates can be challenged. Consumers only rely on
finalized
roots. - Optionally keep a small on-chain cache of the last N values for instant read access (no proof) at slightly higher storage cost but zero per-call gas.
Why I prefer this: consumers pay O(log N) gas for rare claim transactions (or O(1) for agg sig), the heavy work and collusion-resistance calculations happen off-chain where you can run robust statistics, and accountability is enforced via slashing and dispute.
Detailed reasoning & security properties
Manipulation resistance
- Use robust statistics off-chain (weighted median or trimmed mean) so a minority of malicious reporters can’t swing the value. Weight by stake/reputation if possible.
- Require K-of-M signing (or aggregated signature) so an attacker must control many reporters.
- Provide dispute/fraud proofs and economic slashing (aggregator posts bond). A successful challenge loses bond — makes manipulation uneconomic.
Low gas for consumers
- Consumers verify a single Merkle proof (log N siblings) instead of reading many report objects.
- If you use BLS aggregated signatures, consumer does one native signature verify (very cheap compared to many signature checks or large data writes).
Practical operations
- Publish compact commitments each epoch (e.g., every block window or every 15s depending on asset sensitivity).
- Maintain an indexer/aggregator service that serves proofs — consumers rarely construct proofs themselves.
- Use
finalized
flag after dispute window; onlyfinalized
roots are trusted by on-chain logic.
Move sketch — anchor + consumer verification
This is runnable-looking Move pseudocode; replace native
with your Sui runtime crypto primitives (BLS verify, merkle verify). Keep objects tiny.
address 0xORACLE {
module oracle::anchor {
use sui::object::{UID};
use sui::tx_context::{self, TxContext};
use sui::event;
use std::vector;
// A compact epoch commitment
struct EpochRoot has key {
id: UID,
epoch: u64,
root: vector<u8>, // Merkle root (or encoded aggregate)
aggregator: address, // who posted
agg_sig: option::Option<vector<u8>>, // optional aggregated signature bytes
published_at: u64,
finalized: bool,
bond: u128, // optional economic bond
}
struct RootPublished has store { epoch: u64, root: vector<u8>, by: address, ts: u64 }
struct RootFinalized has store { epoch: u64, root: vector<u8>, ts: u64 }
struct RootSlashed has store { aggregator: address, amount: u128 }
// native stubs (implement in runtime): BLS verify / merkle verify
native public fun verify_agg_sig(pubkeys_digest: vector<u8>, agg_sig: vector<u8>, message: vector<u8>): bool;
native public fun verify_merkle_proof(leaf: vector<u8>, proof: vector<vector<u8>>, root: vector<u8>): bool;
public(entry) fun publish_root(epoch: u64, root: vector<u8>, agg_sig: option::Option<vector<u8>>, bond: u128, ctx: &mut TxContext): EpochRoot {
let id = object::new(ctx);
let r = EpochRoot { id, epoch, root, aggregator: tx_context::sender(ctx), agg_sig, published_at: tx_context::epoch(ctx), finalized: false, bond };
event::emit(RootPublished { epoch, root: r.root, by: r.aggregator, ts: r.published_at });
r
}
public(entry) fun finalize(root_obj: &mut EpochRoot, now: u64, dispute_window: u64) {
assert!(now >= root_obj.published_at + dispute_window, 1);
root_obj.finalized = true;
event::emit(RootFinalized { epoch: root_obj.epoch, root: root_obj.root, ts: now });
}
// challenge & slash (verifier must provide off-chain fraud-proof that governance validates)
public(entry) fun slash(root_obj: &mut EpochRoot, amount: u128) {
assert!(root_obj.bond >= amount, 2);
root_obj.bond = root_obj.bond - amount;
event::emit(RootSlashed { aggregator: root_obj.aggregator, amount });
}
}
module oracle::consumer {
use oracle::anchor;
use sui::tx_context::TxContext;
// Use value on-chain by proving inclusion against a finalized root
public(entry) fun consume_with_proof(root_obj: &anchor::EpochRoot, leaf: vector<u8>, proof: vector<vector<u8>>) {
assert!(root_obj.finalized, 100);
assert!(anchor::verify_merkle_proof(leaf, proof, root_obj.root), 101);
// decode leaf -> (symbol, value, epoch) and apply logic
}
// Optionally accept aggregated sig path: verify agg_sig over (epoch,root)
public(entry) fun consume_with_agg_sig(root_obj: &anchor::EpochRoot, pubkeys_digest: vector<u8>) {
assert!(root_obj.finalized, 200);
assert!(option::is_some(&root_obj.agg_sig), 201);
let sig = option::borrow(&root_obj.agg_sig).copy();
let msg = build_message(root_obj.epoch, root_obj.root);
assert!(anchor::verify_agg_sig(pubkeys_digest, sig, msg), 202);
}
fun build_message(epoch: u64, root: vector<u8>): vector<u8> {
// domain separated encoding of epoch || root
}
}
}
Notes I follow
- Only
finalized
roots are consumed. agg_sig
is optional; when available it gives the cheapest consumer experience (single verify).bond
andslash
mechanism deters a malicious aggregator.
Off-chain aggregator (what I run)
-
Collect signed reports: each reporter signs
(symbol, value, epoch, reporter_id)
with its private key. -
Perform aggregation: compute weighted median or trimmed mean. I prefer weighted median by stake for price feeds.
-
Build a Merkle tree over either:
- (a) full reports (if consumers sometimes need raw report proofs), or
- (b) compact per-symbol leaves
(symbol||agg_value||epoch)
if consumers only need the aggregate.
-
Optionally produce a BLS aggregated signature over the message
(epoch||root||policy_id)
if the reporter set supports threshold BLS. -
Publish: call
publish_root(epoch, root, agg_sig_opt, bond)
.
I run an indexer that serves Merkle proofs to consumers and also monitors RootPublished
events to know when to finalize after the dispute window.
TypeScript: build Merkle leaf/root & proof (compact example)
This is the same pattern I use in my infra — deterministic encoding, sha256 tree, sorted pairs:
import crypto from "crypto";
function sha256(b: Buffer) { return crypto.createHash('sha256').update(b).digest(); }
function leafFor(symbol: string, value: string, epoch: number) {
// canonical encoding must be consistent off-chain/on-chain
return sha256(Buffer.from(`${symbol}|${epoch}|${value}`,'utf8'));
}
function buildTree(leaves) {
let layer = leaves.slice();
const layers = [layer];
while (layer.length > 1) {
const next = [];
for (let i=0;i<layer.length;i+=2) {
const a=layer[i], b=(i+1<layer.length?layer[i+1]:layer[i]);
// sort to remain order independent
const pair = Buffer.compare(a,b) <= 0 ? Buffer.concat([a,b]) : Buffer.concat([b,a]);
next.push(sha256(pair));
}
layer = next;
layers.push(layer);
}
return layers;
}
function getProof(layers, idx) {
const proof = [];
for (let level=0; level<layers.length-1; level++) {
const layer = layers[level];
const pairIdx = idx ^ 1;
proof.push(pairIdx < layer.length ? layer[pairIdx] : layer[idx]);
idx = Math.floor(idx/2);
}
return proof;
}
I serve the leaf
+ proof
to consumers from an indexer API. Consumer calls consume_with_proof
giving the EpochRoot
id, leaf bytes and proof array.
Gas minimization tips I always apply
- Publish only compact root on-chain. Don’t write all reports.
- Let consumers do on-chain verification only when needed: for read-only use, verify proofs off-chain and trust client; for settlement/security-critical actions, require on-chain proof verification.
- Use aggregated signature path (one native op) if available — huge gas win.
- Pack leaves tightly (binary fixed-width for epoch + value) to reduce proof byte lengths.
- On-chain caching: keep a tiny cache of most recent values (the aggregator can write a small
CachedValue
object for extremely hot keys so consumers can read without proof). Evict frequently.
Tests & audits I run
- Robustness: compare weighted median vs mean under adversarial inserts.
- Equivocation: aggregator posts two conflicting roots for same epoch; ensure dispute flow & slashing detect and penalize.
- Single-reporter takeover: simulate N-1 honest + 1 malicious and verify aggregate is stable.
- Proof verification: fuzz Merkle proof inputs (lengths, malformed siblings) to confirm on-chain verification rejects garbage cheaply.
- Replay & domain: replay old roots/proofs onto new epochs/chains — must fail due to domain separation included in signed messages.
Trade-offs and final notes
- Agg sig vs Merkle: aggregated sig (BLS) = cheapest consumer, but requires cryptographic native support and keyed reporters. Merkle root = extremely portable and native-friendly but consumer pays log N proof cost. I prefer offering both: publish root + agg sig when available.
- Dispute window latency: longer windows increase security (time to challenge) but increase time-to-finality for consumers. Choose based on financial risk.
- Indexers & availability: consumers rely on indexers for proofs; run redundant indexers and relayers to avoid single points of failure.
As a professional Web3 developer specializing in Sui and Move, I'll outline how I implement strategies to prevent manipulation while optimizing gas costs for data consumers on the Sui network.
Core Protection Mechanisms
- Smart Contract Security
- I leverage Move's object-centric model to create tamper-resistant smart contracts 1:1
- Implement formal verification using Move Prover to mathematically prove contract correctness 0:5
- Structure contracts to prevent common exploits like reentrancy attacks and integer overflows
- Transaction Processing Strategy
- Utilize Sui's parallel transaction execution for optimal gas efficiency 0:7
- Route simple transactions outside consensus protocol for instant settlement
- Implement MEV resistance through deterministic ordering in parallel execution 1:0
flowchart LR
classDef simple fill:#90EE90,stroke:#006400,color:#000
classDef complex fill:#FFB6C1,stroke:#8B0000,color:#000
classDef optimize fill:#87CEEB,stroke:#00008B,color:#000
TX[Transaction] --> Type{Type?}
Type -->|Simple| Simple["• Token Transfer
• Basic Operations"]
Type -->|Complex| Complex["• Multi-asset
• Cross-contract Calls"]
Simple --> Optimize["Optimization Strategies:
• Parallel Execution
• DAG-based Ordering
• Sponsored Gas"]
Complex --> Validate["Validation Layer:
• MEV Resistance
• Formal Verification
• State Protection"]
Optimize --> Result["Results:
• Lower Gas Costs
• Faster Settlement
• Enhanced Security"]
Validate --> Result
class Simple simple
class Complex complex
class Optimize,Validate,Result optimize
The diagram above illustrates my approach to transaction handling on Sui. Green boxes represent simple transactions that can bypass consensus for immediate settlement, while pink indicates complex operations requiring additional validation. Blue sections show the optimization layers that ensure both security and cost efficiency.
Implementation Strategies
- Gas Cost Optimization
- Implement sponsored transactions and gas stations 1:0 to eliminate direct user costs
- Leverage horizontal scaling architecture to maintain consistent costs during high demand 1:1
- Use programmable transaction blocks (PTBs) for complex operations to reduce overall gas consumption
- Data Consumer Protection
- Structure smart contracts using Move's object-oriented model for predictable behavior 0:5
- Implement deterministic ordering in parallel transaction execution to prevent manipulation 1:0
- Utilize Sui's DAG-based consensus (Mysticeti) for ultra-fast finality and reduced latency 1:1
Best Practices
- Contract Development
- Write contracts that take advantage of parallel execution where possible
- Implement proper state management to prevent race conditions
- Use formal verification tools to prove contract correctness before deployment
- Transaction Optimization
- Batch similar transactions when possible
- Leverage sponsored gas for user-facing applications
- Monitor network congestion and adjust transaction timing accordingly
By implementing these strategies, I ensure that my applications on Sui maintain high security standards while keeping costs minimal for data consumers. The combination of Move's security features and Sui's advanced transaction processing creates a robust environment that prevents manipulation while optimizing resource utilization.
Use a hybrid approach: push most raw samples off-chain to a decentralized oracle network, store compact aggregated checkpoints on-chain (time-windowed TWAPs or truncated TWAPs) and read them on-demand, and when you need stronger attack resistance compute a cheap on-chain trimmed-mean/median only over a small, recent sample of trusted reporters — this keeps gas low while raising the cost to manipulate. Keep reporters permissioned-but-rotating or stake-backed so you can slash or rotate bad nodes fast, require signatures from a quorum to include a new checkpoint, and cap per-block price movement (or use truncated updates) so a single large trade can’t instantly flip the value. Bias your on-chain logic toward simple, single-pass math (incremental TWAP updates or sum/count windows) instead of expensive sorts; if you must compute medians, do it off-chain and publish a succinct Merkle proof plus the small sorted slice on-chain for verification to avoid high gas. Add cheap sanity checks in Move (max delta, liquidity-weighted checks, reporter timestamp bounds) to reject obvious lies before any expensive state write. For many use cases you’ll get the best trade-off by combining (1) low-cost, frequent TWAP checkpoints on Sui (good for gas) with (2) occasional higher-cost verified median/trimmed-mean checkpoints only when consumers need high-confidence prices — that way ordinary reads stay cheap and high-security reads happen rarely.
Do you know the answer?
Please log in and share it.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
- How to Maximize Profit Holding SUI: Sui Staking vs Liquid Staking615
- Why does BCS require exact field order for deserialization when Move structs have named fields?65
- Multiple Source Verification Errors" in Sui Move Module Publications - Automated Error Resolution55
- Sui Move Error - Unable to process transaction No valid gas coins found for the transaction419
- Sui Transaction Failing: Objects Reserved for Another Transaction410