Only this pageAll pages
Powered by GitBook
1 of 70

Entangle

Entangle

Loading...

Loading...

Universal Data Feeds

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Universal Token Standard

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Entangle Interoperable Blockchain

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

More

Loading...

Loading...

Loading...

Loading...

Security Audits

Entangle has undergone rigorous audits by the industry's top security firms — Halborn, Sentnl, and Astrarizon — ensuring its infrastructure is fortified and secure at the highest standards.

Halborn Audits

Sentnl Audits

Astrarizon Audits

Overview

Universal Data Feeds (UDF) is a next-generation, high-performance oracle network delivering hyper-fast, cost-efficient, reliable, and highly secure data feeds across multiple blockchains. UDF is the gateway to a new era of decentralized data, enabling real-time, high-frequency data delivery for DeFi, AI-driven applications, and Real-World Assets (RWAs). Supporting both push and pull models through dedicated marketplace contracts deployed on target chains, UDF ensures trust-minimized, low-latency updates while optimizing costs for decentralized applications.

For a deeper analysis, explore the details in our whitepaper.

How does it work?

UDF is a decentralized platform that connects on-chain and off-chain data to smart contracts, facilitating real-time data delivery from a variety of sources. UDF supports both EVM and non-EVM networks with a standardized delivery format that's designed to offer developers the flexibility to work across blockchains — providing a flexible, secure, and scalable infrastructure for creating data-driven solutions across diverse platforms.

By offering both Push and Pull Oracle delivery models, UDF allows developers to choose the most suitable method for their use cases. The Push model continuously updates data at predetermined intervals, while the Pull model gives applications the ability to retrieve data only when needed, optimizing efficiency and cost. UDF empowers decentralized applications to interact with real-time data, whether it’s for trading, cross-chain communication, or any other data-dependent function.

Additionally, UDF offers an intuitive and easy to use marketplace hub, a fully integrated ecosystem, acting as the entry point for users to access feeds. It provides users an all in one page to search for assets and manage their data feed subscriptions.

Features

Explore

Overview

Entangle is a programmable interoperability layer that seamlessly connects all blockchains, data sources, and the real world, unlocking endless possibilities for future-ready decentralized applications. With Entangle, developers can easily launch, scale, and automate dApps, tokens and AI agents to interact across all blockchains without limitations.

Entangle’s toolkit provides developers access to ultra-fast, verifiable and programmable data from any source while enabling secure, trustless verification of complex off-chain software on-chain.

The technology stack serves as the foundational toolkit to build and scale mass-adoption ready applications including: DeFAI, Autonomous AI Agents, GameFAI, Real World Assets (RWA), DeSci and more.


For any inquiries or assistance, feel free to reach out to the Entangle team via the or the community via the channel.

Pull Model

Entangle's Pull Model ensures real-time data availability for user transactions, eliminating dependency on scheduled updates. This approach enhances the precision and reliability of blockchain applications by providing up-to-date information when needed.

When a transaction is initiated, the application requests the latest data directly from Entangle's decentralized sources. The data is retrieved instantly from a snapshot of verified data, and is authenticated within the same transaction. This ensures only accurate, real-time data is used, minimizes costs, and provides a reliable foundation for cross-chain applications.

User Transaction

When a dApp user wants to perform an action (e.g., open a leveraged position, or open a lending/borrowing position), the latest data feed proof is included in the transaction’s calldata. This action uses the PullMarketplace contract with the functions verifyWithFee

and
verifyAsSubscriber
for PAYG and Subscription methods respectively.

On-Chain Verification

The UDF oracle contract verifies signatures from the aggregator (transmitters). If valid, the feed value is accepted for that user’s transaction.

Gas & Fee Implication

Each user pays a “verification fee” in native tokens (either through Pay-As-You-Go (PAYG) approach or predefined monthly subscriptions) to cover the cost of verifying the aggregator’s signatures and for the aggregator’s services. This suits lower-frequency but latency-sensitive use cases.

Summary

  • Minimal Data Staleness: The feed is as fresh as the aggregator’s most recent update with an update frequency of 200ms.

  • Lower Latency: Data is fetched during transaction creation and verified during execution, ensuring real-time accuracy.

  • Decentralized Access: Each user includes the proof, removing reliance on a single push node.

  • Fine-Grained Cost: Perfect for dApps using PAYG with moderate or unpredictable usage, as they pay only when they need the data.

  • Transaction Gas Costs: Each transaction requiring oracle verification incurs verification overhead.

  • Best for On-Demand Use Cases: Ideal for lending protocols, derivatives, and real-time settlement applications.

Entangle Blockchain Audit

TGE Audit

NGL Token Audit

Cover

Photon Messaging Audit

Cover

Audit Results

Cover

Entangle IDO Audit

Cover

Code Review Report

Cover
Cover
Cover
Learn More

High-Frequency Updates

Ultra-low-latency data updates by leveraging the Entangle Interoperable Blockchain and parallelized Layer 2 rollups. This means 200ms frequency for updates, short block times and reduced data latency. Ideal for high-speed trading, gaming, and AI-driven dApps.

Flexible Data Delivery Models

Choose exactly how your dApp receives oracle data. Select Pull for on-demand data access within transactions (PAYG or subscription), or Push for continuous updates using subscriptions with a fair cost-sharing model. Efficiently and precisely manage your data consumption needs.

Monetization Options

Control your oracle costs with flexible monetization options: Pay-As-You-Go for occasional data requests, Pull Subscriptions for predictable monthly access, and Push Subscriptions with deposits and cost-sharing. UDF provides affordability whatever your scale.

Intuitive Marketplace UI

Find, manage, and buy oracle feeds easily via the intuitive Marketplace UI. Quickly discover available feeds, customize subscription settings, and track your usage seamlessly from a single convenient dashboard. Accessing decentralized data has never been easier.

Customizable Update Parameters

Customize Push updates precisely with selectable price deviation thresholds (0.25%, 0.5%, 1%, 2.5%, 5%) and a default 24-hour heartbeat. Optimize data freshness and costs according to your app’s sensitivity, ensuring timely updates that are aligned with market movements and your specific needs.

Robust Security

Trusted data delivery using Byzantine Fault Tolerance (BFT). Decentralized transmitter nodes securely aggregate and cryptographically verify data, instantly detecting and penalizing malicious activity. UDF guarantees that your application always receives tamper-proof, validated data, even under adverse network conditions.

Cover

Architecture

Cover

Developer Guides

Cover

User Guides

Cover

Data Endpoints

Cover

Frequently Asked Questions

Products

More

contact form
Discord

Data Delivery Methods

UDF provides both push and pull oracle solutions through dedicated marketplace contracts deployed on target chains. These contracts enable seamless data access tailored to different use cases. Pull model is like ordering data on demand; push model is like subscribing to a live feed.

At the core of this system is VerificationLib, a smart contract deployed on target chains to aggregate signed oracle votes into a single, consensus-driven value. It supports multiple data types, including price feeds and high-precision floating-point values, ensuring adaptability across various applications.

Both push and pull marketplace contracts operate alongside VerificationLib, leveraging its validation mechanism to guarantee the integrity and reliability of oracle data.

When to Use Push vs. Pull Models

The Pull Model (On-Demand) fetches data only when required, ensuring it is up-to-date and reducing unnecessary updates. This method optimizes for accuracy and cost efficiency since the data is retrieved in real time based on the application’s needs. It eliminates delays caused by maintaining an on-chain state and is ideal for scenarios requiring real-time precision, such as DeFi trades or event-based actions.

On the other hand, for the Push Model (Continuous), data is delivered periodically, irrespective of immediate need, by maintaining an on-chain state. While it ensures that data is consistently available, this approach can introduce delays and inaccuracies due to the cost and technical limitations of frequently updating the on-chain state. As a result, this model is best suited for DEXs or stablecoin issuers requiring continuous price updates for liquidity pools at fixed intervals or price deviations.

Pricing

UDF’s flexible monetization covers both subscription-based payments for push and pull feeds and a pay-as-you-go (PAYG) model for pull verifications, allowing users to choose plans based on their data needs and cost preferences. Pricing details are implemented via the PullMarketplace and PushMarketplace contracts.

The Push Model delivers regular oracle updates based on configurable price deviations (0.25%, 0.5%, 1%, 2.5%, 5%) or a default heartbeat (every 24 hours). Users deposit funds upfront, and subscription costs are shared among all users. This becomes increasingly cost-effective as more subscribers join the same feed.

The Pull Model lets users fetch oracle data directly within their transactions using either Pay-As-You-Go (PAYG) or monthly subscriptions. PAYG users pay a small fee per data request, ideal for occasional queries, while subscriptions offer unlimited data access at predictable monthly rates. Since data updates occur continuously off-chain, users only pay transaction verification costs, regardless of usage frequency.

Please refer to the UDF for in-depth details on how the prices are calculated.

Pull Model

  • PAYG (Pay-As-You-Go): Users pay a small protocol fee per request. This model is best for dApps with sporadic or low-frequency data needs, as costs scale with usage. Learn more about the exact formula we use in our . PAYG is solely programatic and cannot be purchased through the marketplace, learn more .

  • Subscription: Users can subscribe to continuous data access for a fixed periodic (e.g. monthly) fee, eliminating the PAYG protocol fee. This model is ideal for applications with consistent data consumption, reducing transaction overhead while ensuring predictable expenses. You can manage your subscriptions through the marketplace.

Push Model

  • Fair Pricing Model: The protocol ensures pricing transparency by dynamically estimating costs based on gas prices, assets volatility, and cost sharing mechanisms. Users prepay for updates, there is a minimum deposit covering a few updates, and an estimated suggested deposit to cover for about 7 days of updates for the user to be able evaluate costs. Additionally we advise users to also consider the buffer deposit to cove for gas spikes and volatility.

  • Exclusive Access: On-chain price data is restricted to paying users, ensuring that only those contributing to the ecosystem benefit from updates.

  • Cost Sharing Mechanism: As more consumers subscribe to a feed, the cost per user decreases, making the model more economical at scale.

Cost Structure Across Multiple Chains

Gas prices vary significantly (e.g., Ethereum vs. an L2) and UDF must adapt. Fees vary based on the target chain’s gas costs; higher fees apply to expensive chains, while cheaper chains benefit from lower costs. Pricing is periodically adjusted to reflect changes in network fees, ensuring sustainable operations across all supported chains.

Speed

The Pull Model ensures that data updates are available in real-time, with minimal delay since users fetch and verify updates themselves, making it particularly useful for time-sensitive applications where immediate data updates are crucial, such as trading platforms or live dashboards.

In contrast, the Push Model, may introduce some latency since data is pushed periodically on-chain, an expensive process. While it is generally fast, it is better suited for applications where real-time updates are not as critical.

Gas Usage

The Pull Model provides excellent scalability for applications requiring frequent updates. It is best suited for scenarios with lower transaction volumes, where the cost impact of update verification remains minimal.

On the other hand, the Push Model scales efficiently across all scenarios by providing much simpler flow for feed value retrieval, saving gas for end-users. It's particularly advantageous for applications with medium-to-high transaction volumes, where gas usage is a significant concern. Push users simply read the latest data from storage without incurring additional gas charges, making this model a more cost-effective solution for handling high transaction volumes.

Fetch Data via Pull Model (PAYG)

In this section we will guide you on how to implement the Pull Model using the PAYG method.

Fetch Data via Push Model

In this section we will guide you on how to implement the Push Model.

Manage Subscription

In this step-by-step guide we'll go over how to manage your subscriptions using the Universal Data Feeds (UDF) . This process is an intuitive and straight forward process, follow the instructions below to get started.

1

Connect Wallet

Navigate to and click on "Connect Wallet" at the top right to connect your wallet.

Cover

EVM Smart Contracts

Cover

Solana Smart Contracts

Cover

EVM Smart Contracts

Cover

Solana Smart Contracts

Universal Token Standard (UTS)

Universal Data Feeds (UDF)

Entangle Interoperable Blockchain (EIB)

Security Audits

Join the Entangle Community

FAQ & Troubleshooting

Report an Issue

Become a Partner

Cover
Cover
Cover
Cover
Cover
Cover
Cover
Cover

Pull Model

Push Model

whitepaper
whitepaper
here
Cover
Cover

Solana Smart Contracts

This page is under construction and will be available soon. We're exploring Solana connectivity as a possible addition in a future release. We appreciate your patience and encourage you to follow us on social media to stay updated.

Solana Smart Contracts

This page is under construction and will be available soon. We're exploring Solana connectivity as a possible addition in a future release. We appreciate your patience and encourage you to follow us on social media to stay updated.

2

Navigate to Dashboard

Click on the "Dashboard" tab on the top of the page.

3

Dashboard

Your "Dashboard" allows you to manage all your subscriptions. You may view both active and inactive feeds, top up or renew subscriptions as well as view all your subscription details.

hub
https://udf.entangle.fi/

Architecture

The diagram above illustrates the architecture of Entangle's Universal Data Feeds (UDF), a system designed to ensure secure, efficient, and scalable delivery of verified data across blockchains. At its core, UDF integrates data Aggregation, Attestation, and Updating with a convenient Data Delivery method, supporting diverse use cases while ensuring reliability and accuracy.

Terminology

Core Stages

The process begins with data collection, where the raw data is fetched from reliable, high-quality Data Providers at fixed intervals. This data is encapsulated into a structured format containing key attributes such as the feedKey, value, and timestamp. To ensure the integrity and authenticity of the data, it is signed using ECDSA signatures, effectively securing it from tampering. Once packaged, the signed data is sent as an update transaction to the Oracle Chain, where it undergoes aggregation and attestation (validation).

The Oracle Chain serves as the processing hub, consisting of two key modules. It offloads data collection and processing to L2 auxiliary blockchains, enabling fast, distributed data collection and parallel processing for real-time data feeds. The Aggregation module consolidates inputs from multiple publishers into a coherent dataset. Subsequently, the Attestation module creates on-chain verifiable proofs, certifying the accuracy and reliability of the aggregated data on the target chain.

Users can then use the Update Provider Service which is a service to generate snapshots of data which are maintained on the Oracle Chain for consistency and retrieved via a Delivery Method (i.e., an API) for accessibility. It provides a unified reference point, eliminating the need to interact directly with the Oracle Chain.

On the Target Chain, UDF plays a pivotal role in managing delivered data. It enables decentralized applications to access and utilize verified data directly in their logic. It also facilitates verification of data using the VerificationLib which is the smart contract library that handles validating data on target chains. These measures ensure that all signatures are valid, votes are unique, and the data has met consensus thresholds. For numerical feeds, the verification process aggregates the data into a final state, often using statistical methods like medians to derive a reliable result.

Integration with EIB & L2 Solutions

UDF integrates EIB with L2 solutions for scalability, performance, and cost optimization. This approach allows relaying aggregated data snapshots to each target chain. The L2 network is parallelized and synced with EIB to handle specific tasks (aggregator rollups) and offload mainchain overhead while enabling unlimited horizontal scaling.

EIB's robust consensus mechanism (Tendermint BFT) that finalizes data more rapidly than many L1 networks is leveraged by the L2 solutions as a trusted layer to periodically commit their state. This lets the L2 solutions inherit EIB’s security while achieving greater compute bandwidth and lower costs, enabling near real-time data updates.

Additionally, unlike traditional L2 processes, UIP's internal utility networks bypass full block finalization for messages that do not involve value transfers, relying solely on source network finalization to speed up delivery.

In short, UDF leverages the EIB, a specialized blockchain, for orchestrating:

  • Cross-Chain Consensus

  • Validator Set & Finality

  • Performance & Lower Costs

Role of Transmitters & Decentralized Agent Network

A decentralized network of lightweight transmitter nodes retrieves raw data from various sources and cryptographically signs each update before submission to the oracle chain. These signatures collectively form a Byzantine-tolerant proof, ensuring the integrity and validity of the data. Signatures are merged into a final proof, which is used for validation on external blockchains and off-chain applications.

  • Transmitters must stake the native EIB tokens to participate in the network, aligning incentives with honest operation. Staked assets act as a security deposit, misbehavior, downtime, or incorrect data submissions result in slashing penalties. This mechanism prevents Sybil attacks while ensuring that only committed, well-incentivized nodes contribute to UDF’s data integrity.

  • Generate signatures on data updates, contributing to a trust-minimized consensus.

  • Are monitored and rotated, with penalties for downtime or producing inconsistent signatures.

Finalized Data Snapshot

Once finalized, the data snapshot is posted on the EIB/L2 oracle chain, ensuring accuracy through multiple layers of signed votes. The Finalized Data Snap service continuously synchronizes with the oracle chain, providing real-time oracle data for users and push nodes to retrieve validated oracle data efficiently.

The final snapshot is a cryptographically verifiable object that includes:

  • Aggregated Value (e.g., BTC/USD = 100,000)

  • Timestamp

  • Transmitter Signatures

  • Optional Extra Metadata (standard deviation, volume data, etc.)

Summary

UDF supports two primary delivery models, Push and Pull. In the Push Model, updates are actively sent by the Push Publisher (i.e., Push Node) to the target chain, while in the Pull Model, users initiate requests for the latest data snapshots and append verification details to their transactions.

UDF offloads computationally intensive tasks such as aggregation and validation to the Oracle Chain, allowing the system to minimize on-chain costs while ensuring rapid updates. Additionally, a robust verification process guarantees that the data remains tamper-proof throughout its lifecycle, allowing cross-chain deployments without comprising data integrity.

UDF is an essential pillar in infrastructure for modern blockchain ecosystems. It excels in delivering accurate, timely, and secure data to decentralized applications, positioning it as a leading solution for cross-chain data delivery.

Delegating to Validators

This page provides step-by-step instructions on how to delegate tokens to your validators. This is a simple and quick process with our intuitive user interface, see below for more information.

1

Step 1

Navigate to the Entangle Hub and click the ‘Connect Wallet’ button. Approve connecting to the platform and adding Entangle Mainnet to your wallet.

2

Step 2

Click ‘Blockchain’ in the header menu and Blockchain section will open. Here, select the ‘Validators’ tab.

3

Step 3

Select any validator you want to delegate your tokens to and click ‘Delegate’ button next to it. This will open the ‘Delegate’ window.

4

Step 4

Enter the amount of tokens manually or simply use the ‘Max’ button. Please remember that you will need some native tokens for the gas fee.

5

Step 5

Click ‘Delegate’ and sign all transactions. Your delegated tokens take 21 days to unlock, starting from the transaction time.

6

Step 6

Great! You have successfully delegated your tokens. They will be available in your wallet in 21 days. During this period, you will continue to accrue yield. You can manage and track your delegation on the .

Developer Guides

UDF is a modular oracle protocol that allows smart contracts to access both Web2 and Web3 data seamlessly, delivering authenticated, customizable data on-demand. It offers developers the flexibility to choose between push and pull data feeds, optimizing cost-efficiency and performance. UDF standardizes data streaming into a universal format, enabling dApps to easily connect with data sources across any EVM and non-EVM network.

Existing dApps or developers planning to build one requiring an oracle for price data, can integrate our data feeds into your smart contracts. Get started by taking a look at one of our guides.

Token Deployment Types

UTS offers three distinct types of token deployments for manually deployed tokens, each with its own characteristics.

Custom Tokens

  • Can be launched by anyone

  • Not officially registered on the Entangle platform

  • Token and connector contracts can be modified by deployers as needed

  • Offer maximum flexibility but may lack official recognition

Factory Tokens

  • Deployed through Factory contracts

  • In the case of UTS Connectors deployment:

    • Underlying tokens remain owned by third parties

    • Provides a standardized deployment process

Verified Tokens

  • Registered and vetted by Entangle

  • Official recognition on the Entangle platform

  • Increased trust and credibility for token projects

For more detailed information about how to verify your token on Entangle platform please visit or check out the guide.

Check Subscription

In this step-by-step guide we'll go over how to check if a subscription to a data feed is still active using the Universal Data Feeds (UDF) hub. This process is an intuitive and straight forward process, follow the instructions below to get started.

1

Connect Wallet

Navigate to https://udf.entangle.fi/ and click on "Connect Wallet" at the top right to connect your wallet.

2

Navigate to Dashboard

Click on the "Dashboard" tab on the top of the page.

3

Open Your Feeds

Scroll down to "Your Feeds" section. Here you can view;

  • The feed that you are subscribed to

Fetch Data via Pull Model (Subscriptions)

In this section we will guide you on how to implement the Pull Model using the Subscription method.

Examples

This section will help you to set up the environment and get familiar with few examples using UTS Token and Connector.


Accessing Feeds

In this step-by-step guide we'll go over how to connect your wallet and search for feeds to find the one that you'll need using the Universal Data Feeds (UDF) . This process is an intuitive and straight forward process, follow the instructions below to get started.

1

Connect Wallet

Navigate to and click on "Connect Wallet" at the top right to connect your wallet.

Overview

Universal Tokens are cross-chain native tokens secured by UIP. The Universal Token Standard (UTS) enables token developers to launch new or expand existing tokens across all major blockchains through a within a few clicks.

UTS revolutionizes cross-chain management, giving developers the power to effortlessly expand their assets across popular chains while keeping full control of their smart contracts — UTS requires no special permissions or rights. Take your token to the next level with UTS, the ultimate tool to seamlessly scale and control, and unlock the infinite possibilities of the interconnected web.

Features

Oracle Contract & User Interaction

UDF’s oracle contracts provide two distinct interfaces, Pull and Push, designed to deliver flexible data access for dApps. Please refer to the section for implementation details.

The Pull interface enables on-demand verification within user transactions, supporting both Pay-As-You-Go (PAYG) and subscription-based models. The Push interface offers subscribed users seamless access to pre-verified, on-chain data updates.

These interfaces, detailed in the table below, leverage VerificationLib to ensure data integrity and adaptability across diverse use cases.

Interface
Function
Purpose
Use Case

Fee Components

UTS provides a cost-efficient and transparent fee system for cross-chain transactions, ensuring users pay only for the resources required. Its optimized structure minimizes costs while maintaining reliable and secure token transfers.

Gas Fees

Cross-chain transactions require gas fees on both source and destination networks, covering computational tasks like minting, burning, locking, and unlocking. Gas limits dynamically adjust to real-time network conditions to prevent overpayment.

  • Destination Gas Limit (dstGasLimit):

Solana Smart Contracts

This page is under construction and will be available soon. We're exploring Solana connectivity as a possible addition in a future release. We appreciate your patience and encourage you to follow us on to stay updated.

UTS Connector

The UTS Connector is designed to add cross-chain bridging capabilities to your tokens. If you want to add bridging capabilities to an already deployed token, the Connector is the solution. Once deployed, it allows tokens to be locked on one chain and unlocked on another, facilitating the creation or release of UTS tokens. You can use the provided contract as it is or adjust it to suit your needs. To get started, simply deploy the Connector, and you'll be able to bridge tokens seamlessly.

For additional technical details, you can explore the contract on GitHub.

Below are two types of Connectors you can choose from based on your needs:

  • Connector with

Bridging

Bridging an asset is simple process with our streamlined and intuitive interface. This guide will walk you through how to link assets using the Bridge.

1

Navigation

First navigate to the bridge interface via the .

Contract Addresses

All chains have the same addresses

Addresses

Contract name
Address

Undelegating from Validators

This page provides step-by-step instructions on how to undelegate tokens from your validators. This is a simple and quick process with our intuitive user interface, see below for more information.

1

Step 1

Navigate to the and click the ‘Connect Wallet’ button. Approve connecting to the platform and adding Entangle Mainnet to your wallet.

Create a Liquidity Pool

If you want your token to be traded against other assets, you'll need to create a liquidity pool. A liquidity pool is a collection of cryptocurrency tokens locked in a smart contract on a decentralized exchange (DEX). It serves as a reserve, enabling users to exchange tokens directly using the pool's locked tokens without requiring a matching buyer or seller. Alternatively, you can watch the video above for a voiced over walkthrough.

1

Launch Universal Token

To create a liquidity pool, you first need a token. If you don’t already have one, you will need to

Overview

EIB is at the core of Entangle's ecosystem. Built on the Cosmos SDK and powered by the Ethermint framework, this highly customised Layer-1 blockchain is designed to function as a central hub, coordinating cross-chain message processing and transaction validation across networks. It employs Merkle tree structures for efficient and secure data storage and retrieval, ensuring data integrity and optimizing storage for high-volume cross-chain applications.

Explore

Become a Partner

As the ultimate Web3 unification layer, Entangle brings together all blockchains, applications, tokens, and data sources into one seamless ecosystem. It’s built to accelerate scalability and fuel mass adoption, empowering developers and users alike to leverage cutting-edge technology that transcends the limitations of fragmented systems.

We invite everyone to join our growing ecosystem and leverage innovative technology that accelerates scalability and adoption. Please fill up the partnership request here:

Report an Issue

If you encountered any issues during the integration process, or noticed a bug while integrating contracts, we’re here to help — simply submit a request on . Please provide as many details as possible, including any error messages or unexpected behavior you observed. Our team will assist you in identifying the problem and guiding you through a solution.

UTS Router

0x5Ac3F749C209f0fdc9E1869Dcb9d109E75e48c61

UTS Registry

0x481d89337aBcb336bdfA422e85af8aa88919b342

UTS Factory

0x123d82338E00AecB432F526a8aEB9442D48e4412

UTS Deployment Router

0x587Bc1BB463F309c4511c36877825D6ec196f6A6

Chains

  • Arbitrum

  • Mantle

  • Binance Smart Chain

  • xLayer

  • CoreDAO

  • Base

  • Optimism

  • Avalanche

  • Polygon

  • Ethereum

Offers a balance between customization and standardization

GitHub
token verification
social media
Cover

Architecture

Cover

Developer Guides

Cover

Frequently Asked Questions

UDF Oracle

Core system for data aggregation, signature verification, and on-chain publication.

Pull Model

Data-verification method for each user transaction, containing oracle votes.

Push Model

Data publication method where nodes regularly push updated values on-chain.

Transmitters

Decentralized agents that sign and attest to data, forming a security layer for aggregated values.

Entangle Interoperable Blockchain (EIB)

A specialized oracle chain that coordinates data availability, finalization, and bridging logic.

Layer 2 (L2)

Layer 2 rollups that further boost throughput and reduce latency of the EIB.

Finalized Snapshot

A canonical data set aggregated from various sources & attested by transmitters.

VerificationLib

A smart contract library that validates oracle votes for secure data feeds on target chains.

Byzantine Fault Tolerance (BFT)

An algorithim for fault tolerance used by transmitters to sign data updates.

Dashboard

Custom Data Feeds

Fetch Data via Pull Model (PAYG)

Fetch Data via Pull Model (Subscription)

Fetch Data via Push Model

Cover
Cover
Cover
Cover

EVM Smart Contracts

Solana Smart Contracts

Cover
Cover

Initial Setup

UTS Connector

UTS Token

Cover
Cover
Cover

Ideal for dApps with sporadic data needs.

Pull

verifyAsSubscriber()

Confirms the user has an active pull subscription, verifies votes, and returns the aggregated data value without additional protocol fees.

Suited for protocols (e.g. lending) needing frequent, real-time price checks with predictable costs.

Push

getFeedPrice()

Allows subscribed users to read the latest push feed data stored on-chain without verification overhead.

Suited for DEXs or stablecoin issuers requiring continuous price updates for liquidity pools.

Data Endpoints & Omnichain Infrastructure

  • Multiple Chains: Each supported chain has UDF Oracle Push and Pull contract deployments. See the data endpoints page for more information.

  • Push Node Authorization: Authorization mechanisms manage the push nodes that are permitted to submit updates on each chain, ensuring controlled data propagation through access control mechanisms.

  • Cross-Chain: For multi-network deployments, EIB supports two sync methods. In the subscription model, chains listen for finalized updates. In the push model, updates are actively sent when values change or a heartbeat is triggered. Both approaches keep data consistent with minimal delay.

Omnichain Messaging & Cross-Chain Data Propagation

UDF supports seamless omnichain data delivery through two models. In the subscription model, transmitter nodes monitor the Entangle Interoperable Blockchain (EIB) and relay oracle updates to subscribed chains as they’re finalized. This ensures efficient propagation with minimal overhead. In contrast, the push model takes a more active approach. Specialised nodes listen to live oracle emissions from L2, compare them with on-chain values, and trigger updates when deviation thresholds or heartbeat timers are met. Each target chain is updated independently, keeping data in sync and available in real time for multi-chain dApps.

Pull

verifyWithFee()

developer guides

Processes the protocol fee for the PAYG pull model during a transaction, verifies transmitter votes, and returns the aggregated data value.

User-defined maximum gas for the destination network.
  • Destination Gas Price (dstGasPriceInWei): Real-time gas price updated by UTS backend.

  • Native Token Prices: Prices of source and destination native tokens (e.g., ETH, BNB) in USD are tracked for accurate fee estimation.

  • Payload Fees

    Fees for transferring additional data, calculated based on the data size (in bytes) and destination gas price.

    Bridge Transaction Fees

    Protocol fees for managing token transfers, covering operational costs of the Entangle Bridge.

    • Source Network Execution: Gas fees for burning or locking tokens.

    • Destination Network Execution: Gas fees for minting or unlocking tokens.

    • Protocol Fee: A flat fee deducted during the transaction.

    Fee Optimization

    UTS minimizes on-chain workload by performing calculations off-chain. Backend services compute values like dstGasPriceAtCurrentNative and dstPayloadPriceAtCurrentNative before passing them to the contract, reducing unnecessary costs for users.

    codebaseFeeAtCurrentNative = dstGasLimit * dstGasPriceInWei * (dstNativePriceInUSDe18 / curNativePriceInUSDe18)
    codepayloadPriceAtCurrentNative = payloadLength * dstPricePerByteInWei * (dstNativePriceInUSDe18 / curNativePriceInUSDe18)

    Network in which you are receiving the feed on

  • Mode type for the particular feed (Push or Pull)

  • Deviation selected for the feed

  • Status of the feed (If the feed is active or inactive)

  • Expiration date of the feed

  • 2

    Choose Wallet

    Choose which wallet you would like to connect. In this example we will use MetaMask.

    3

    Authorize Wallet Access

    Your wallet will request authorization to connect with UDF. Confirm the connection request to proceed.

    4

    Data Feeds

    Click the "Data Feeds" tab at the top to access the page containing all data feeds.

    5

    Filter Assets by Class

    Click on "All Types" to begin filtering the view for a certain asset type. Alternatively, you can select an asset type from the list. Additionally, you can filter the assets by Top, Trending, Most Viewed, New and Coming Soon.

    6

    Searching Assets

    The search bar is located next to your wallet address. You can open it quickly using the forward slash shortcut button ("/").

    Here you can begin typing the name of the asset you are looking for. If the name matches one in our database it will be shown in the list, like so.

    7

    Ordering Assets

    Click on the third button from the right to open the ordering menu. Here you can order the data feeds using different methods.

    hub
    https://udf.entangle.fi/
    Explore
    self service portal

    Contract Sovereignity

    Deploy, mint, burn, lock, or unlock tokens while retaining full control over your token.

    Logic Customization

    Easily add custom logic and cross-chain messaging to your token.

    Dual Proof of Stake Mechanics

    Transparent, verifiable, and tamper-proof, operating without third parties.

    Gas Management

    Set custom gas limits per blockchain with auto adjusting fees based on network conditions.

    Low Cost Bridging

    Simple and cost effective token bridging. Tokens mint or unlock automatically on the target chain.

    No Liquidity Pools Required

    Tokens move directly cross-chains without locking funds, reducing complexity and costs.

    : If you do not want or cannot provide mint/burn access to the Connector, this option allows you to control the token’s locking and unlocking functions. Use this when you prefer to restrict token minting or burning but still want to enable bridging.
  • Connector with Mint/Burn Mechanism: Choose this option if you're able to provide mint and burn access to the Connector. It allows the Connector to mint and burn tokens during the bridging process.

  • Connector Based on Native Currency: This type of Connector is built over the native currency of a blockchain, using the native token as the underlying asset for bridging.

  • UTSConnector.sol
    Lock/Unlock Mechanism
    2

    Source and Destination

    Choose the source (from) and destination (to) network by clicking the network button. Then choose the token or connector by clicking the asset button. If you are bridging an unverified asset, you will need to paste the UTS Token or Connector address manually.

    3

    Sign

    Sign the bridging transacition and wait until it is completed, it should only take several minutes.

    4

    Finishing

    Once finished, the funds will have been bridged diretly to the address on the destination chain.

    Entangle Hub
    2

    Step 2

    Click ‘Blockchain’ in the header menu and Blockchain section will open. Here, select the ‘Validators’ tab.

    3

    Step 3

    Select the validator for which you want to undelegate your tokens from and click ‘Delegate’ button next to it. This will open the ‘Delegate’ window. Switch to the "Undelegate" tab.

    4

    Step 4

    Enter the amount of tokens manually or just use the “Max” button. Please, remember, that you will need native tokens for the gas fee.

    5

    Step 5

    Click “Undelegate” and sign the transactions.

    6

    Step 6

    Done! You have successfully undelegated your tokens.

    Entangle Hub
    .
    2

    Import

    Ensure that you have imported your token into your wallet. If you're using MetaMask, you can follow their official guide. For other wallets, please refer to their respective documentation for transferring tokens.

    3

    Add Liquidity

    Be sure to copy the token address from the station page to ensure you select the correct token.

    You can now create a liquidity pool to enable seamless exchanges. If you're using , the process is straightforward — follow their guide on . For other DEXs, refer to their respective documentation for instructions on adding liquidity.

    That’s it! You’ve successfully created a liquidity pool on a DEX, allowing your users to exchange tokens seamlessly.

    launch a universal token
    ZenDesk

    User Guides

    The fastest way to start exploring and deploying omnichain tokens is through the UTS portal found via the navigation bar on the Entangle website. Deployment through the UTS portal is referred to as automated deployment.

    Automated deployment with UTS is specifically designed to simplify the expansion of existing tokens across multiple blockchains while providing the ability to launch new universal tokens. Using the intuitive UTS interface developers can effortlessly configure token details — such as name, ticker, total supply, decimals, and bridging mechanisms. Once the setup is verified, the system handles all deployment tasks, including creating contracts and allocating the token supply across the chosen chains. The UTS interface is designed to minimize errors and streamline processes.

    This section provides information on how to launch new tokens, connect existing tokens, and other functionalities related to the UTS infrastructure using the UTS interface.

    Explore

    Video Guides

    For voiced over guides with full walk throughs you can check out our page.

    Manual Deploy

    Developers who require greater control and flexibility can customize their token via smart contracts, a process referred to as manual deployment. It allows direct interaction with the Entangle framework and involves deploying token smart contracts to individual blockchains, requiring developers to define all token parameters, and manage bridging mechanisms programmatically.

    While this approach offers more control, it requires a deeper understanding of blockchain infrastructure and additional effort to ensure consistency and security across networks. Manual deployment is ideal for projects requiring customized token behavior and complete flexibility in management.

    This section provides information on how to create, deploy new tokens, or connect existing tokens to the UTS infrastructure manually.

    Architecture

    If you have any questions or need assistance, please feel free to use our contact form to connect with an expert on our team.

    The Universal Token Standard is built for seamless deployment, management, and cross-chain interoperability of omnichain tokens. Integrated with the Entangle Bridge protocol, UTS enables efficient, secure cross-chain transactions using a flexible framework of smart contracts and mechanisms like mint-and-burn and lock-and-unlock.

    Each token has its own token pool, which simplifies cross-chain transfers by handling the necessary token actions. Token pools act as a secure layer that limits how often tokens can be transferred, adding extra protection. They are set up to either "lock" or "burn" tokens on the source chain and then "unlock" or "mint" them on the destination chain. This results in four possible combinations: Burn and Mint, Lock and Mint, Burn and Unlock, and Lock and Unlock.

    Bridging

    Token bridging is the process of transferring tokens from one blockchain to another, enabling interoperability and seamless interaction across multiple networks. Since blockchains operate independently and cannot directly communicate with one another, token bridging serves as a mechanism to "move" tokens between them.

    UTS simplifies token bridging by integrating with the Entangle Bridge Protocol. This system automates the mint and burn or lock and mint processes, enabling developers to focus on token functionality while ensuring secure and efficient cross-chain transfers. With UTS, bridging is decentralized, trustless, and designed to minimize the complexity typically associated with multi-chain operations. UTS offers two modes, expert mode, and simple mode.

    Token Models

    When transferring tokens there are several different models users can use to handle tokens on source and destination chains. In this section each type of model is explained.

    Burn and Mint

    The burn and mint model maintains token supply consistency by burning tokens on the source chain and minting an equivalent amount on the destination chain. This preserves total supply during cross-chain transfers and supports custom tokenomics.

    Lock and Mint

    In the lock and mint model, tokens are locked on the issuing blockchain, and fully collateralized wrapped tokens are minted on the destination blockchain. These wrapped tokens, with burn-and-mint functionality, enable cross-chain transfers and extended functionality.

    Burn and Unlock

    The burn and unlock model returns tokens to their issuing blockchain by burning them on the non-issuing source chain and releasing an equivalent amount on the issuing destination chain.

    Unlock scheme requires to have enough liquidity on destination side to perform bridge operation, make sure to check this before bridging.

    Lock and Unlock

    The lock-and-unlock model enables cross-chain transfers for non-upgradable tokens by locking tokens on the source chain and releasing an equivalent amount on the destination chain. This method maintains token integrity and requires careful liquidity management to ensure balance across chains.

    Unlock scheme requires to have enough liquidity on destination side to perform bridge operation, make sure to check this before bridging.

    UTS Token

    The UTS Token is designed to be bridgeable by default. Once you create it, you can immediately begin bridging it across networks. You can use the provided implementation as-is or customize it to suit your needs.

    A key feature of the UTSToken is its ability to override the _update function to restrict burning access. For additional technical details, you can explore the UTSToken.sol contract on GitHub.

    In this section, we’ll provide examples of two types of tokens: a simple token and a token that uses cross-chain messages, allowing you to bridge tokens to multiple addresses in a single transaction.

    User Guides

    UDF has an easy to use and intuitive hub for quickly managing all of your data feeds. This section walks you through everything you need to know to start using it. Whether you’re exploring data feeds or managing your existing subscriptions, you’ll find step-by-step guides to help you along the way. We’ve kept things clear and practical so you can focus on building without getting lost in the details.

    Developer Guides

    The Universal Token Standard (UTS) is a framework for deploying and managing omnichain tokens across multiple blockchains. It uses mint-and-burn or lock-and-unlock mechanisms to ensure consistent token supply during cross-chain transfers. Integrated with the Entangle Bridge, UTS supports EVM and non-EVM environments, enabling seamless token management and interoperability across diverse blockchains.

    Explore

    Expand Existing Token

    On chains where token already exists UTS offers a lock-and-unlock bridging mechanism, similar to mint-and-burn but requiring additional liquidity for bridging. This guide will walk you through how to expand existing tokens using UTS.

    1

    Entangle Hub

    First, navigate to UTS via the navigation bar on the Entangle website.

    2

    Token Details

    Enter the address of the tokens that are on different chains which you wish to link. You can select the chain by clicking on the icon. In this example we're using the USDT addresses on BNB and Polgygon.

    Make sure you read and understand the messages before checking them. Once you're ready click the "Import Tokens" button to move on.

    3

    Network Selection

    Now you should decide which networks to deploy on. Here you can choose your prefered bridging mechanism but remember the total supply will remain unchanged since the token already exists. If you don't want to add new chains (as in our example) click "Skip & Deploy".

    After signing the transaction to confirm deployment of the smart contract you be automatically redirected to the next step.

    4

    Finishing

    You have now completed expanding the existing token. However, to bridge tokens that exist on more than one chain, you're required to have liquidity locked into UTS Connectors. To find out how you canc achieve this, you can follow to lock liquidity on connectors for .

    Developer Guides

    This section provides information and guides for developers intending to use Entangle's Interoperable Blockchain (EIB). If you have any questions or need assistance, please feel free to use our contact form to connect with an expert on our team.

    Validators

    Each transaction processed on the network requires thorough validation to ensure compliance with established rules and protocols. Validators are responsible for verifying these transactions, ensuring that all operations are accurately checked, recorded, and aligned with the network’s governing principles.

    Staking and Voting Power

    Validators use the native token, to participate in securing the network. Validators stake the native token to gain voting power, with greater stakes or delegated tokens enhancing their influence over the network's security and consensus. This staking mechanism ensures that validators have a vested interest in maintaining the network's security.

    Security and Monitoring

    Validators actively monitor the network for signs of malicious activity. Their vigilance is crucial in preventing attacks, double-spending, or other behaviors that could compromise the blockchain's security.

    Rewards and Incentives

    Validators are incentivized through rewards, which come from gas fees generated by the transactions they validate. This reward mechanism is designed to acknowledge and compensate validators for their crucial contributions and encouraging active participation.

    Slashing and Penalties

    Validators are held accountable through a robust slashing mechanism that discourages malicious behavior and ensures network security

    1. If a validator signs two conflicting blocks, a percentage of their tokens are slashed.

    2. Validators that sign fewer than 50 of the last 100 blocks will have a portion of their staked tokens slashed and be temporarily "jailed" for a set period.

    Explore

    Launch Universal Token

    Creating a new token is a simple process with our streamlined and intuitive interface. This guide will walk you through how to create a new token using UTS. Alternatively, you can watch the video above for a voiced over walkthrough.

    1

    Navigation

    First, navigate to UTS via the navigation bar on the Entangle website.

    2

    Token Details

    Total supply is the summarised initial supply on all chains; for more information about the mechanism, see the page.

    Fill in all of the necessary information (Ticker, Name, Total Supply, Mechanism, Decimals, Contract Address) for the token you're launching, and then click "Preview Setup" to proceed to the next step.

    The button may be replaced with a connect your wallet button if you have not connected it yet. In which case please connect it first, then the preview button will become available.

    3

    Preview

    On this page you should double check all of the details you entered to make sure it is correct before moving on. When you're ready click "Confirm Setup" to proceed to the next step.

    4

    Network Selection

    Now you should decide networks for deployment and how to initially split the total supply between chosen blockchains. You can decide to split it evenly, or define a custom value. If you decide to define a custom value, make sure that the total value of tokens on each chain equals the initial supply. The total deployment fee will be automatically updated and displayed in the native currency of the connected blockchain network.

    When you're ready click "Setup & Deploy" and sign the transaction to confirm deployment of the smart contract. After a few seconds the deployment will be completed and you will be automatically redirected to the next step.

    5

    Finishing

    After succesful deployment you will see the newly created cluster of smart contracts for the token on the station page. That's it! Now copy the token address and go to Entangle bridge page to !

    Multiple Chains

    UTS supports launching to multiples chains. The process is similar to the steps described above, for a full breakdown and walk through you can watch the video below.

    Push Model

    Entangle's Push Model delivers continuous, automated updates for critical data, such as prices and asset values, across multiple blockchains. These updates are delivered periodically, making them ideal for scenarios requiring data at set intervals or infrequently, without the need for user requests. This is particularly useful for applications like monitoring dashboards or dApps that display market prices or feed metrics, ensuring optimal performance without user-initiated transactions.

    The Push Model transmits verified information across blockchains when specified deviations occur and at set heartbeat intervals. All updates undergo a secure, consensus-driven verification process before being published on-chain, ensuring data accuracy and security.

    Scheduled or Triggered Updates

    UDF push nodes post the current aggregated feed to a target chain at given price deviations of 0.25%, 0.5%, 1%, 2.5%, or 5% depending on the deviation parameter selected by users, or based on a predefined heartbeat of 24 hours to guarantee sufficient data freshness even when price variations are minimal.

    This means users with stricter update frequencies bear a proportionally higher cost, increasing a user's cost share. This ensures that users requiring frequent updates pay more, while those with wider deviation tolerances contribute adequately less, maintaining fairness and economic efficiency.

    Single On-Chain Storage

    The UDF push oracle contract holds the verified value so that authorized users’ dApps can read it without paying additional verification overhead. This is managed by the PushMarketplace contract, and whitelisted addresses can read via the getFeedPrice function.

    Fee Model

    Subscribed users can share the cost of running the same feed which guarantees cost efficiency for users. As more consumers subscribe to a feed, the cost per user decreases, making the model more economical at scale. Consider checking out our for indepth details on the cost sharing formula.

    UDF charges a small percentage on deposits to the push marketplace contract. The push oracle updates cost is shared across subscribed readers, making it cheaper for the UDF push oracle user base wanting continuous access.

    Summary

    • Gas Efficiency for Consumers: Price reads are restricted to subscribed users and data updates are shared across multiple users, reducing individual verification costs.

    • Cost Efficiency for Consumers: Cost sharing mechanisms amongst subscribed users makes subscriptions cost efficient.

    • Slight Delay in Data Freshness: Updates happen periodically (price deviation triggers or time-based heartbeats).

    • Best for Continuous Data Access

    Subscribe to a Data Feed

    In this step-by-step guide we'll go over how to subscribe to a data feed using the Universal Data Feeds (UDF) . This process is an intuitive and straight forward process, follow the instructions below to get started.

    1

    Connect Wallet

    Navigate to and click on "Connect Wallet" at the top right to connect your wallet.

    Fees Calculation & Gas Estimation Logic

    Fee calculation and gas estimation help you understand the costs involved in cross-chain transactions and deployments. These processes account for things like gas limits, payload size, and currency prices on the source and destination chains to ensure your operations run smoothly. Entangle provides to estimate fees for bridging and deploying tokens, making it easier to plan and execute your transactions.

    This page explains the logic for calculating transaction fees and estimating gas costs for cross-chain operations, including base fees, payload costs, and optimization strategies handled off-chain by the backend.

    Base Transaction Fee

    Transfer Liquidity to Connector

    Caution, the liquidity you transfer to the UTS Connctor is non-refundable.

    Adding liquidity to the UTS connector is simple, this guide will explain how it's done.

    1

    Supported Accounts

    Entangle supports two type of accounts EVM and Bech32. To navigate with the Bech32 address (with ent prefix) you can interact with the CLI commands outlined below.

    Converting Formats

    You can convert between the HEX and Bech32 format like so:

    Initial Setup

    Before starting any of the examples, you’ll need to set up your environment. We recommend using the development environment. If you choose to use it, please follow the .

    Once your development environment is set up, install the core dependencies using the following commands:

    After initializing an empty Hardhat project and installing dependencies, you are ready to write your token or connector. Next, try creating a or a .


    Explore

    Uniswap
    adding liquidity to Uniswap v3
    YouTube
    Cover

    Launch Universal Token

    Cover

    Create a Liquidity Pool

    Cover

    Expand Existing Token

    Cover

    Transfer Liquidity to Connector

    Cover

    Bridging

    Cover

    How to Change Validators

    Cover

    How to Deploy Token on 3 Chains

    Cover

    How to Launch on a Single Chain

    Cover

    How to Create Liquidity Pool

    Cover

    How to Expand a Token to Avalanche

    Cover

    How to Expand a Token to Sonic

    Cover

    How to Expand a Token to Base

    Cover

    How to Expand a Token to Arbitrum

    Cover

    How to Expand a Token to BNB Chain

    Cover

    Set up a Validator Node

    Cover

    Delegating to Validators

    Cover

    Undelegating from Validators

    Cover

    Supported Accounts

    Mint & Burn Connector Scheme

    Lock & Unlock Connector Scheme

    Connector Over Native Currency

    Cover
    Cover
    Cover

    Token Deployment Types

    Create a Custom Token

    Factory Blueprint Deployment

    Examples

    Cover
    Cover
    Cover
    Cover

    Simple Token

    Token with Messages

    Cover
    Cover

    Accessing Feeds

    Subscribe to a Data Feed

    Check Subscription

    Manage Subscription

    Renew Subscription

    Cover
    Cover
    Cover
    Cover
    Cover

    Manual Deploy

    Bridge SDK

    Token Verification

    Fees Calculation & Gas Estimation Logic

    Estimations

    Cover
    Cover
    Cover
    Cover
    Cover
    : Suited for DEXs, stablecoin issuers, and liquidity protocols needing steady price updates.
    whitepaper
    Hardhat
    Hardhat setup guide
    npm
    simple token
    lock and unlock connector
    Cover

    Mint & Burn Connector Scheme

    Cover

    Lock & Unlock Connector Scheme

    Cover

    Connector Over Native Currency

    Cover

    Simple Token

    Cover

    Token with Crosschain Messages

    dstGasLimit: User-defined gas limit to be used on the destination network during the redeem transaction.
  • dstGasPriceInWei: Stored in the contract and updated by the backend; represents the gas price on the destination network based on chainId.

  • dstNativePriceInUSDe18: Stored in the contract and updated by the backend; indicates the USD price of the native currency on the destination network, depending on chainId.

  • curNativePriceInUSDe18: Stored in the contract and updated by the backend; reflects the USD price of the native currency on the source network.

  • Base Fee Calculation

    To calculate the base fee in terms of the current native currency:

    This formula determines the amount of native currency required on the source network to execute the transaction (excluding payload), which is then compared to msg.value.

    Payload Cost Calculation

    To calculate the cost related to the payload, use these parameters:

    • payloadLength: User-defined length of the payload in bytes.

    • dstPricePerByteInWei: Cost per byte of payload in the native currency on the destination network.

    • dstNativePriceInUSDe18: Represents the USD price of the native currency on the destination network.

    • curNativePriceInUSDe18: Represents the USD price of the native currency on the source network.

    The payload cost calculation in the current native currency is:

    This formula calculates how much native currency is needed on the source network to cover the payload cost, which is also compared to msg.value.

    Final Calculation

    To determine the total required amount, sum baseFeeAtCurrentNative and payloadPriceAtCurrentNative, then compare to msg.value. Note that users may incur small losses if dstGasLimit exceeds the actual gas consumed.

    Optimization of Calculations

    To optimize the process, the backend handles calculations off-chain to minimize contract updates across different destination networks:

    • dstGasPriceInWei

    • dstPricePerByteInWei

    • dstNativePriceInUSDe18

    • curNativePriceInUSDe18

    Using these parameters, the backend performs these calculations:

    • Calculate dstGasPriceAtCurrentNative:

    • Calculate dstPayloadPriceAtCurrentNative:

    The backend then sends only the dstGasPriceAtCurrentNative value to the contract. Optionally, it can also send dstPayloadPriceAtCurrentNative if a dynamic price per byte is preferred; otherwise, a static price is more efficient.

    APIs
    Adding Keys

    Importing Keys

    Exporting Private Keys

    Querying Account Details

    Address Navigation

    To navigate with HEX addresses you can use Metamask or other EVM wallets, with following parameters.

    Entangle Mainnet

    Category
    Value

    Network Name

    Entangle Mainnet

    Default RPC URL

    https://json-rpc.entangle.fi/

    Chain ID

    33033

    Currency Symbol

    NTGL

    Entangle Testnet

    Category
    Value

    Network Name

    Entangle Testnet

    Default RPC URL

    https://34.174.174.102:8545/

    Chain ID

    33133

    Currency Symbol

    NTGL

    npm i @entangle-labs/uts-contracts
    npm i @openzeppelin/contracts
    dstGasPriceAtCurrentNative = dstGasPriceInWei * dstNativePriceInUSDe18 / curNativePriceInUSDe18
    dstPayloadPriceAtCurrentNative = dstPricePerByteInWei * dstNativePriceInUSDe18 / curNativePriceInUSDe18
    baseFeeAtCurrentNative = dstGasLimit * dstGasPriceInWei * dstNativePriceInUSDe18 / curNativePriceInUSDe18
    payloadPriceAtCurrentNative = payloadLength * dstPricePerByteInWei * dstNativePriceInUSDe18 / curNativePriceInUSDe18
    entangled debug addr <address>
    entangled keys add <key_name> --keyring-backend file
    entangled keys add <key_name> --keyring-backend file --recover
    entangled keys unsafe-export-eth-key <key_name> --keyring-backend file
    entangled q account <address> 
    architecture
    perform your first bridge
    2

    Choose Feed

    Click on the feed that you wish to subscribe to.

    3

    Select Destination Network

    Select the "Network" that you wish to receive your data feed on.

    4

    Choose Mode

    Learn more about the Push and Pull data delivery methods here.

    Choose between "Push" or "Pull" mode.

    • Push delivers updates proactively to the blockchain, ensuring automated data availability.

    • Pull allows authorized addresses to fetch update on-demand during transactions, ensuring the latest data is used at the point of need.

    5

    Pull Mode

    If you chose Push Mode skip to the next step.

    For "Pull mode" choose the desired duration. Your subscription will remain active for the selected duration extension and will end on the expiry date unless extended beforehand by depositing additional funds, allowing you to renew it seamlessly.

    You can deposit any amount, as long as it meets the minimum required. The app will automatically calculate your subscription period based on the amount you choose to deposit.

    6

    Push Mode

    If you chose Pull Mode you can skip this step.

    For "Push mode" select the desired deviation. This is the percentage change in value required to trigger a new update, ensuring updates are only made when meaningful updates occur.

    7

    Payment

    Enter the amount that you wish to pay. The duration is estimated based on current gas costs and asset volatility. Sudden gas spikes or high volatility can shorten the subscription period.

    8

    Address

    Specify the addresses that will have permission to access and read price updates directly from the oracle contract.

    9

    Subscribe and Finish

    Click on the "Subscribe" button to finalize the subscription.

    hub
    https://udf.entangle.fi/
    Import

    Import your underlying token for UTS Connector in Metamask. You may follow the official guide to import any token.

    2

    Transfer

    Copy the connector address from the station page to ensure that you are transferring tokens to the correct address.

    Now you need to ensure you supply liquidity to all connectors to allow bridging in every direction.

    For those using Metamask, transferring is simple, follow their indepth . If you're using another wallet please refer to its documentation for transfering tokens.

    That's it! Now the connector has liquidity and is ready to be unlocked in bridging transactions. Go to Entangle bridge page to perform your first bridge!

    Architecture

    Fee Components

    Developer Guides

    User Guides

    Contract Addresses

    Frequently Asked Questions

    Cover
    Cover
    Cover
    Cover
    Cover
    Cover
    this guide
    bridging
    Cover

    Bridge SDK Developer Guide

    Cover

    Bridging User Guide

    Custom Data Feeds

    If you're looking for a data type that isn't currently supported but would like it to be, feel free to contact us, and we can discuss implementing it.

    Custom data in data feeds refers to user-defined information that is integrated into a data feed to meet the specific needs of a dApp or smart contract. This enables developers to pull tailored data from both on-chain and off-chain sources, facilitating more accurate and relevant decision-making and operations. With UDF, users can easily expand the data available to their applications by incorporating new data types into the Entangle UDF infrastructure.


    When Is Custom Data Needed?

    • Integrating New Crypto Assets: Add new cryptocurrency price feeds to ensure decentralized exchanges, lending platforms, or wallets always have the latest market prices.

    • Real-World Asset (RWA) Integration: Introduce real-world assets like commodities, real estate, or physical goods into the decentralized ecosystem, enabling their tokenization and trading.

    • Proof of Reserves Integration: Add external data feeds to verify asset reserves, providing transparency and confidence in the backing of digital assets or financial platforms.


    Requesting New Data Types

    To integrate new data into UDF, and provide the following information:

    • Initial Data with Examples: Share real sample data that will be processed during the integration.

    • Data Processing Requirements: Outline any necessary transformations or formatting for the data to be delivered on-chain.

    • Update Frequency Suggestions: Recommend the desired update frequency to tailor the integration to the protocol’s needs.


    Integration Process

    This section outlines the process of integrating a new data feed into UDF. The default integration flow ensures smooth onboarding of new data sources and utilizes UDF’s capabilities for fetching, parsing, and distributing data on-chain.

    1

    Define REST URL Template

    The Rest URL template defines how data is fetched from external sources. You will need to create a URL template that points to the endpoint of the data provider. The template uses Go text syntax, with placeholders such as DataKey and SourceID. Example for Binance API:

    This URL template is inserted into the configuration file, allowing Entangle's backend to fetch the necessary data.

    Connector Over Native Currency

    The main idea of this connector is to have a possibility to bridge native currency between chains.

    Create contract with name UTSConnectorNativeShowcase .

    You need to import:

    UTSBase is our main contract that should be inherited by any Token or Connector.

    In this implementation we also used Ownable

    We are starting with defining contract and dependencies. As access control we are choosing Ownable.

    Also we need to define NATIVE_TRANSFER_GAS_LIMIT some errors and address converter library.

    Then we need do define constructor. Since it is connector, we need _nativeCurrencyDecimals( since our asset for bridging is native currency, we can provide a null address, but meaningful decimals value still required). We need also setup _router address, that can be found .

    _allowedChainIds are simply whitelist of chain id's, where you are allowing to bridge tokens.

    _chainConfigs is array of settings responsible for bridge settings. We described this config .

    In constructor we need to call __UTSBase_init function to initialize UTS Base contract. Also we need to set router and chain config.

    _nativeTransferGasLimit serves for defend your and your users gas to avoid attack vector over too complicated or useless receive function at the receiver address.

    We can skip setting router and chain configs in constructor, but before starting bridging we need to do it with relevant public functions.

    Lets start with defining 2 view functions that will help us to track balance of this connector and also decimals of native currency and also receive function that will allow our connector to receive native currency.

    After this step we need to override 3 functions: _mintTo, _burnFrom and _authorizeCall.

    Since this connector is working via lock/unlock scheme, you need to fulfill it, to start bridging to this connector. This can be done or via just transferring native to connector, or you can initially bridge your native from this connector to any chain where you have UTS token or connector with non zero balance and initial funds will be locked in connector.

    In the outbounding transaction we need to ensure that msg.value we are going to accept is greater than amount, to ensure that we received enough native currency.

    In the inbounding transaction we need to ensure that we have enough native currency on connector balance and as a transfer method we will use raw call, since we want also provide restricted gas value.

    Don't forget to check success.

    Last but not least we need to override one our internal function that is responsible for sending request to router for bridge proposal. Here we need modify value of this message. Main fee asset in our protocol is native currency, and we need to transfer some fee to router to pay fee. If we will leave as it is, it will transfer whole msg.value to router. It is incorrect logic in this case, so we need to substruct our amount that will be locked on the connector balance.

    So, our contract is ready, now it can be deployed on networks and we can start bridging tokens between each chain.

    You can find full code

    Lock & Unlock Connector Scheme

    Create contract with name UTSConnectorLockUnlockShowcase .

    You need to import:

    UTSBase is our main contract that should be inherited by any Token or Connector.

    In this implementation we also used Ownable, Pausable and IERC20Metadata

    We are starting with defining contract and dependencies. As access control we are choosing Ownable.

    Then we need do define constructor. Since it is connector, we need underlyingToken_(the token that will be bridged through UTS protocol). We need also setup _router address, that can be found .

    _allowedChainIds are simply whitelist of chain id's, where you are allowing to bridge tokens.

    _chainConfigs is array of settings responsible for bridge settings. We described this config .

    In constructor we need to call __UTSBase_init function to initialize UTS Base contract. Also we need to set router and chain config.

    We can skip setting router and chain configs in constructor, but before starting bridging we need to do it with relevant public functions.

    After this step we need to override 3 functions: _mintTo, _burnFrom and _authorizeCall.

    Since this connector is working via lock/unlock scheme, you need to fulfill it, to start bridging to this connector. This can be done or via just transferring underlying token to connector, or you can initially bridge your tokens from this connector to any chain where you have uts token or connector with non zero balance and initial money will be locked in connector.

    So, here is very simple logic, in the outbounding bridge transaction, we need to transfer tokens from spender to connector address, in the inbounding redeem transaction, we need to transfer tokens from connector to receiver to address.

    Also we will implement one more function: getter for underlying token decimals.

    Also we need to use SafeERC20 library by OpenZeppelin.

    So, our contract is ready, now it can be deployed on networks and we can start bridging tokens between each chain.

    You can find full code

    Mint & Burn Connector Scheme

    Create contract with name UTSConnectorMintBurnShowcase .

    You need to import:

    UTSBase is our main contract that should be inherited by any Token or Connector.

    In this implementation we also used Ownable, Pausable and IERC20Metadata

    We are starting with defining contract and dependencies. As access control we are choosing Ownable and we also want make this contract as Pausable, because in bridge flow it is also nice to have an option to pause all interactions to make some changes for example.

    Then we need do define constructor. Since it is connector, we need underlyingToken_(the token that will be bridged through UTS protocol). We need also setup _router address, that can be found .

    _allowedChainIds are simply whitelist of chain id's, where you are allowing to bridge tokens.

    _chainConfigs is array of settings responsible for bridge settings. We described this config .

    In constructor we need to call __UTSBase_init function to initialize UTS Base contract. Also we need to set router and chain config.

    We can skip setting router and chain configs in constructor, but before starting bridging we need to do it with relevant public functions.

    After this step we need to override 3 functions: _mintTo, _burnFrom and _authorizeCall. We need to do it, because this connector is mint/burn, so, internal logic should be of main bridging function should be done via mint/burn of underlying token.

    Of course to implement mint/burn logic you need to grant mintable/burnable roles on your underlying token to Connector contract.

    So, here is very simple logic, in the inbounding redeem transaction, we need to mint tokens, in the outbounding bridge transaction, we need burn tokens.

    Also we will implement 3 more functions to controll pause state and getter for underlying token decimals.

    Also we need extended ERC20 interface to call mint and burn functions. In this example, we use standard mint and burnFrom token functions, but you can use any interface and logic supported by your underlyingToken contract.

    So, our contract is ready, now it can be deployed on networks and we can start bridging tokens between each chain.

    You can find full code

    Token Verification

    Token verification is an optional process that enhances the visibility and usability of your token in Entangle’s bridge and dApp ecosystem. By verifying your token, it becomes searchable by name rather than by address, improving user accessibility and integration within the platform.

    After deploying your token and setting up its cluster, you can use the bridge and associated dApps. By default, users can search for your token using its contract address. Token verification ensures your token is indexed, allowing users to find it quickly by name in search fields.

    After deploying and setting up your cluster you can start bridging and using our dApp for this purpose, but by default, you can find your token using address only. This guide will help you to verify your token and after verification, we will index your token and you will have a possibility just to write the name of your token in the search field.

    Verification Steps

    1

    Prepare Your Repository

    • Fork the token verification .

    • Create a project folder in the projects directory and add a CLUSTER_INFO.json file based on the provided .

    2

    Expand Existing Clusters

    • If you’ve already verified your token but added new deployments to its cluster, create a new pull request mentioning the expansion and update the CLUSTER_INFO.json.

    3

    Submit Your Request

    • Fill out the required details in the repository’s README and corresponding .

    • Submit a pull request using the provided PULL_REQUEST_TEMPLATE.md .

    Notes

    Instructions for Expanding Verified Tokens in Cluster Updates After Token Verification

    If your token is already verified but you've expanded your cluster, you can create a new pull request. Please mention that your token is already verified and you only need to expand it. Additionally, ensure that you include the updated information in the CLUSTER_INFO.json file as part of the pull request.

    Specifying Entity Types in Deployment Information

    In the deployment information's type field, there are two possible entities: Token and Connector.

    If the entity is a token, specify Token; if it is a connector, specify Connector.

    Guidelines for Setting the DeployedViaFactory Field in Cluster Info

    In the cluster information, there is a field called DeployedViaFactory. If you deployed your tokens or connectors through our factory (either manually or via the dApp), set this field to true. Otherwise, set it to false. Deployments using our predefined blueprints via the factory will result in a faster verification process.

    Internal Requirements for Verified Tokens: Ensuring User Security

    Our internal requirements for verified tokens are straightforward: we reject scam tokens and any other tokens that pose a risk to regular users' funds.

    Chain ID Configuration for Solana and TON Deployments

    As we prepare to expand to Solana and TON, please use the following chainId values for deployments:

    • For Solana: 11100000000000000501

    Simple Token

    Create contract with name UTSTokenShowcase .

    You need to import:

    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    import "@entangle-labs/uts-contracts/contracts/ERC20/UTSBase";

    We are starting with defining contract and dependencies. As access control we are choosing Ownable and also since it is UTS Token we need to import ERC20 implementation, here we are using one by OpenZeppelin.

    UTSBase is our main contract that should be inherited by any Token or Connector.

    In this implementation we also used Ownable and ERC20

    Then we need do define constructor. Since it is Token, we don't need a lot, just general UTS settings and ERC20 metadata.

    We need setup _router address, that can be found .

    _allowedChainIds are simply whitelist of chain id's, where you are allowing to bridge tokens.

    _chainConfigs is array of settings responsible for bridge settings. We described this config .

    In constructor we need to call __UTSBase_init function to initialize UTS Base contract. Also we need to set router and chain config.

    We can skip setting router and chain configs in constructor, but before starting bridging we need to do it with relevant public functions.

    After this step we need to override 3 functions: _mintTo, _burnFrom and _authorizeCall.

    So, here is very simple logic, in the outbounding bridge transaction, we need to burn tokens from from address (do not forget about ERC20 allowance check), in the inbounding redeem transaction, we need to mint tokens to receiver to address.

    So, our contract is ready, now it can be deployed on networks and we can start bridging tokens between each chain.

    You can find full code

    Create a Custom Token

    You can extend the base implementation of the UTS Token or UTS Connector to meet your specific requirements. To implement your custom token, you’ll need to follow a few basic guidelines.

    1

    Install Entangle Package

    Start by installing the Entangle Labs UTS Contract package using NPM.

    2

    Estimations

    We offer several functions to help you estimate costs, including bridging and deployment fees.

    Bridge Costs

    To estimate bridge fees and minimum gas limits, we provide the estimateBridgeFee function. See below for more information.

    Name
    Meaning

    Renew Subscription

    Users can renew their previously subscribed data feeds without the need to set the parameters again. In this step-by-step guide we'll go over how to renew your subscriptions using the Universal Data Feeds (UDF) . This process is an intuitive and straight forward process, follow the instructions below to get started.

    Users can renew their inactive subscriptions from the "" section or from the "" section of the dashboard.

    Notification Section

    1

    Bridge SDK

    This provides everything you need to integrate the Web3 Bridge into your frontend application. The bridge supports multiple chains and tokens, offering seamless interoperability for Universal Token Standard (UTS).

    Refer to this for an example bridge project.

    Setup

    After cloning the

    Architecture

    The Entangle Interoperable Blockchain consists of 3 Layers:

    • Application Layer

    • Modules Layer

    • Tendermint Consensus Layer

    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@entangle-labs/uts-contracts/contracts/ERC20/UTSBase";
    contract UTSConnectorNativeShowcase is UTSBase, Ownable {}
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
    import "@entangle-labs/uts-contracts/contracts/ERC20/UTSBase";
    contract UTSConnectorLockUnlockShowcase is UTSBase, Ownable {}
    constructor(
        address underlyingToken_,
        address _router,  
        uint256[] memory _allowedChainIds,
        ChainConfig[] memory _chainConfigs
    ) Ownable(msg.sender) {
        __UTSBase_init(underlyingToken_, IERC20Metadata(underlyingToken_).decimals());
    
        _setRouter(_router);
        _setChainConfig(_allowedChainIds, _chainConfigs);
    }
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/Pausable.sol";
    import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
    import "@entangle-labs/uts-contracts/contracts/ERC20/UTSBase";
    contract UTSConnectorMintBurnShowcase is UTSBase, Ownable, Pausable {}
    constructor(
        address underlyingToken_,
        address _router,  
        uint256[] memory _allowedChainIds,
        ChainConfig[] memory _chainConfigs
    ) Ownable(msg.sender) {
        __UTSBase_init(underlyingToken_, IERC20Metadata(underlyingToken_).decimals());
    
        _setRouter(_router);
        _setChainConfig(_allowedChainIds, _chainConfigs);
    }
    contract UTSTokenShowcase is UTSBase, Ownable, ERC20 {}
    constructor(
        address _router,  
        uint256[] memory _allowedChainIds,
        ChainConfig[] memory _chainConfigs
    ) Ownable(msg.sender) ERC20("UTS Token Showcase", "UTSTS") {
        __UTSBase_init(address(this), decimals());
    
        _setRouter(_router);
        _setChainConfig(_allowedChainIds, _chainConfigs);
    
        _mint(msg.sender, 1_000_000 * 10 ** decimals());
    }
    https://entangle.zendesk.com/hc/en-us/requests/new?ticket_form_id=17464570919965entangle.zendesk.com
    2

    Set Up Parsing Pipelines

    In the configuration file, set up pipelines to parse data from the response JSON. Below is an example JSON response structure:

    • Pipeline for Price: asset.price

    • Pipeline for Timestamp: asset.timestamp

    • Pipeline for Volume: asset.volume

    These pipelines should be defined using GJSON syntax to extract the required fields.

    3

    Configure the System

    The next step is to implement both the URL template and parsing pipelines in the YAML configuration file. This connects the data feed with Entangle UDF.

    Example configuration snippet:

    4

    Fetch Data

    To retrieve data updates, use the Finalized Data API. For example, to fetch the BTC/USD price feed, execute the following curl command:

    Below is a sample response containing publisher votes along with their signatures, and data encoded as bytes in the update_call_data property which is ready to be used on-chain.

    5

    Finishing

    Monitor and Update

    Ongoing monitoring ensures that the integration functions correctly. Periodically review the configuration and update it as needed to accommodate changes in the data provider's API or Entangle’s system.

    Once you have fetched the data, use the PushMarketplaceor PullMarketplace smart contract to verify the updates on-chain.

    contact us
    here
    here
    here
    here
    here
    here
    here
    here
    here
    For TON:
    100004503599627370496
    repository
    template
    Google form
    file
    here
    here
    here
    {
      "asset": {
        "price": 1000000000000000000,
        "timestamp": 1721636387,
        "volume": 10000000000
      }
    }
    urlTemplate: "https://api.binance.com/api/v3/avgPrice?symbol={{.DataKey}}"
    pipelines:
      - value: "asset.price"
      - timestamp: "asset.timestamp"
      - volume: "asset.volume"
    curl https://udfsnap.ent-dx.com/last_votes?feedKeys=BTC/USD
    {
      "update_call_data": "0x..",
      "feeds": [
        {
          "feed_key": "BTC/USD",
          "votes": [
            {
              "Value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS4fbe+zAAA=",
              "Timestamp": 1737093395,
              "Signature": {
                "R": "0xfb2e89fb52f1d832d5437f4b773c0f67749b914b25c592af9cbc8ffe58e9e928",
                "S": "0x3c7e717a67b8a0c072f0271f35f3994c865c12b930f20b57149b623cade43d43",
                "V": 27
              }
            },
            {
              "Value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS4fbe+zAAA=",
              "Timestamp": 1737093402,
              "Signature": {
                "R": "0xe6a1448feac17a219c63a426f978cd395f8be55a74ebc717a88385033c7c5432",
                "S": "0x1a16ba5138e5293b03c093097c8564c55a0f054537a6c665d3b4bc9cf716d46f",
                "V": 28
              }
            },
            {
              "Value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS4fbe+zAAA=",
              "Timestamp": 1737093400,
              "Signature": {
                "R": "0x8308dc0d3b5a32a12374fbc8a2852cb14af4e31cc015b4d463e4cfb41d5aa469",
                "S": "0x12d5746c9499e7dc5edbbc436f696478ab4ad5a96247fb357d3d0c418769778d",
                "V": 28
              }
            }
          ]
        }
      ]
    }
    https://api.binance.com/api/v3/avgPrice?symbol={{.DataKey}}
    using AddressConverter for address;
    
    uint256 public immutable NATIVE_TRANSFER_GAS_LIMIT;
    
    error UTSConnectorNativeShowcase__E0();
    
    error UTSConnectorNativeShowcase__E1();
    
    error UTSConnectorNativeShowcase__E2(bytes);
    constructor(
        address _router,  
        uint256[] memory _allowedChainIds,
        ChainConfig[] memory _chainConfigs,
        uint8 _nativeCurrencyDecimals,
        uint256 _nativeTransferGasLimit
    ) Ownable(msg.sender) {
        __UTSBase_init(address(0), _nativeCurrencyDecimals);
    
        _setRouter(_router);
        _setChainConfig(_allowedChainIds, _chainConfigs);
    
        NATIVE_TRANSFER_GAS_LIMIT = _nativeTransferGasLimit;
    }
    receive() external payable {}
    
    function underlyingDecimals() external view returns(uint8) {
        return _decimals;
    }
    
    function underlyingBalance() external view returns(uint256) {
        return address(this).balance;
    }
    function _authorizeCall() internal override onlyOwner() {}
    function _burnFrom(
        address /* spender */,
        address /* from */, 
        bytes memory /* to */, 
        uint256 amount, 
        uint256 /* dstChainId */, 
        bytes memory /* customPayload */
    ) internal override returns(uint256 bridgedNativeAmount) {
        if (amount >= msg.value) revert UTSConnectorNativeShowcase__E0();
    
        return amount;
    }
    function _mintTo(
        address to,
        uint256 amount,
        bytes memory /* customPayload */,
        Origin memory /* origin */
    ) internal override returns(uint256 receivedNativeAmount) {
        if (amount > address(this).balance) revert UTSConnectorNativeShowcase__E1();
    
        (bool _success, bytes memory _response) = to.call{value: amount, gas: NATIVE_TRANSFER_GAS_LIMIT}("");
    
        if (!_success) revert UTSConnectorNativeShowcase__E2(_response);
    
        return amount;
    }
    function _sendRequest(
        uint256 payment,
        bytes memory dstToken,
        bytes memory to,
        uint256 amount,
        uint8 srcDecimals,
        uint256 dstChainId,
        uint64 dstGasLimit,
        bytes memory customPayload,
        bytes memory protocolPayload
    ) internal override returns(bool success) {
        return IUTSRouter(router()).bridge{value: payment - amount}( 
            dstToken,
            msg.sender.toBytes(),
            to,
            amount,
            srcDecimals,
            dstChainId,
            dstGasLimit,
            customPayload,
            protocolPayload
        );
    }
    function _authorizeCall() internal override onlyOwner() {}
    function _burnFrom(
        address spender,
        address /* from */, 
        bytes memory /* to */, 
        uint256 amount, 
        uint256 /* dstChainId */, 
        bytes memory /* customPayload */
    ) internal override returns(uint256 bridgedAmount) {
        IERC20(_underlyingToken).safeTransferFrom(spender, address(this), amount);
    
        return amount;
    }
    function _mintTo(    
        address to,
        uint256 amount,
        bytes memory /* customPayload */,
        Origin memory /* origin */
    ) internal override returns(uint256 receivedAmount) {
        IERC20(_underlyingToken).safeTransfer(to, amount);
    
        return amount;
    }
    function underlyingDecimals() external view returns(uint8) {
        return _decimals;
    }
    
    import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    
    using SafeERC20 for IERC20;
    function _authorizeCall() internal override onlyOwner() {}
    function _burnFrom(
        address spender,
        address /* from */, 
        bytes memory /* to */, 
        uint256 amount, 
        uint256 /* dstChainId */, 
        bytes memory /* customPayload */
    ) internal override whenNotPaused() returns(uint256 bridgedAmount) {
        IERC20Extended(_underlyingToken).burnFrom(spender, amount);
    
        return amount;
    }
    function _mintTo(
        address to,
        uint256 amount,
        bytes memory /* customPayload */,
        Origin memory /* origin */
    ) internal override whenNotPaused() returns(uint256 receivedAmount) {
        IERC20Extended(_underlyingToken).mint(to, amount);
    
        return amount;
    }
    function unpause() external {
        _authorizeCall();
        _unpause();
    }
        
    function pause() external onlyOwner() {
        _pause();
    }
    
    function underlyingDecimals() external view returns(uint8) {
        return _decimals;
    }
    interface IERC20Extended {    
        function mint(address to, uint256 amount) external;
        function burnFrom(address from, uint256 amount) external;
    }
    {
        "General information":{
            "TokenName":"Mytoken",
            "TokenSymbol":"MTK",
            "DeployedViaFactory": "false",
            "ChainIDs":[1, 42161]
        },
        "Deployments": [
            {
            "ChainId": 1,
            "Address": "0x",
            "Type": "Token",
            "Decimals": 18
        },
        {
            "ChainId": 42161,
            "Address": "0x",
            "Type": "Connector",
            "Decimals": 6  
        }
        ]
    }
    function _authorizeCall() internal override onlyOwner() {}
    function _burnFrom(
        address spender,
        address from, 
        bytes memory /* to */, 
        uint256 amount, 
        uint256 /* dstChainId */, 
        bytes memory /* customPayload */
    ) internal override returns(uint256 bridgedAmount) {
        if (from != spender) _spendAllowance(from, spender, amount);
    
        _update(from, address(0), amount);
    
        return amount;
    }
    function _mintTo(
        address to,
        uint256 amount,
        bytes memory /* customPayload */,
        Origin memory /* origin */
    ) internal override returns(uint256 receivedAmount) {
        _update(address(0), to, amount);
    
        return amount;
    }

    Import Dependencies

    Next, you'll need to import the UTS Base smart contract dependency. The UTS Base contract is the core component in the creation of a UTS Token or UTS Connector. To implement any token or connector, you’ll need to inherit from the UTS Base smart contract. Simply put, it acts as a wrapper around the cross-chain communication logic.

    To learn more, check out our examples, which include code with detailed technical documentation.

    3

    Inheritance and Virtual Functions

    Inherit from UTS Base contract. All necessary functions are virtual, allowing you to override them with your own logic if necessary.

    • The __UTSBase_init function MUST be called before using other functions of the UTSBase contract.

    • The _authorizeCall function MUST be overridden to include access restriction to the setRouter and setChainConfig functions.

    • The _mintTo function MUST be overridden to implement mint/transfer underlying tokens to receiver to address by _router.

    • The _burnFrom function MUST be overridden to implement burn/transferFrom underlying tokens from spender/from address for bridging.

    4

    Deployment

    Once you've finished editing the logic in your implementation, you can proceed with deployment. If you don't have precomputed contract addresses, you can leave initial settings, such as chain Ids and chain configs, empty.

    5

    Configuration

    Without configuring these settings in your Token/Connector contracts, your bridge will not function properly. Therefore, you must apply these configurations on both sides of your cluster.

    If you didn’t provide chain configurations during deployment, you can add them afterward by calling setChainConfig.

    6

    Finishing

    That's it! You've successfully created a custom token, and your cluster is now set up and ready to go. For additional important information, please refer to the section below. We also provide clear examples of custom tokens to guide you further.

    Additional Important Information and Notes

    Ensure Connector is Funded for Proper Functioning

    Connector's chain. Without funds, the Connector contract won't be able to unlock tokens. You can fill it by using the bridge from the Connector's chain, which will lock funds on that chain, or you can directly transfer the underlying token to the Connector's address. See how to transfer liquidity to the Connector.

    Maintain Adequate Token Balances in Your Connectors

    If you have multiple Connectors in your cluster, you must ensure their balances always contain enough underlying tokens to facilitate the redemption of funds.

    Automate Token Minting and Burning for Connector Liquidity

    You can implement advanced logic to allow your Connector to mint and burn tokens, eliminating the need to manage liquidity on the Connectors.

    Destination chain Id

    Destination gas limit

    Length of your custom payload

    UTS protocol payload

    Gas Limits

    The UTS Router provides a function called dstMinGasLimit which returns the amount of gas required to execute the {redeem} function on the destination chain.

    Deployment Costs

    If you want to perform a cross-chain deploying using our UTSDeploymentRouter, you can use the estimateDeploy function to estimate the separated payments required for sending crosschain deployment requests in the payment token. The function will return the fees you need to pay in PAYMENT_TOKEN.

    Name
    Meaning

    Array of chain ids where UTS Tokens will be deployed

    Array of chain ids where UTS Connectors will be deployed

    Deployment Costs in Native Currency

    If you want to perform a cross-chain deploying using our UTSDeploymentRouter, you can use the estimateDeployNative function to estimate the separated payments required for sending crosschain deployment requests in the payment token. The function will return the fees you need to pay in native currency.

    Connect Wallet

    Navigate to https://udf.entangle.fi/ and click on "Connect Wallet" at the top right to connect your wallet.

    2

    Navigate to Dashboard

    Click the "Dashboard" tab on the top of the page.

    3

    Notifications Section

    Scroll down to the "Notifications" section.

    4

    Select Feed

    Identify the feed that you with to renew and click the "Renew" button.

    5

    Renewal Amount

    Enter the amount that you wish to for.

    6

    Confirm and Finish

    Click the "Extend" button and confirm the transaction on your wallet.

    Your Feeds Section

    1

    Connect Wallet

    Navigate to https://udf.entangle.fi/ and click on "Connect Wallet" at the top right to connect your wallet.

    2

    Navigate to Dashboard

    Click the "Dashboard" tab on the top of the page.

    3

    Feeds Section

    Scroll down to "Your Feeds" section.

    4

    Select Feed

    Select any feed by clicking on it to bring up the subscription page or click on the 3 vertical dots on the right-hand side of the desired feed.

    5

    Top Up

    Click on the "Top Up" button.

    6

    Renewal Amount

    Input the amount that you wish to top up.

    7

    Confirm and Finish

    Click on the "Top Up" button at the bottom of the page to renew your subscription.

    hub
    Notifications
    Your Feeds
    using SSH or HTTPS and opening it locally, following the below guide to complete setup.
    1

    Dependencies

    install the necessary dependencies by running:

    2

    Blockchain Providers

    You can configure your blockchain providers like so:

    1. Navigate to /blockchain/EVM/provider.ts.

    2. Set up your wagmi configuration and provide your project ID (Learn more here:):

    1. Update the transports variable to use your custom RPC endpoints for different chains. By default, they are set to public RPCs, which may not be reliable:

    3

    Environment Variables

    In /core/Coin/CoinRepository/CoinRepository.ts, ensure you provide the required environment variables:

    • NEXT_PUBLIC_COINGECKO_API_KEY

    Using the Bridge

    1. Navigate to /constants/tokens.ts:

      1. Add UTS tokens or connectors you want to bridge.

      2. Follow the TokenOption type to ensure compatibility.

    2. The bridge SDK supports 10 default chains, compatible with UTS:

      1. Ethereum, Mantle, BSC, Base, Arbitrum, Avalanche, Optimism, Polygon, CoreDAO, and XLayer.

      2. These chains are defined in SelectNetworkModal.tsx and filtered based on tokens in the TOKENS file.

    How to Add a New Chain

    To integrate a new chain, follow these steps:

    1. Add the network to Web3Manager (e.g., EVMManager for EVM chains).

    2. Add the network configuration to tokens.ts.

    File Structure

    • .husky – Git hooks for the repository.

    • .next – Next.js build folder.

    • api – GraphQL API calls.

    • app – Next.js app router directory for pages.

    • blockchain – Blockchain logic, including providers, hooks, and ABIs.

    • containers – Reusable container components.

    • core – Redux layers (actively uses RTK; transitioning to RTK-query).

    • helpers – Utility functions and helpers.

    • hooks – Common application hooks.

    • lib – Third-party libraries used in the project.

    • providers – React contexts and providers.

    • public – Public assets folder.

    • scripts – Service scripts (e.g., Cosmos blockchain interactions).

    • ui–components – Reusable components that are used in the whole app (like tabs and tables).

    • utils – Common utilities.

    Contributing

    For questions or support, please reach out via the issues section or contact the repository maintainers.

    Contributions are welcome! If you’d like to contribute, please follow the repository guidelines and submit a pull request.

    repository
    repository
    repository
    Application Layer

    The Application Layer is the user-facing component of EIB, bridging consumer devices and the blockchain. It validates, decodes, and routes messages to enable smart contracts, dApps, and other blockchain-based applications, ensuring seamless user interaction and efficient execution.

    Sub-Layers

    • Execution Layer: Validates and executes smart contracts, chaincode, and foundational rules, ensuring accurate transaction processing.

    • Application Sub-Layer: Provides end-user services like wallets, lending, and staking. Interfaces such as Web3 applications or APIs facilitate user interactions with blockchain-based services.

    Modules Layer

    This comprises a variety of modules that provide specialized functions to the blockchain. These modules are responsible for handling core operations such as asset management, governance, and network security.

    See the list of modules and their description in the table below.

    Module name
    Description

    Delegated Proof of Stake (DPoS)

    Facilitates staking for Validators and Delegators.

    Banking

    Sending and receiving assets on Entangle Blockchain.

    GOV Module

    Changes to blockchain parameters, addition of new Validators, Distributors or Agents.

    Auth Module

    Allows authorized entities to launch smart contracts on Entangle Blockchain.

    IBC Module

    Facilitates communication with Cosmos-based Chains.

    Tendermint Consensus Layer

    EIB ensures reliability and security with a Byzantine Fault Tolerant (BFT) consensus mechanism, allowing the network to function even if up to one-third of nodes are faulty or compromised. This ensures consistent validation of cross-chain transactions and prevents disruptions from malicious actors.

    Participants:

    Validators: Propose and vote on transaction blocks, using round-robin scheduling based on their stake proportion.

    Delegators: Delegate their tokens to validators, who in turn earn a commission from the delegated stake.

    Consensus Process

    The consensus process in Tendermint involves several key steps to ensure secure and consistent block creation:

    1. Propose: A designated validator compiles transactions into a block and broadcasts it to peers. This ensures that all validators have a common starting point for considering new transactions.

    2. Pre-Vote: Each validator decides whether to support the proposed block. If a validator is already locked on a previous block, or if it receives a valid new proposal, it broadcasts its prevote for that block. If no valid proposal is received, it signs a nil prevote. This step is crucial to gauge initial support for the block, ensuring that validators are aligned before moving forward.

    3. Pre-Commit: Validators broadcast a precommit if they receive more than two-thirds of prevotes for a proposed block, effectively locking onto that block. Locking onto a block prevents validators from equivocating, which is essential for ensuring consensus consistency and security.

    4. Commit: During the commit step, validators wait to receive at least two-thirds of commits for a block. Once this condition is satisfied, the validator sets the CommitTime and moves to the next phase. This step finalizes the block and adds it to the blockchain, ensuring that all validators have reached agreement.

    5. NewHeight: After a block has been committed, the NewHeight step allows the network to gather additional commitments for the committed block from validators that may have been delayed. This step helps to maintain overall network integrity by ensuring that slower validators are included, promoting fairness and cohesion across the network.

    Locking Mechanisms

    Locks play a crucial role in maintaining consistency during voting stages by preventing validators from changing their support within the same round. Once a validator locks onto a block, they remain committed to it until consensus is achieved. This mechanism ensures that validators do not equivocate, thereby maintaining the reliability of the consensus process.

    Initiating New Rounds

    New rounds may be initiated in cases such as proposal failures, invalid blocks, untimely propagation, or insufficient pre-vote or pre-commit consensus. These new rounds are essential to the robustness of the Tendermint consensus process, allowing the network to overcome temporary challenges and maintain consistent block production. This flexibility is key to maintaining the integrity of the network even when disruptions occur.

    The Three Layers of EIB
    guide to transfer tokens

    Set up a Validator Node

    Becoming a validator on the EIB involves setting up your node, creating a wallet, configuring your system, and finally launching your validator node. This guide will walk you through these steps in detail to help you get started.

    Hardware Prerequisites

    Before proceeding, ensure that your hardware meets the recommended specifications to run a validator node efficiently.

    Hardware
    Mainnet
    Testnet

    Software Prerequisites

    Before you begin, make sure your system has the following software installed:

    • Git

    • Golang (minimum version 1.21)

    • Make

    • jq

    Step 1: Setting Up Your Node

    1. Clone the Entangle Blockchain Repository: Start by cloning the and navigating into the project directory:

    2. Build the Project: Compile the project using the make command, which will build the necessary binaries:

      After installation, you can verify the installation by running:

    3. Initialize Your Node: Create your node by initializing it with a unique moniker and specifying the chain ID:

    Step 2: Wallet Generation

    1. Create a New Key: Generate a new key for your wallet. You'll need to provide a key name and select the keyring backend and algorithm:

    2. Retrieve Your Address: Extract your wallet address and store for later use:

    Step 3: Configuration

    1. Update Configuration Files: Download and . You'll need to replace the existing files in your .entangle/config/ directory with these.

    2. Set Persistent Peers: In your .entangle/config/config.toml file, update the field with the provided list of nodes:

    Step 4: Launching Your Node

    1. Start Your Node: With the configurations set, you can start your node. Ensure to specify the chain ID and set the gas cap for JSON-RPC:

    2. Verify Node Synchronization: Check if your node is fully synced with the network:

      A response of false indicates successful synchronization.

    Step 5: Creating Your Validator Node

    1. Ensure You Have NTGL Tokens: To create a validator, you must have a sufficient amount of NTGL tokens for staking and transaction fees.

    2. Create Validator: Use the following command to create your validator. Replace <key_name> with your key name and adjust other parameters as necessary:

    3. Verify Your Validator Node: Check if your validator has been successfully added to the validator set:


    By following these steps, you can set up and launch a validator node on the Entangle blockchain. Remember to keep your node online and perform regular maintenance to ensure its smooth operation and contribution to the network's security and efficiency.

    Token with Messages

    Create contract with name UTSTokenWithLogicShowcase .

    You need to import:

    We start with defining the contract and the dependencies. For the access control we choose Ownable and also since it is UTS Token we need to import ERC20 implementation, here we are using one by openzeppelin.

    UTSBase is our main contract that should be inherited by any Token or Connector.

    In this implementation we also used Ownable and ERC20.

    Then we need do define constructor. Since it is Token, we don't need a lot, just general UTS settings and ERC20 metadata.

    We need setup _router

    import "@entangle-labs/uts-contracts/contracts/ERC20/UTSBase";
    npm i @entangle-labs/uts-contracts
    /**
     * @notice Returns estimated minimal amount to pay for bridging and minimal gas limit.
     * @param dstChainId destination chain Id.
     * @param dstGasLimit {redeem} call gas limit on the destination chain.
     * @param customPayloadLength user's additional data length.
     * @param protocolPayload UTS protocol's additional data.
     * @return paymentAmount source chain native currency amount to pay for bridging.
     * @return dstMinGasLimit destination chain minimal {redeem} call gas limit.
     */
    function estimateBridgeFee(
        uint256 dstChainId,
        uint64 dstGasLimit,
        uint16 customPayloadLength,
        bytes calldata protocolPayload
    ) public view virtual returns(uint256 paymentAmount, uint64 dstMinGasLimit)
    /**
    * @notice Returns the amount of gas required to execute {redeem} function on the destination chain.
    * @param dstChainId destination chain Id.
    * @return dstMinGasLimitAmount the amount of gas required to execute {redeem} function on the provided {dstChainId}.
    */
    function dstMinGasLimit(
        uint256 dstChainId
    ) public view returns(uint64 dstMinGasLimitAmount)
    /**
     * @notice Estimates the separated payments required for send crosschain deployment requests in the {PAYMENT_TOKEN}.
     * @param dstTokenChainIds destination chain Ids for {UTSToken} deployments.
     * @param dstConnectorChainIds destination chain Ids for {UTSConnector} deployments.
     * @return tokenPaymentAmount array of estimated payment amount in the {PAYMENT_TOKEN} for each {dstChainId}.
     * @return connectorPaymentAmount array of estimated payment amount in the {PAYMENT_TOKEN} for each {dstChainId}.
     * @return totalPaymentAmount estimated total payment amount in the {PAYMENT_TOKEN}.
     */
    function estimateDeploy(
        uint256[] calldata dstTokenChainIds,
        uint256[] calldata dstConnectorChainIds
    ) external view returns(
        uint256[] memory tokenPaymentAmount, 
        uint256[] memory connectorPaymentAmount, 
        uint256 totalPaymentAmount
    )
    /**
     * @notice Estimates the separated payments required for send crosschain deployment requests in native currency.
     * @param dstTokenChainIds destination chain Ids for {UTSToken} deployments.
     * @param dstConnectorChainIds destination chain Ids for {UTSConnector} deployments.
     * @return tokenPaymentAmountNative array of estimated payment amount in native currency for each {dstChainId}.
     * @return connectorPaymentAmountNative array of estimated payment amount in native currency for each {dstChainId}.
     * @return totalPaymentAmountNative estimated total payment amount in native currency.
     */
    function estimateDeployNative(
        uint256[] calldata dstTokenChainIds,
        uint256[] calldata dstConnectorChainIds
    ) external view returns(
        uint256[] memory tokenPaymentAmountNative, 
        uint256[] memory connectorPaymentAmountNative, 
        uint256 totalPaymentAmountNative
    )
    npm i

    Distributor Module

    A database of authorized Distributors added through the GOV Module.

    EVM Module

    Hosts smart contracts deployed on Entangle Blockchain such as the Controller. Provides composability between Entangle Blockchain and EVM Infrastructure such as Metamask, Hardhat, and Truffle.

    Vesting Module

    Facilitates vesting of native tokens.

    https://entangle.zendesk.com/hc/en-us/requests/new?ref=blog.entangle.fi&ticket_form_id=22454894777501entangle.zendesk.com
    https://www.youtube.com/watch?v=xYa_dHStr3Uwww.youtube.com
    : Used to fetch USD prices for native currencies, essential for calculating bridge fees.
  • NEXT_PUBLIC_BASE_MESSAGES_URL: GraphQL endpoint for tracking the history of bridge operations.

  • Wagmi Connect Wallet Guide
    Python
  • golangci-lint

  • Solc-JS

  • CPU

    4 or more physical CPU cores

    2 or more physical CPU cores

    RAM

    16GB+

    8GB+

    Storage

    500GB+ SSD

    250GB+ SSD

    Network

    100mbps+

    10mbps+

    OS

    Ubuntu 22.04

    Ubuntu 22.04 or macOS

    official Entangle blockchain repository
    genesis.json
    config.toml
    persistent_peers
    address, that can be found
    .

    _allowedChainIds are simply whitelist of chain id's, where you are allowing to bridge tokens.

    _chainConfigs is array of settings responsible for bridge settings. We described this config here.

    In constructor we need to call __UTSBase_init function to initialize UTS Base contract. Also we need to set router and chain config.

    Also we added mint function to premint some tokens for deployer address.

    We can skip setting router and chain configs in constructor, but before starting bridging we need to do it with relevant public functions.

    Also let's define some events to have a possibility to debug and track transactions and also some errors and library.

    After this step we need to override 3 functions: _mintTo, _burnFrom and _authorizeCall. We need to do it, because this token is mint/burn, so, internal logic should be of main bridging function should be done via mint/burn of underlying token.

    In this implementation, we use customPayload as an option to transfer tokens to multiple receivers in different amounts just by one transaction. To do that, we define rules for how the raw bytes passed in customPayload should be encoded. In the _burnFrom function, we burn the tokens from the token holder in the provided amount and implement basic validations of the customPayload, if it is provided.

    Also, it is necessary to implement tokens minting to the receiver or multiple receivers in the _mintTo function. Both possible scenarios need to be handled depending on whether a meaningful customPayload was provided. In this case, the raw bytes should be decoded, and the corresponding token _amounts should be minted to _receivers.

    So, our contract is ready, now it can be deployed on networks and we can start bridging tokens between each chain.

    You can find full code here

    here
    /**
     * @notice Sets the destination chains settings.
     * @param allowedChainIds chains Ids available for bridging in both directions.
     * @param chainConfigs array of {ChainConfig} settings for provided {allowedChainIds}, containing:
     *        peerAddress: connected {UTSToken} or {UTSConnector} contract address on the destination chain
     *        minGasLimit: the amount of gas required to execute {redeem} function on the destination chain
     *        decimals: connected {peerAddress} decimals on the destination chain
     *        paused: flag indicating whether current contract is paused for sending/receiving messages from the connected {peerAddress}
     *
     * @return success call result.
     */
    function setChainConfig(
        uint256[] calldata allowedChainIds,
        ChainConfig[] calldata chainConfigs
    ) external virtual returns(bool success)
    const projectId = 'your project id';
    export const transports = {
      [mainnet.id]: http('https://ethereum-rpc.publicnode.com'),
      [mantle.id]: http('https://mantle-rpc.publicnode.com'),
      [bsc.id]: http('https://bsc-rpc.publicnode.com'),
      ...
    };
    NEXT_PUBLIC_COINGECKO_API_KEY=your API KEY
    NEXT_PUBLIC_BASE_MESSAGES_URL=your GraphQL endpoint
    git clone https://github.com/Entangle-Protocol/entangle-blockchain
    cd entangle-blockchain
    git checkout main
    make install
    entangled --help
    entangled init <moniker> --chain-id entangle_33033-1
    entangled keys add <key_name> --keyring-backend file --algo eth_secp256k1
    MY_ADDRESS=$(entangled keys show <key_name> -a --keyring-backend file)
    echo $MY_ADDRESS
    persistent_peers = "node1@ip:port, node2@ip:port"
    entangled start --chain-id entangle_33033-1 --json-rpc.gas-cap 200000000
    curl -s 127.0.0.1:26657/status | jq '.result.sync_info.catching_up'
    entangled tx staking create-validator \
    --amount="5000000000000000000aNGL" \
    --pubkey=$(entangled tendermint show-validator) \
    --moniker="validator" \
    --chain-id=entangle_33033-1 \
    --commission-rate="0.10" \
    --commission-max-rate="0.20" \
    --commission-max-change-rate="0.01" \
    --min-self-delegation="1" \
    --gas=500000 \
    --gas-prices="10aNGL" \
    --from=<key_name> \
    --keyring-backend file
    entangled query tendermint-validator-set
    dstChainId
    dstGasLimit
    customPayloadLength
    protocolPayload 
    dstTokenChainIds
    dstConnectorChainIds
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    import "@entangle-labs/uts-contracts/contracts/ERC20/UTSBase";
    contract UTSTokenWithLogicShowcase is UTSBase, Ownable, ERC20 {}
    constructor(
        address _router,  
        uint256[] memory _allowedChainIds,
        ChainConfig[] memory _chainConfigs
    ) Ownable(msg.sender) ERC20("UTS Token With Logic Showcase", "TWL") {
        __UTSBase_init(address(this), decimals());
    
        _setRouter(_router);
        _setChainConfig(_allowedChainIds, _chainConfigs);
    
        _mint(msg.sender, 1_000_000 * 10 ** decimals());
    }
    using AddressConverter for bytes;
    
    error UTSTokenWithLogicShowcase__E0();
    
    error UTSTokenWithLogicShowcase__E1();
    
    error UTSTokenWithLogicShowcase__E2();
    
    event MultiBridged(
        address indexed spender, 
        address from, 
        bytes indexed dstPeerAddressIndexed, 
        bytes dstPeerAddress,
        bytes[] receivers, 
        uint256[] amounts,
        uint256 indexed dstChainId
    );
    
    event MultiRedeemed(
        address[] indexed receiversIndexed, 
        address[] receivers,
        uint256[] amounts, 
        bytes indexed srcPeerAddressIndexed, 
        bytes srcPeerAddress,
        uint256 indexed srcChainId,
        bytes sender
    );
    
    function _authorizeCall() internal override onlyOwner() {}
    function _burnFrom(
        address spender,
        address from, 
        bytes memory /* to */, 
        uint256 amount, 
        uint256 dstChainId, 
        bytes memory customPayload
    ) internal override returns(uint256 bridgedAmount) {
        if (from != spender) _spendAllowance(from, spender, amount);
    
        _update(from, address(0), amount);
    
        // This is just an example of how multi-bridge can be implemented.
        if (customPayload.length > 0) {
            // {address} type array can be used here if the token will exist only in EVM-compatible chains.
            (bytes[] memory _receivers, uint256[] memory _amounts) = abi.decode(customPayload, (bytes[], uint256[]));
    
            // Some basic checks are added here:
            //     1. the {_receivers} and {_amounts} arrays lengths are the same
            //     2. the {_receivers} addresses are not empty
            //     3. the sum of {_amounts} is equal to {amount}
    
            if (_receivers.length != _amounts.length) revert UTSTokenWithLogicShowcase__E0();
    
            uint256 _amountsSum;
    
            for (uint256 i; _receivers.length > i; ++i) {
                if (_receivers[i].length == 0) revert UTSTokenWithLogicShowcase__E1();
    
                _amountsSum += _amounts[i];
            }
    
            if (amount != _amountsSum) revert UTSTokenWithLogicShowcase__E2();
    
            ChainConfig memory config = _chainConfig[dstChainId];
    
            emit MultiBridged(spender, from, config.peerAddress, config.peerAddress, _receivers, _amounts, dstChainId);
        }
    
        return amount;
    }
    function _mintTo(
        address to,
        uint256 amount,
        bytes memory customPayload,
        Origin memory origin
    ) internal override returns(uint256 receivedAmount) {
        if (customPayload.length > 0) {
            (bytes[] memory _receiversInBytes, uint256[] memory _amounts) = abi.decode(customPayload, (bytes[], uint256[]));
    
            address[] memory _receivers = new address[](_receiversInBytes.length);
    
            for (uint256 i; _receiversInBytes.length > i; ++i) {
                _receivers[i] = _receiversInBytes[i].toAddress();
                _update(address(0), _receivers[i], _amounts[i]);
            }
    
            emit MultiRedeemed(
                _receivers, 
                _receivers,
                _amounts, 
                origin.peerAddress, 
                origin.peerAddress,
                origin.chainId,
                origin.sender
            );
    
        } else {
            _update(address(0), to, amount);
        }
    
        return amount;
    }

    EVM Smart Contracts

    Using the Push model means retrieving data from on-chain contract storage. This requires the data to exist in the on-chain contract storage, uploaded by a publisher or node operator beforehand. UDF maintains a node that continuously publishes updates for supported assets, but anyone is free to run their own node instance to ensure redundancy or customize their setup.

    To utilize an update in your contract, you can read the value of the asset of interest from the PushMarketplace contract deployed on each supported chain. For demonstration purposes, in this guide we will create a consumer contract whose logic depends on the BTC/USD price.

    Step 1: Initialize hardhat project

    First of all, let's create new project and initialize hardhat in it.

    Step 2: Create PushReader contract and hardhat ignition script

    Next, let's create our consumer contract. The consumer contract, referred to as the PushReader, will retrieve data stored in PushMarketplace, which assumes the availability of verified updates pushed on-chain beforehand.

    In this example, the contract will read the latest stored price of the BTC/USD asset and store it. To achieve this, we'll use the getFeedPrice function, a free data retrieval method for previously subscribed readers.

    This contract should already be in subscription so it can have access for verification. The subscription can be purchased from the marketplace and the consumer contract needs to be added as an authorized address for the subscription.

    For convenience, this function returns both the price and the timestamp in a single call. Providing both values ensures that users can verify the freshness of the data, which is critical for applications where price accuracy and timing are essential for decision-making.

    Next, create an ignition script to help with deployment of the new PushReader contract.

    Step 3: Deploy PushReader

    To deploy your contract on testnet, you'll need ETH eth_sepolia testnet tokens. You can obtain funds from public faucets (, , , , ).

    Now let's modify the hardhat configuration file to add the eth_sepolia network.

    Now we can deploy the PushReader contract by running the command below.

    Expected Result

    Step 4: Create Push Subscribtion

    Now we should add deployed PushConsumer(PushReader) contract as allowed address to our subscribtion.

    for desired feed and with desired parameters and put deployed PushConsumer contract as address that can read the contract.

    Step 5: Execute PushConsumer.consumePrice transaction

    To validate that we have our price, we will write an example backend script that send transaction to execute PushConsumer.consumePrice.

    Let's create a separate directory called "scripts" and create a new script consumePrice.ts in it.

    Change the PushReaderAddress to the address you got from deployment and execute the script to send the transaction to the blockchain.

    Expected Result

    You can use cast to examine the transaction call trace and logs. The emitted event shows the latest update that we read. Note that gas usage may vary depending on the result and the version of the library in use.

    Expected Result

    Media Kit

    Take care of the below points while using the logo

    We are pleased to share Entangle’s media kit, which contains essential brand assets, key messaging, and valuable resources to support our shared efforts. As we continue to drive innovation in Web3, this kit will provide you with everything needed to accurately represent Entangle and strengthen our partnership. Together, we are building the future of decentralized technology.

    Guidelines

    • Do not crop the logo, rotate it, or place it with other colors

    • Do not re-create using any other typeface

    • Do not use shadows, transparency, or any other effects

    • Refrain from altering the shape, and proportion of the logos

    • Keep padding around the logo.

    Colour Codes

    Logos

    Backgrounds

    ​

    FAQ

    Universal Token Standard
    Universal Data Feeds
    mkdir push-consumer && cd push-consumer
    yarn init -y
    # Yarn initialization
    yarn add --dev hardhat
    yarn hardhat init
    # Hardhat initialization flow(select TypeScript project)
    Option 1
    Option 2
    Option 3
    Option 4
    Option 5
    Subscribe to a push datafeed
    ./contracts/PushReader.sol
    // SPDX-License-Identifier: BSL1.1
    pragma solidity ^0.8.20;
    interface IPushMarketplace  { 
    
       function getFeedPrice(
            bytes32 feed
        ) external returns (uint256 price, uint256 timestamp);
    }
    contract PushReader {
        IPushMarketplace public pushMarketplace;
        uint public latestPrice;
        uint public latestTimestamp;
        constructor(address _pushMarketplace){
            pushMarketplace = IPushMarketplace(_pushMarketplace);
        }
        function getData(bytes32 feedKey) external{
            (latestPrice, latestTimestamp) = pushMarketplace.getFeedPrice(feedKey);
        }
    }
    ./ignition/modules/PushReader.ts
    import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
    
    // PushMarketplace address on Eth Sepolia network
    const PushMarketplaceAddress = "0x48A10FF4ea77A099Cc966b537b5efC5b15c1060A"
    
    const PushReaderModule = buildModule("PushReaderModule", (m) => {
      const consumer = m.contract("PushReader", [PushMarketplaceAddress]);
    
      return { consumer };
    });
    
    export default PushReaderModule;
    ./hardhat.config.ts
    import { HardhatUserConfig } from "hardhat/config";
    import "@nomicfoundation/hardhat-toolbox";
    
    const config: HardhatUserConfig = {
      solidity: "0.8.28",
      networks: {
        eth_sepolia: {
            chainId: 11155111,
            // or http://127.0.0.1:8545, if you forked it locally
            url: "https://ethereum-sepolia-rpc.publicnode.com",
            accounts: [ "0x" ], // TODO: Set deployer private key
        },
      },
    };
    
    export default config;
    yarn hardhat ignition deploy ./ignition/modules/PushReader.ts --network eth_sepolia
    ✔ Confirm deploy to network eth_sepolia (11155111)? … yes
    Compiled 1 Solidity file successfully (evm target: paris).
    Hardhat Ignition 🚀
    
    Deploying [ PushReaderModule]
    
    Batch #1
      Executed PushReaderModule#PushReader
    
    [ PushReaderModule] successfully deployed 🚀
    
    Deployed Addresses
    
    PushConsumerModule#PushConsumer - 0xe23650424625B602c0f996F25b287203632A3f16
    mkdir scripts && touch ./scripts/consumePrice.ts
    ./scripts/consumePrice.ts
    import {
      PushReader,
    } from "../typechain-types";
    import { ethers } from "hardhat";
    
    // PushConsumer address we got from the deployment
    const PushReaderAddress = "0xe23650424625B602c0f996F25b287203632A3f16";
    
    async function main() {  
      const pushConsumer = await ethers.getContractAt(
        "PushReader",
        PushReaderAddress
      ) as PushReader
    ;
      const feedKey = ethers.encodeBytes32String("BTC/USD");
      let tx = await pushReader.getFeedPrice(feedKey);
      await tx.wait();
    
      console.log("sent PushReader.getData tx", tx.hash);
      let price = await pushReader.latestPrice();
      let timestamp = await pushReader.latestTimestamp();
      console.log("price:", price );
      console.log("timestamp:", timestamp );
    }
    
    main()
      .then(() => process.exit(0))
      .catch(error => {
        console.error(error);
        process.exit(1);
      });
    
    yarn hardhat run ./scripts/consumePrice.ts --network eth_sepolia
    sent PushReader.getData tx 0x8c9c7abdfc243500d8f20dafd69cb6b2f9b5c41a1bb5f8a374bb04a31e43dc94
    price: 76660817492475224330633n
    timestamp: 1744027000n
    cast run 0x8c9c7abdfc243500d8f20dafd69cb6b2f9b5c41a1bb5f8a374bb04a31e43dc94 -r https://eth-sepolia.public.blastapi.io
    Executing previous transactions from the block.
    Traces:
      [70570] 0xe23650424625B602c0f996F25b287203632A3f16::getData(0x4254432f55534400000000000000000000000000000000000000000000000000)
        ├─ [20482] 0x48A10FF4ea77A099Cc966b537b5efC5b15c1060A::getFeedPrice(0x4254432f55534400000000000000000000000000000000000000000000000000)
        │   ├─ [15586] 0x9E5953C651932937e5a9185404B925030F5cCF3a::getFeedPrice(0x4254432f55534400000000000000000000000000000000000000000000000000) [delegatecall]
        │   │   ├─  emit topic 0: 0x3aa8c2e667a2fabc8ac13b12611dabfd9bdd2f66210ad437122a7ab032ddf011
        │   │   │           data: 0x000000000000000000000000e23650424625b602c0f996f25b287203632a3f164254432f55534400000000000000000000000000000000000000000000000000
        │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000103bca8eeefcd59d11890000000000000000000000000000000000000000000000000000000067f3bd78
        │   └─ ← [Return] 0x00000000000000000000000000000000000000000000103bca8eeefcd59d11890000000000000000000000000000000000000000000000000000000067f3bd78
        └─ ← [Stop] 
    
    
    Transaction successfully executed.
    Gas used: 91846

    Purple

    A527E1

    Dark Grey

    1B1B1B

    Light Grey

    6E6A6A

    Grey to White

    F0F0F0 - FFFFFF

    White

    FFFFFF

    Name

    PNG

    SVG

    Circle White

    ​​

    ​​

    Circle Black

    ​​

    ​​

    Circle Gray

    ​​

    ​​

    Circle Purple

    ​​

    ​​

    Сhamfer rectangle White

    ​​

    ​​

    Сhamfer rectangle Black

    ​​

    ​​

    Сhamfer rectangle Gray

    ​​

    ​​

    Сhamfer rectangle Purple

    ​​

    ​​

    Background White

    ​​

    Background Gray

    ​

    Background Purple

    ​​

    Background White Without Logo

    ​​

    Background Gray Without Logo

    ​​

    Background Purple Without Logo

    ​​

    Background White Without Logo

    ​​

    Background Gray Without Logo

    ​​

    Background Purple Without Logo

    ​​

    Entangle Mainnet

    Agent Network

    Entangle Omnipoints

    Entangle e-Bridge

    Delegating Tokens

    Does UTS charge any fees?

    How do I decide which bridging mechanism is better? Mint & Burn or Lock & Unlock

    I want to deploy my token on several chains. Do I need to have all the native tokens to do so?

    How do I split the total supply of a new token?

    What if I connect existing tokens and then try to bridge it without enough liquidity on the Connector?

    I’ve completed a deployment, but can’t see my token on the bridge.

    EVM Smart Contracts

    In the Pull model, consumers include verification data about the most recent update directly in their transaction. This data is fetched from the oracle and verified within the same transaction before being used.

    This scheme comes with the following properties:

    1. Consumers always use the latest update in their transaction, so the price used in the transaction is as close to real time as protocol update latency.

    2. The cost for maintaining update relevance on-chain relies on end-consumers. This allows the oracle protocol to have much larger set of assets.

    This guide will help developers who want to use UDF Pull model (with subscription) within their contracts. It uses Hardhat for contract compilation, although similar methods apply with other frameworks.

    Step 1: Initialize new hardhat project

    In the first step, we are establishing a basic solidity development setup.

    Step 2: Write a contract that verifies an update in the transaction

    Now create a new PullVerifierSub contract, which utilizes the pullMarketplace.verifyAsSubscriber function to verify the update information provided through calldata. The update contains oracle votes along with their signatures.

    This contract should already be in subscription so it can have access for verification. The subscription can be purchased from the marketplace and the consumer contract needs to be added as an authorized address for the subscription.

    Once the PullVerifierSub contract verifies the update against these inputs, it stores them on-chain, to later be accessed. If the verification fails (e.g., due to mismatched data, invalid signatures, or other inconsistencies) the contract reverts the entire transaction, ensuring that only valid data is accepted.

    Next, create an ignition script to help with deployment of the new PullVerifierSub contract.

    Step 3: Deploy PullVerifierSub

    To deploy your contract on testnet, you'll need ETH eth_sepolia testnet tokens. You can obtain funds from public faucets (, , , , ).

    Now let's modify the hardhat configuration file to add the eth_sepolia network.

    Now we can deploy the PullVerifierSub contract by running the command below.

    Expected Result

    Step 4: Create a Pull Subscribtion

    Now we should add the deployed PullVerifierSub contract as an allowed address to our subscription, so that it can verify Pull updates.

    To do that, go to the BTC/USD and select Pull Mode. Then add the address of the deployed PullVerifierSub contract under "Which addresses can read the contract?" and click Subscribe.

    You may read more about subscribing to feeds at .

    Step 5: Execute transaction

    First, add the UDF SDK library. We will use it to fetch the update using the REST API and encode it for on-chain usage.

    To validate that we have our price, we will write an example backend script that send transaction to execute PullVerifierSub.verifyAsSubscriber. Let's create separate directory scripts and our new script verifyAsSub.ts to do just that.

    Change the PullVerifierAddress to the address you got from deployment and execute the script.

    Now let's run the script using the command below to ensure it's working.

    Expected Results

    You can use cast to examine the transaction call trace and logs. The emitted event shows the latest update that we verified. Note that gas usage may vary depending on the result and the version of the library in use.

    Expected Results

    Factory Blueprint Deployment

    If our blueprint Token or Connector meets your requirements, you can deploy the token using our Factory. You may also deploy the Token or Connector contracts on all desired chains (ensure that an existing UTS Router is available on these chains). See below for more information.

    Single-Chain Deployment via UTS Factory

    UTS Token

    If you want to deploy UTS Token using our blueprint, you can call the function below on UTS Factory contract:

    Use DeployTokenData :

    Field
    Meaning

    If PureToken is set to true, then initialSupply should be equal or more than mintedAmountToOwner.

    If PureToken is set to false, then initialSupply should be equal to mintedAmountToOwner

    UTS Connector

    If you want to deploy UTS Connector, you should use function below:

    Using struct DeployConnectorData

    Field
    Meaning

    Chain Config struct should be built using struct below:

    Ensure the chain configurations are properly set up to allow all your smart contracts to communicate with each other.

    Name
    Meaning

    owner, router ,chainConfigs.peerAddressand underlyingToken are addresses, but since UTS is omnichain, we designed our protocol to be ready for non evm blockchains like Solana, Ton and others. So, to pass address like data use abi.encodePacked(address), on evm chains

    You may configure minGasLimit parameter to take more gas for transfer execution on destination chain if you need so. Please do your own calculations.

    You can set this minGasLimit as 0, so, minGasLimit will be set from UTSRouter. You can find more information in

    Cross-Chain Deployment with UTS Deployment Router

    You can use our Deployment Router for cross-chain deployment, allowing you to deploy and set up the entire cluster with a single function call. To do this, simply call the function below on the UTSDeploymentRouter.

    To do this you need to provide deployMetadata:

    Name
    Meaning

    If you want to pay in ERC-20 token you can do it with PAYMENT_TOKEN in UTSDeploymentRouter. You also have a possibility to pay in native. Currently it is NGL

    If you want to estimate deployment fee we have functions for that reason on UTSDeploymentRouter. You can find this information in section

    That's it, now you are ready to make your first cross-chain token transfer!

    I undelegated my tokens but cannot find them in my wallet.

    How do I subscribe to a data feed?
    What is the UDF pricing model like?
    What is the difference between Push and Pull modes?
    How much should be deposited for Push subscriptions?
    How can I check if a subscription is active?
    What if the feed I am searching for is not available?
    What happens if my push deposit runs out?
    How do I manage my subscriptions?
    Can I implement smart contracts to my data feed?
    How often should partners update data on their server?
    What should I do if the data provided by an external API does not meet the required format?
    Can Entangle UDF support custom modifiers for data parsing?
    How do I handle optional fields like timestamp and volume in the server response?
    Can I use public data providers for integration?
    How do I connect to the Entangle Mainnet?
    How do I use the Entangle Explorer Hub?
    Which wallets can I use?
    What is an Agent?
    Can I run an Agent?
    I have an agent NFT, how do I run an Agent?
    What is the process for onboarding as an Agent?
    I’m a developer who wants to include Transmitter Agents in my build, what's the process?
    What are Omnipoints?
    How do I earn Omnipoints?
    How do I check how many Omnipoints I have earned?
    What can I do with my earned Omnipoints?
    How do I bridge USDC?
    How long does the bridge take?
    How do I bridge to the Entangle mainnet?
    How do I bridge back to Ethereum?
    Bridging from Entangle to Solana
    I cannot see my bridged tokens
    What is delegating or staking?
    Why should I delegate?
    What’s in it for me?
    How do I delegate or stake $NGL?
    When can I claim my rewards?
    How do I undelegate or unstake my $NGL?
    What is the 21 day lock?
    What are the risks associated with delegating or staking?
    How can I mitigate the risks of delegating?
    My tokens are on a hardware wallet like Ledger. Can I still delegate?
    How can I stake my NFT?
    Option 1
    Option 2
    Option 3
    Option 4
    Option 5
    pair page
    Subscribe to a Data Feed
    yarn init -y
    # yarn initialization flow
    yarn add --dev hardhat
    yarn hardhat init
    # Hardhat initialization flow(select TypeScript project)
    ./contractrs/PullVerifierSub.sol
    // SPDX-License-Identifier: BSL1.1
    pragma solidity ^0.8.20;
    
    interface IPullMarketplace  {
            struct PriceUpdate {
            uint256 price;
            uint256 timestamp;
        }
        function verifyAsSubscriber(
            bytes calldata updateData,
            bytes32 feedKey
        )
            external
            returns (PriceUpdate memory);
    }
    contract PullVerifierSub {
        IPullMarketplace public pullMarketplace;
        uint public latestPrice;
        uint public latestTimestamp;
        constructor(address _pullMarketplace){
            pullMarketplace = IPullMarketplace(_pullMarketplace);
        }
        // @notice function that verifies feed as subscriber from provided update through UDFOracle and stores update data
        function verify(bytes calldata updateData, bytes32 feedKey) external{
            IPullMarketplace.PriceUpdate memory priceUpdate = pullMarketplace.verifyAsSubscriber(updateData,feedKey);
            latestPrice = priceUpdate.price;
            latestTimestamp = priceUpdate.timestamp;
        }
    }
    
    ./ignition/modules/PullVerifierSub.ts
    import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
    
    // PullMarketplace address on Eth Sepolia network
    const PullMarketplaceAddress = "0xC6670092056e7bf56c3149FDE52A187b3e9f2e63";
    
    const PullVerifierSubModule = buildModule("PullVerifierSubModule", (m) => {
    	const consumer = m.contract("PullVerifierSub", [PullMarketplaceAddress ]);
    
    	return { consumer };
    });
    
    export default PullVerifierSubModule;
    ./hardhat.config.ts
    import { HardhatUserConfig } from "hardhat/config";
    import "@nomicfoundation/hardhat-toolbox";
    
    const config: HardhatUserConfig = {
      solidity: "0.8.28",
      networks: {
        eth_sepolia: {
            chainId: 11155111,
            // or http://127.0.0.1:8545, if you forked it locally
            url: "https://ethereum-sepolia-rpc.publicnode.com",
            accounts: [ "0x" ], // TODO: Set deployer private key
        },
      },
    };
    
    export default config;
    yarn hardhat ignition deploy ./ignition/modules/PullVerifierSub.ts --network eth_sepolia
    ✔ Confirm deploy to network eth_sepolia (11155111)? … yes
    Compiled 1 Solidity file successfully (evm target: paris).
    Hardhat Ignition 🚀
    
    Deploying [ PullVerifierSubModule ]
    
    Batch #1
      Executed PullVerifierSubModule#PullVerifierSub
    
    [ PullVerifierSubModule] successfully deployed 🚀
    
    Deployed Addresses
    
    PullVerifierSubModule#PullVerifierSub - 0x7c0ad1Bb6c6dD48CA70C190B400aD56DeF61F43C
    
    yarn add --dev @entangle-labs/udf-sdk
    mkdir scripts && touch ./scripts/verifyAsSub.ts
    ./scripts/verifyAsSub.ts
    import {
      PullVerifierSub,
    } from "../typechain-types";
    import { ethers } from "hardhat";
    import { UdfSdk } from '@entangle-labs/udf-sdk';
    
    // PullVerifierSub address we got from the deployment
    const PullVerifierAddress = "0x7c0ad1Bb6c6dD48CA70C190B400aD56DeF61F43C";
    
    async function main() {  
      const pullVerifier = await ethers.getContractAt(
        "PullVerifierSub",
        PullVerifierAddress 
      ) as PullVerifierSub;
    
      // Fetch the update data from finalized-data-snap
      const sdk = new UdfSdk();
      const updateData = await sdk.getCallData(["BTC/USD"]);
      const feedKey = ethers.encodeBytes32String("BTC/USD");
      let tx = await pullVerifier.verify(updateData,feedKey);
      await tx.wait();
    
      console.log("sent PullVerifierSub.verify tx", tx.hash);
      let price = await pullVerifier.latestPrice();
      let timestamp = await pullVerifier.latestTimestamp();
      console.log("price:", price );
      console.log("timestamp:", timestamp );
    }
    
    main()
      .then(() => process.exit(0))
      .catch(error => {
        console.error(error);
        process.exit(1);
      });
    yarn hardhat run ./scripts/verifyAsSub.ts --network eth_sepolia
    sent PullVerifierSub.verify tx 0x7d202c67c1d3f04606743a406979eb4dd4a435be37eb0490c502895c28ecc0ec
    price: 84087090417798546633122n
    timestamp: 1743492361n
    cast run 0x7d202c67c1d3f04606743a406979eb4dd4a435be37eb0490c502895c28ecc0ec -r https://ethereum-sepolia-rpc.publicnode.com
    Executing previous transactions from the block.
    Traces:
      [99231] PullVerifierSub::verify(0x55444646014254432f55534400000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000011ce4ebc2338797454e80000000000000000000000000000000000000000000000000000000067eba567c157813327ab23012c0c51d803a60fdeb2db3460e19840849b99b5e4996ee90853a0d1ad5e5be5304cb76990ffd1e04680f7f2f85680ac62f529b5614031062e1c0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567cd0d22ac7bc0820ebcbc11b087c059c2d36b207d020a3987b21b56b11c2ca0982796fc953c1ebf14434ee0dffc225d87e12ca4506f07f0971e4fcd72bcbab2241c0000000000000000000000000000000000000000000011ce6ed6df09a64f08420000000000000000000000000000000000000000000000000000000067eba567c82350a2e16b70134ec057193550fd49b18e793604b1e4743fc01c2cae01f9b7631cdfa9033e2c414cf29451f916c482316673fd8be956a1d5ea5dc1791115c01b, 0x4254432f55534400000000000000000000000000000000000000000000000000)
    	├─ [82339] ERC1967Proxy::fallback(0x55444646014254432f55534400000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000011ce4ebc2338797454e80000000000000000000000000000000000000000000000000000000067eba567c157813327ab23012c0c51d803a60fdeb2db3460e19840849b99b5e4996ee90853a0d1ad5e5be5304cb76990ffd1e04680f7f2f85680ac62f529b5614031062e1c0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567cd0d22ac7bc0820ebcbc11b087c059c2d36b207d020a3987b21b56b11c2ca0982796fc953c1ebf14434ee0dffc225d87e12ca4506f07f0971e4fcd72bcbab2241c0000000000000000000000000000000000000000000011ce6ed6df09a64f08420000000000000000000000000000000000000000000000000000000067eba567c82350a2e16b70134ec057193550fd49b18e793604b1e4743fc01c2cae01f9b7631cdfa9033e2c414cf29451f916c482316673fd8be956a1d5ea5dc1791115c01b, 0x4254432f55534400000000000000000000000000000000000000000000000000)
    	│   ├─ [77350] PullMarketplace::verifyAsSubscriber(0x55444646014254432f55534400000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000011ce4ebc2338797454e80000000000000000000000000000000000000000000000000000000067eba567c157813327ab23012c0c51d803a60fdeb2db3460e19840849b99b5e4996ee90853a0d1ad5e5be5304cb76990ffd1e04680f7f2f85680ac62f529b5614031062e1c0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567cd0d22ac7bc0820ebcbc11b087c059c2d36b207d020a3987b21b56b11c2ca0982796fc953c1ebf14434ee0dffc225d87e12ca4506f07f0971e4fcd72bcbab2241c0000000000000000000000000000000000000000000011ce6ed6df09a64f08420000000000000000000000000000000000000000000000000000000067eba567c82350a2e16b70134ec057193550fd49b18e793604b1e4743fc01c2cae01f9b7631cdfa9033e2c414cf29451f916c482316673fd8be956a1d5ea5dc1791115c01b, 0x4254432f55534400000000000000000000000000000000000000000000000000) [delegatecall]
    	│   │   ├─ [60369] 0xc0931aEE1064BD5245fEe76A2d740eab8436621e::40366475(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f55534400000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000011ce4ebc2338797454e80000000000000000000000000000000000000000000000000000000067eba567c157813327ab23012c0c51d803a60fdeb2db3460e19840849b99b5e4996ee90853a0d1ad5e5be5304cb76990ffd1e04680f7f2f85680ac62f529b5614031062e1c0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567cd0d22ac7bc0820ebcbc11b087c059c2d36b207d020a3987b21b56b11c2ca0982796fc953c1ebf14434ee0dffc225d87e12ca4506f07f0971e4fcd72bcbab2241c0000000000000000000000000000000000000000000011ce6ed6df09a64f08420000000000000000000000000000000000000000000000000000000067eba567c82350a2e16b70134ec057193550fd49b18e793604b1e4743fc01c2cae01f9b7631cdfa9033e2c414cf29451f916c482316673fd8be956a1d5ea5dc1791115c01b0000000000000000000000000000000000000000000000) [staticcall]
    	│   │   │   ├─ [55380] 0xB2F863B68d85b198DDe2fE7da1D8baFdCFf199c0::40366475(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f55534400000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000011ce4ebc2338797454e80000000000000000000000000000000000000000000000000000000067eba567c157813327ab23012c0c51d803a60fdeb2db3460e19840849b99b5e4996ee90853a0d1ad5e5be5304cb76990ffd1e04680f7f2f85680ac62f529b5614031062e1c0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567cd0d22ac7bc0820ebcbc11b087c059c2d36b207d020a3987b21b56b11c2ca0982796fc953c1ebf14434ee0dffc225d87e12ca4506f07f0971e4fcd72bcbab2241c0000000000000000000000000000000000000000000011ce6ed6df09a64f08420000000000000000000000000000000000000000000000000000000067eba567c82350a2e16b70134ec057193550fd49b18e793604b1e4743fc01c2cae01f9b7631cdfa9033e2c414cf29451f916c482316673fd8be956a1d5ea5dc1791115c01b0000000000000000000000000000000000000000000000) [delegatecall]
    	│   │   │   │   ├─ [3000] PRECOMPILES::ecrecover(0x0a68e8365be00d0cd98a1171d18af4e3e1566fd09a59d61fe23743c2dbe50c12, 28, 87450987175619729345224437904190378668378471047311994984055329008011973683464, 37826109101770063310129024824192616189507182989479589014137121493233374922286) [staticcall]
    	│   │   │   │   │   └─ ← [Return] 0x0000000000000000000000006733d110a59dc160b5c8093066a7f5103885196f
    	│   │   │   │   ├─ [8142] ERC1967Proxy::55b5190b(7564662d76312e310000000000000000000000000000000000000000000000000000000000000000000000006733d110a59dc160b5c8093066a7f5103885196f) [staticcall]
    	│   │   │   │   │   ├─ [3246] 0xA7a8eAAA131dc4D2f70636F5F8796e640B119926::55b5190b(7564662d76312e310000000000000000000000000000000000000000000000000000000000000000000000006733d110a59dc160b5c8093066a7f5103885196f) [delegatecall]
    	│   │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
    	│   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
    	│   │   │   │   ├─ [3000] PRECOMPILES::ecrecover(0x14e205399af2fdf39cd5ba0d6d33d50ffbb0007a622f772edc16663e7de9cd57, 28, 92747342280930951330331743016924826142985862405571157083665267571049381011608, 17906971417906977260169118529732908076796855624976136117544900421598137987620) [staticcall]
    	│   │   │   │   │   └─ ← [Return] 0x000000000000000000000000be524616e96bb4b62cce8034ab6bea8f2505b55a
    	│   │   │   │   ├─ [3642] ERC1967Proxy::55b5190b(7564662d76312e31000000000000000000000000000000000000000000000000000000000000000000000000be524616e96bb4b62cce8034ab6bea8f2505b55a) [staticcall]
    	│   │   │   │   │   ├─ [3246] 0xA7a8eAAA131dc4D2f70636F5F8796e640B119926::55b5190b(7564662d76312e31000000000000000000000000000000000000000000000000000000000000000000000000be524616e96bb4b62cce8034ab6bea8f2505b55a) [delegatecall]
    	│   │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
    	│   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
    	│   │   │   │   ├─ [3000] PRECOMPILES::ecrecover(0xca613c8b1a20618b010d94a62a700c6e09917c2a8778a82c881f2be28d25a2b3, 27, 90524965894879087420297465183903263448359497350110207873450031945407891896759, 44829987373565001565186606953511927342046667061064660196284399196770407617984) [staticcall]
    	│   │   │   │   │   └─ ← [Return] 0x00000000000000000000000093b502d3eb45b9eae948f8fca01e64d9c0ba538a
    	│   │   │   │   ├─ [3642] ERC1967Proxy::55b5190b(7564662d76312e3100000000000000000000000000000000000000000000000000000000000000000000000093b502d3eb45b9eae948f8fca01e64d9c0ba538a) [staticcall]
    	│   │   │   │   │   ├─ [3246] 0xA7a8eAAA131dc4D2f70636F5F8796e640B119926::55b5190b(7564662d76312e3100000000000000000000000000000000000000000000000000000000000000000000000093b502d3eb45b9eae948f8fca01e64d9c0ba538a) [delegatecall]
    	│   │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
    	│   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
    	│   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567
    	│   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000011ce5ecc567d2b3ab1a20000000000000000000000000000000000000000000000000000000067eba567
    	│   │   ├─ emit VerifyAsSubscriberCalled(verifier: PullVerifierSub: [0x9Cd59BEbE8daBbb4a79739619a99DF890498305e], feedKey: 0x4254432f55534400000000000000000000000000000000000000000000000000)
    	│   │   └─ ← [Return] PriceUpdate({ price: 84087090417798546633122 [8.408e22], timestamp: 1743496551 [1.743e9] })
    	│   └─ ← [Return] PriceUpdate({ price: 84087090417798546633122 [8.408e22], timestamp: 1743496551 [1.743e9] })
    	└─ ← [Stop]
    
    
    Transaction successfully executed.
    Gas used: 125591
    

    True/false flag is token should be without any extensions (non-mintable, non-burnable, without fee, working by lock/unlock scheme). If true, other flags should be false

    True/false flag is token mintable by owner (owner can mint arbitrary token amount)

    True/false flag is token burnable (everyone can burn his tokens)

    True/false flag is token burnable by BURNER_ROLE role only

    True/false flag is token will supports fee extracting for bridging(currently unsupported, should be false by default)

    UTSRouter address on the deployment chain

    Array of initial destination chain IDs that token binded to

    Array of ChainConfig structs, initial settings

    Salt to deploy new token to specified address, you can specify it, if you want specific address

    Provided salt to deploy new connector to specified address

    Address encoded here will be setted as the owner of the token

    The name of new token

    The symbol of new token

    The decimals of new token

    Token initial supply, that will be minted

    Token supply, that will be minted to owner (must be less than or equal initialSupply)

    owner

    UTSConnector owner's address, encoded in bytes

    underlyingToken

    Address of the ERC20 token on top of which is UTSConnector built(you can also use a placeholder address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, if the desired connector have to interact with network native currency, e.g. Ether)

    feeModule

    True/false flag is connector will supports fee extracting for bridging(currently unsupported, should be false by default)

    router

    UTSRouter address

    allowedChainIds

    Array of initial destination chain IDs that connector binded to

    chainConfigs

    Array of ChainConfig structs, initial settings

    peerAddress

    Destination peer address, that can bridge or receive tokens to/from source chain. Normally it should be address of token/connector on destination chain

    minGasLimit

    Minimal gas amount that can be provided as function's input and will be used at redeem function

    decimals

    Destination peer token decimals

    paused

    True/false flag is destination peer paused

    dstChainId

    Destination chain Id (or current)

    isConnector

    True/false flag is specified params for deploy UTSConnector

    params

    encoded deployData (encoded DeployTokenData struct or encoded DeployConnectorData struct)

    Estimations
    Estimations

    salt

    /**
     * @notice Deploys a new {UTSToken} using the provided deployment parameters.
     * @param deployData the {DeployTokenData} struct containing deployment parameters.
     * @dev See the {UTSERC20DataTypes.DeployTokenData} for details.
     *
     * @return success call result.
     * @return newToken a newly deployed {UTSToken} contract address.
     */
    function deployToken(DeployTokenData calldata deployData)
    struct DeployTokenData {
        bytes     owner;
        string    name;
        string    symbol;
        uint8     decimals;
        uint256   initialSupply;
        uint256   mintedAmountToOwner;
        bool      pureToken;
        bool      mintable;
        bool      globalBurnable;
        bool      onlyRoleBurnable;
        bool      feeModule;
        bytes     router;
        uint256[] allowedChainIds;
        ChainConfig[] chainConfigs;
        bytes32   salt;
    }
    owner
    name
    symbol
    decimals
    initialSupply
    mintedAmountToOwner
    /**
     * @notice Deploys a new {UTSConnector} using the provided deployment parameters.
     * @param deployData the {DeployConnectorData} struct containing deployment parameters.
     * @dev See the {UTSERC20DataTypes.DeployConnectorData} for details.
     *
     * @return success call result.
     * @return newConnector a newly deployed {UTSConnector} contract address.
     */
    function deployConnector(DeployConnectorData calldata deployData)
    struct DeployConnectorData {
        bytes     owner;
        bytes     underlyingToken;
        bool      feeModule;
        bytes     router;
        uint256[] allowedChainIds;
        ChainConfig[] chainConfigs;
        bytes32   salt;
    }
    struct ChainConfig {
        bytes   peerAddress;
        uint32  minGasLimit;
        uint8   decimals;
        bool    paused;
    }
    /**
     * @notice Sends UTSToken and UTSConnector deployment crosschain requests via UTS protocol V1.
     * @param deployMetadata array of {DeployMetadata} structs, containing destination chain Ids and deploy parameters:
     *        dstChainId: destination chain Id
     *        isConnector: flag indicating whether is request for deploy connector(true) or token(false)
     *        params: abi.encoded {DeployTokenData} struct or abi.encoded {DeployConnectorData} struct
     * @dev See the {UTSERC20DataTypes.DeployTokenData} and {UTSERC20DataTypes.DeployConnectorData} for details.
     *
     * @param paymentToken address of the token used for payment.
     * @dev Any {paymentToken} address different from the {PAYMENT_TOKEN} is identified as a payment in native currency.
     *
     * @return paymentAmount total payment required for send deployment requests.
     * @return currentChainDeployment deployment address on the current chain (if a relevant request was provided).
     */
    function sendDeployRequest(
        DeployMetadata[] calldata deployMetadata,
        address paymentToken
    ) external payable whenNotPaused() returns(
        uint256 paymentAmount, 
        address currentChainDeployment
    )
    pureToken
    mintable
    globalBurnable
    onlyRoleBurnable
    feeModule
    router
    allowedChainIds
    chainConfigs
    salt

    EVM Smart Contracts

    In the Pull model, consumers include verification data about the most recent update directly in their transaction. This data is fetched from the oracle and verified within the same transaction before being used.

    This scheme comes with the following properties:

    1. Consumers always use the latest update in their transaction, so the price used in the transaction is as close to real time as protocol update frequency.

    2. The cost for maintaining update relevance on-chain relies on end-consumers. This allows the oracle protocol to have much larger set of assets.

    This guide will help developers who want to use Pull model (PAYG) within their contracts. It uses Hardhat for contract compilation, although similar methods apply with other frameworks.

    Step 1: Initialize new hardhat project

    In the first step, we are establishing a basic solidity development setup.

    Step 2: Write a contract that verifies an update in the transaction

    Now create a new PullVerifier contract, which utilizes the pullMarketplace.verifyWithFee function to verify the update information provided through calldata. The update contains oracle votes along with their signatures.

    Once the PullVerifier contract verifies the update against these inputs, it returns the verified value to the caller contract. If the verification fails (e.g., due to mismatched data, invalid signatures, or other inconsistencies) the contract reverts the entire transaction, ensuring that only valid data is accepted.

    Now that we have a contract, let's write a hardhat ignition script to deploy it.

    Step 3: Deploy the contract

    To deploy your contract on testnet, you'll need ETH eth_sepolia testnet tokens. You can obtain funds from public faucets (, , , , ).

    Now let's modify the hardhat configuration file to add the eth_sepolia network.

    Now we can deploy the PullVerifier contract by running the command below.

    Expected Result

    Step 4: Understanding update format and Finalized Data API

    At this point, the PullConsumer contract is ready to verify updates that we send it. But before doing that, let's quickly go through the update format and the data that it expects.

    As an example, let’s imagine you need BTC/USD price in your contract. First, we need to fetch the latest update from the Finalized Data backend service. This service constantly synchronizes its state with oracle's state and provides oracle data via convenient APIs (REST, WebSocket).

    Expected Result

    This response provides all necessary details to verify the BTC/USD update, specifically:

    • feeds: An array containing parsed update data for requested feeds.

    • votes: Publisher's latest votes on the specific feed. This aggregated array of votes is necessary to obtain agreed-upon value on-chain.

      • Value: The data that Publisher observed.

      • Timestamp:

    This data enables executing the transaction on the PullVerifier contract. To begin, fetch the latest update from the Finalized Data API for the BTC/USD price.

    Step 5: Send a transaction with the update data

    Now that we understand the Finalized Data API, we can create scripts to demonstrate update verification.

    First of all, we need to fund the PullVerifier contract, so it will be able to pay the verification fee. Copy the following code to the scripts/fundVerifier.ts file.

    Change the PullConsumerAddress to the address you got from deployment and execute the script to fund the deployed PullConsumer contract.

    Now we will need to create a script that retrieves an update from the API, parses the response, encodes it to EVM calldata, and sends a transaction to verify the update. The contract can then validate the update and incorporate the verified price into its on-chain logic.

    First, add the UDF SDK library. We will use it to fetch the update using the REST API and encode it for on-chain usage.

    Copy the script below to the scripts/fetchAndVerify.ts file.

    Don't forget to change the PullVerifierAddress to your contract address.

    Now let’s execute the script using the command below.

    Expected Result

    You can use cast to examine the transaction call trace and logs. The emitted event shows the latest update that we verified.

    Note that gas usage may vary depending on the result and the version of the library in use.

    Expected Result
    Timestamp at which the Publisher observed that data.
  • Publisher: Publisher's public key.

  • Signature: ECDSA signature for the observed value. This signature represents commitment from publisher that this data is what he observed.

  • Option 1
    Option 2
    Option 3
    Option 4
    Option 5
    yarn init -y
    # yarn initialization flow
    yarn add --dev hardhat
    yarn hardhat init
    # Hardhat initialization flow (select TypeScript project)
    ./contractrs/PullVerifier.sol
    // SPDX-License-Identifier: BSL1.1
    pragma solidity ^0.8.20;
    
    interface IPullMarketplace  {
            struct PriceUpdate {
            uint256 price;
            uint256 timestamp;
        }
        function verifyWithFee(
            bytes calldata updateData,
            bytes32 feedKey
        ) external payable returns (PriceUpdate memory);
        function getUpdateFee(uint256 nUpdates) external view returns (uint256);
        
    }
    contract PullVerifier {
        IPullMarketplace public pullMarketplace;
        uint public latestPrice;
        uint public latestTimestamp;
        constructor(address _pullMarketplace){
            pullMarketplace = IPullMarketplace(_pullMarketplace);
        }
        // @notice function that verifies feed from provided update PAYG through PullMarketplace and stores update data
        function VerifyPAYG(bytes calldata updateData, bytes32 feedKey) external{
    	  // Calculate required fee
            uint256 fee = pullMarketplace.getUpdateFee(1);
    	// Verify the update
            IPullMarketplace.PriceUpdate memory priceUpdate = pullMarketplace.verifyWithFee{value: fee}(updateData, feedKey);
    	// store update data
            latestPrice = priceUpdate.price;
            latestTimestamp = priceUpdate.timestamp;
        }
       
    
        // @notice deposit native tokens for fee coverage
       receive() payable external {}
    
    }
    
    ./ignition/modules/PullVerifier.ts
    import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
    
    // PullMarketplace address on Eth Sepolia network
    const PullMarketplaceAddress = "0xC6670092056e7bf56c3149FDE52A187b3e9f2e63";
    
    const PullVerifierModule = buildModule("PullVerifierModule", (m) => {
    	const consumer = m.contract("PullVerifier", [PullMarketplaceAddress ]);
    
    	return { consumer };
    });
    
    export default PullVerifierModule;
    ./hardhat.config.ts
    import { HardhatUserConfig } from "hardhat/config";
    import "@nomicfoundation/hardhat-toolbox";
    
    const config: HardhatUserConfig = {
      solidity: "0.8.28",
      networks: {
        eth_sepolia: {
            chainId: 11155111,
            // or http://127.0.0.1:8545, if you forked it locally
            url: "https://ethereum-sepolia-rpc.publicnode.com",
            accounts: [ "0x" ], // TODO: Set deployer private key
        },
      },
    };
    
    export default config;
    yarn hardhat ignition deploy ./ignition/modules/PullVerifier.ts --network eth_sepolia
    ✔ Confirm deploy to network eth_sepolia (11155111)? … yes
    Hardhat Ignition 🚀
    
    Resuming existing deployment from ./ignition/deployments/chain-11155111
    
    Deploying [ PullVerifierModule ]
    
    Batch #1
      Executed PullVerifierModule#PullVerifier
    
    [ PullVerifierModule] successfully deployed 🚀
    
    Deployed Addresses
    
    PullVerifierModule#PullVerifier - 0xBd0AFEE88B7FcEE6139467700D6f40F13FEDa739
    curl https://udfsnap.ent-dx.com/last_votes?feedKeys=BTC/USD
    {
      "update_call_data": "0x55444646014254432f555344000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000103c693478ddd1a5ff8b0000000000000000000000000000000000000000000000000000000067f3bd9da5c05745f7651d2c2c9f8771ff435193f2b0c719ca149e0b20ef4ecf0b0050c07d76ac34ec08947a026ad849ccce7f324c1d206140c0cf23411ae13f8e5b60121b00000000000000000000000000000000000000000000103c8289badcc4b240340000000000000000000000000000000000000000000000000000000067f3bd9de20d0d68fe93309786b18387c48bbfdd6d2ff03da78bc31294d25b3363a988491f75e29da2c99e3a39bc9afd8bf3072f1c39fe1bfb00033a73af48ba7ad7bf291b00000000000000000000000000000000000000000000103c84ecee2483ad3be70000000000000000000000000000000000000000000000000000000067f3bd9d9ed7b8ba15718887607d52853a12de16bd79d6bf8df3c29a051561d42fe6b160208c1cc24ac7c186fad1f70828be7bbbd66fe7c090193223f788c652ebc127071b",
      "feeds": [
        {
          "feed_key": "BTC/USD",
          "votes": [
            {
              "Value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAABA8aTR43dGl/4s=",
              "Timestamp": 1744027037,
              "Publisher": "0x6733D110A59Dc160b5C8093066A7f5103885196F",
              "Signature": {
                "R": "0xa5c05745f7651d2c2c9f8771ff435193f2b0c719ca149e0b20ef4ecf0b0050c0",
                "S": "0x7d76ac34ec08947a026ad849ccce7f324c1d206140c0cf23411ae13f8e5b6012",
                "V": 27
              }
            },
            {
              "Value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAABA8gom63MSyQDQ=",
              "Timestamp": 1744027037,
              "Publisher": "0xbe524616e96bb4b62ccE8034AB6beA8F2505B55a",
              "Signature": {
                "R": "0xe20d0d68fe93309786b18387c48bbfdd6d2ff03da78bc31294d25b3363a98849",
                "S": "0x1f75e29da2c99e3a39bc9afd8bf3072f1c39fe1bfb00033a73af48ba7ad7bf29",
                "V": 27
              }
            },
            {
              "Value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAABA8hOzuJIOtO+c=",
              "Timestamp": 1744027037,
              "Publisher": "0x93b502d3eb45b9EAE948F8Fca01E64D9c0BA538a",
              "Signature": {
                "R": "0x9ed7b8ba15718887607d52853a12de16bd79d6bf8df3c29a051561d42fe6b160",
                "S": "0x208c1cc24ac7c186fad1f70828be7bbbd66fe7c090193223f788c652ebc12707",
                "V": 27
              }
            }
          ]
        }
      ]
    }
    ./scripts/fundVerifier.ts
    import { ethers } from "hardhat";
    
    // PullVerifier contract address on ETH Sepolia
    const PullVerifierAddress = "0xBd0AFEE88B7FcEE6139467700D6f40F13FEDa739";
    
    async function main() {
    
      // Use default hardhat signer to fund the PullConsumer contract
      const [funder] = await ethers.getSigners();
    
      // 0.0003 is the exact cost for 10 updates on eth_seoplia
      const depositAmount = ethers.parseEther("0.0003");
    
      // Send funding transaction
      const tx = await funder.sendTransaction({
        to: PullVerifierAddress ,
        value: depositAmount
      });
      await tx.wait();
    
      console.log(`sent ${depositAmount} to PullVerifier, tx: ${tx.hash}`);
    }
    
    main()
      .then(() => process.exit(0))
      .catch(error => {
        console.error(error);
        process.exit(1);
      });
    
    yarn hardhat run ./scripts/fundVerifier.ts --network eth_sepolia
    yarn add --dev @entangle-labs/udf-sdk
    scripts/fetchAndVerify.ts
    import { ethers } from "hardhat";
    import {
      PullVerifier,
    } from "../typechain-types";
    import { UdfSdk } from '@entangle-labs/udf-sdk';
    
    // PullVerifier contract address on ETH Sepolia
    const PullVerifierAddress = "0xBd0AFEE88B7FcEE6139467700D6f40F13FEDa739";
    
    async function main() {
    
      // Fetch the update data from finalized-data-snap
      const sdk = new UdfSdk();
      const updateData = await sdk.getCallData(["BTC/USD"]);
      const feedKey = ethers.encodeBytes32String("BTC/USD");
    
      // Bind PullVerifier contract on the network
      const verifier = await ethers.getContractAt(
        "PullVerifier",
        PullVerifierAddress
      );
    
      // Send verify transaction
      let tx = await verifier.VerifyPAYG(
        updateData,feedKey 
      );
      await tx.wait();
      console.log("sent tx:", tx.hash);
      let price = await verifier.latestPrice();
      let timestamp = await verifier.latestTimestamp();
      console.log("price:", price );
      console.log("timestamp:", timestamp );
    }
    
    main()
      .then(() => process.exit(0))
      .catch(error => {
        console.error(error);
        process.exit(1);
      });
    yarn hardhat run ./scripts/fetchAndVerify.ts --network eth_sepolia
    sent tx: 0xb66fb4112b7fdf72211c2238b9b0a609a8321e2694ddad9b69ec7dcc953fdb18
    price: 76683771643884818373141n
    timestamp: 1744027087n
    cast run 0xb66fb4112b7fdf72211c2238b9b0a609a8321e2694ddad9b69ec7dcc953fdb18 -r https://eth-sepolia.public.blastapi.io
    Executing previous transactions from the block.
    Traces:
      [137017] 0xBd0AFEE88B7FcEE6139467700D6f40F13FEDa739::2e37a79c(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f555344000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000103d081c72d9f475f0bd0000000000000000000000000000000000000000000000000000000067f3bdcf2e2ffc130ee5e218e62e5babe2b2c6d0fa30f07c44b3eb131bf32e8dbda99b1e419e4016c33066e7f736958fb849a20edf1f84ecc71acd6ebe1a822142d7276a1c00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf27ef18a4bb82a9d25c7384e5dc40a992a8f6c85d4099d9f77c2833641e91bef96f8c7f3e4296ad701dbd2d93ed345fde78bcbd6c430b5294b81be0eccce83efa1b00000000000000000000000000000000000000000000103d09c19608a94bf2d10000000000000000000000000000000000000000000000000000000067f3bdcf9240ac502823b0d89ec923abcd895508c38ff00f763332d89a5b5acb292600632af57fc4382aa10b59e95d963dd2f39072ba9133186af6c73b939a1a5b6afd371b0000000000000000000000000000000000000000000000)
        ├─ [8177] 0xC6670092056e7bf56c3149FDE52A187b3e9f2e63::getUpdateFee(1) [staticcall]
        │   ├─ [3284] 0xF9E8AEE871D1e9cED62702050F16E0660a88645a::getUpdateFee(1) [delegatecall]
        │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000001b48eb57e000
        │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000001b48eb57e000
        ├─ [70181] 0xC6670092056e7bf56c3149FDE52A187b3e9f2e63::b90ffe1f{value: 30000000000000}(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f555344000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000103d081c72d9f475f0bd0000000000000000000000000000000000000000000000000000000067f3bdcf2e2ffc130ee5e218e62e5babe2b2c6d0fa30f07c44b3eb131bf32e8dbda99b1e419e4016c33066e7f736958fb849a20edf1f84ecc71acd6ebe1a822142d7276a1c00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf27ef18a4bb82a9d25c7384e5dc40a992a8f6c85d4099d9f77c2833641e91bef96f8c7f3e4296ad701dbd2d93ed345fde78bcbd6c430b5294b81be0eccce83efa1b00000000000000000000000000000000000000000000103d09c19608a94bf2d10000000000000000000000000000000000000000000000000000000067f3bdcf9240ac502823b0d89ec923abcd895508c38ff00f763332d89a5b5acb292600632af57fc4382aa10b59e95d963dd2f39072ba9133186af6c73b939a1a5b6afd371b0000000000000000000000000000000000000000000000)
        │   ├─ [69692] 0xF9E8AEE871D1e9cED62702050F16E0660a88645a::b90ffe1f{value: 30000000000000}(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f555344000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000103d081c72d9f475f0bd0000000000000000000000000000000000000000000000000000000067f3bdcf2e2ffc130ee5e218e62e5babe2b2c6d0fa30f07c44b3eb131bf32e8dbda99b1e419e4016c33066e7f736958fb849a20edf1f84ecc71acd6ebe1a822142d7276a1c00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf27ef18a4bb82a9d25c7384e5dc40a992a8f6c85d4099d9f77c2833641e91bef96f8c7f3e4296ad701dbd2d93ed345fde78bcbd6c430b5294b81be0eccce83efa1b00000000000000000000000000000000000000000000103d09c19608a94bf2d10000000000000000000000000000000000000000000000000000000067f3bdcf9240ac502823b0d89ec923abcd895508c38ff00f763332d89a5b5acb292600632af57fc4382aa10b59e95d963dd2f39072ba9133186af6c73b939a1a5b6afd371b0000000000000000000000000000000000000000000000) [delegatecall]
        │   │   ├─ [60369] 0xc0931aEE1064BD5245fEe76A2d740eab8436621e::40366475(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f555344000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000103d081c72d9f475f0bd0000000000000000000000000000000000000000000000000000000067f3bdcf2e2ffc130ee5e218e62e5babe2b2c6d0fa30f07c44b3eb131bf32e8dbda99b1e419e4016c33066e7f736958fb849a20edf1f84ecc71acd6ebe1a822142d7276a1c00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf27ef18a4bb82a9d25c7384e5dc40a992a8f6c85d4099d9f77c2833641e91bef96f8c7f3e4296ad701dbd2d93ed345fde78bcbd6c430b5294b81be0eccce83efa1b00000000000000000000000000000000000000000000103d09c19608a94bf2d10000000000000000000000000000000000000000000000000000000067f3bdcf9240ac502823b0d89ec923abcd895508c38ff00f763332d89a5b5acb292600632af57fc4382aa10b59e95d963dd2f39072ba9133186af6c73b939a1a5b6afd371b0000000000000000000000000000000000000000000000) [staticcall]
        │   │   │   ├─ [55380] 0xB2F863B68d85b198DDe2fE7da1D8baFdCFf199c0::40366475(00000000000000000000000000000000000000000000000000000000000000404254432f5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a955444646014254432f555344000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000103d081c72d9f475f0bd0000000000000000000000000000000000000000000000000000000067f3bdcf2e2ffc130ee5e218e62e5babe2b2c6d0fa30f07c44b3eb131bf32e8dbda99b1e419e4016c33066e7f736958fb849a20edf1f84ecc71acd6ebe1a822142d7276a1c00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf27ef18a4bb82a9d25c7384e5dc40a992a8f6c85d4099d9f77c2833641e91bef96f8c7f3e4296ad701dbd2d93ed345fde78bcbd6c430b5294b81be0eccce83efa1b00000000000000000000000000000000000000000000103d09c19608a94bf2d10000000000000000000000000000000000000000000000000000000067f3bdcf9240ac502823b0d89ec923abcd895508c38ff00f763332d89a5b5acb292600632af57fc4382aa10b59e95d963dd2f39072ba9133186af6c73b939a1a5b6afd371b0000000000000000000000000000000000000000000000) [delegatecall]
        │   │   │   │   ├─ [3000] PRECOMPILES::ecrecover(0x6f256b7d268ebd1218609a792f492fed69e60f9b2bbb7a6aa535dd7eb100cb0a, 28, 20891172600762156370158823662620543704900665111721513626205233704845164780318, 29679939319588129535545874401977999632529215185806134268849298554013395396458) [staticcall]
        │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000006733d110a59dc160b5c8093066a7f5103885196f
        │   │   │   │   ├─ [8142] 0x996520f9717f6141e53D8083168027d7834c172f::55b5190b(7564662d76312e310000000000000000000000000000000000000000000000000000000000000000000000006733d110a59dc160b5c8093066a7f5103885196f) [staticcall]
        │   │   │   │   │   ├─ [3246] 0xA7a8eAAA131dc4D2f70636F5F8796e640B119926::55b5190b(7564662d76312e310000000000000000000000000000000000000000000000000000000000000000000000006733d110a59dc160b5c8093066a7f5103885196f) [delegatecall]
        │   │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
        │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
        │   │   │   │   ├─ [3000] PRECOMPILES::ecrecover(0x8b9e9727843f84ccc91c0597d691d6605a1747bc2d35a5d80ed49bae125b3559, 27, 18062647626320149720686750389925445179000734462126404388533040417546752343801, 50454962982126875055591883219065593480805620376717083982408678482645524954874) [staticcall]
        │   │   │   │   │   └─ ← [Return] 0x00000000000000000000000093b502d3eb45b9eae948f8fca01e64d9c0ba538a
        │   │   │   │   ├─ [3642] 0x996520f9717f6141e53D8083168027d7834c172f::55b5190b(7564662d76312e3100000000000000000000000000000000000000000000000000000000000000000000000093b502d3eb45b9eae948f8fca01e64d9c0ba538a) [staticcall]
        │   │   │   │   │   ├─ [3246] 0xA7a8eAAA131dc4D2f70636F5F8796e640B119926::55b5190b(7564662d76312e3100000000000000000000000000000000000000000000000000000000000000000000000093b502d3eb45b9eae948f8fca01e64d9c0ba538a) [delegatecall]
        │   │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
        │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
        │   │   │   │   ├─ [3000] PRECOMPILES::ecrecover(0x58a2d42e31439b65105206f2c0eaf9da88c41c7ca83b26422134baee5517faa0, 27, 66151943366697264661083307274467456252907404044355893425437843030218939695203, 19430898983218506555122872121129293766952693229336645534639974540211705806135) [staticcall]
        │   │   │   │   │   └─ ← [Return] 0x000000000000000000000000be524616e96bb4b62cce8034ab6bea8f2505b55a
        │   │   │   │   ├─ [3642] 0x996520f9717f6141e53D8083168027d7834c172f::55b5190b(7564662d76312e31000000000000000000000000000000000000000000000000000000000000000000000000be524616e96bb4b62cce8034ab6bea8f2505b55a) [staticcall]
        │   │   │   │   │   ├─ [3246] 0xA7a8eAAA131dc4D2f70636F5F8796e640B119926::55b5190b(7564662d76312e31000000000000000000000000000000000000000000000000000000000000000000000000be524616e96bb4b62cce8034ab6bea8f2505b55a) [delegatecall]
        │   │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
        │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
        │   │   │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf
        │   │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf
        │   │   ├─  emit topic 0: 0xc721ed5888a17a766f8018cb6748b49a685bdec1837b10b49c8c56de9e4d5618
        │   │   │           data: 0x000000000000000000000000bd0afee88b7fcee6139467700d6f40f13feda7394254432f55534400000000000000000000000000000000000000000000000000
        │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf
        │   └─ ← [Return] 0x00000000000000000000000000000000000000000000103d091c76140eff9a150000000000000000000000000000000000000000000000000000000067f3bdcf
        └─ ← [Stop] 
    
    
    Transaction successfully executed.
    Gas used: 163365

    Data Endpoints

    The table below lists the contract addresses for the UDF Push and Pull marketplace contracts across supported networks. These addresses must be used during integration. They serve as the interaction points for accessing UDF services on specific blockchains.

    When implementing your integration, ensure that the correct address for the target network is referenced in your code.

    Marketplace Contract Addresses

    Chain
    PushMarketplace
    PullMarketplace

    Assets

    The table below provides the contract addresses for supported assets across various networks. These addresses represent the deployed instances of the assets within Entangle’s ecosystem.

    Note that assets are encoded in the bytes32 EVM format using their ASCII representation converted to hexadecimal. You can perform this conversion using the below CLI commands with Python or cast. Simply replace NGL/USD in the command with the asset you are using.

    In the output you should expect NGL/USD to be encoded as 0x4e474c2f55534400000000000000000000000000000000000000000000000000

    Feed key
    Data Key
    Aggregator Link

    sonic

    arbitrum

    blast

    polygon

    optimism

    linea

    ethereum

    binance bnb

    monad_testnet

    mantle_sepolia

    abstract

    AIXBT/USD

    0x41495842542f5553440000000000000000000000000000000000000000000000

    APT/USD

    0x4150542F55534400000000000000000000000000000000000000000000000000

    AVAX/USD

    0x415641582F555344000000000000000000000000000000000000000000000000

    BCH/USD

    0x4243482F55534400000000000000000000000000000000000000000000000000

    BERA/USD

    0x424552412F555344000000000000000000000000000000000000000000000000

    BICO/USD

    0x4249434F2F555344000000000000000000000000000000000000000000000000

    BNB/USD

    0x424E422F55534400000000000000000000000000000000000000000000000000

    BTC/USD

    0x4254432F55534400000000000000000000000000000000000000000000000000

    CGPT/USD

    0x434750542F555344000000000000000000000000000000000000000000000000

    DAI/USD

    0x4441492F55534400000000000000000000000000000000000000000000000000

    DOGE/USD

    0x444F47452F555344000000000000000000000000000000000000000000000000

    DOT/USD

    0x444F542F55534400000000000000000000000000000000000000000000000000

    ENJ/USD

    0x454E4A2F55534400000000000000000000000000000000000000000000000000

    ERN/USD

    0x45524E2F55534400000000000000000000000000000000000000000000000000

    ,

    ETH/USD

    0x4554482F55534400000000000000000000000000000000000000000000000000

    FET/USD

    0x4645542F55534400000000000000000000000000000000000000000000000000

    FTM/USD

    0x46544D2F55534400000000000000000000000000000000000000000000000000

    GLMR/USD

    0x474c4d522f555344000000000000000000000000000000000000000000000000

    GORPLES/USD

    0x474F52504C45532F555344000000000000000000000000000000000000000000

    HYPE/USD

    0x485950452f555344000000000000000000000000000000000000000000000000

    ICP/USD

    0x4943502F55534400000000000000000000000000000000000000000000000000

    IMX/USD

    0x494D582F55534400000000000000000000000000000000000000000000000000

    LINK/USD

    0x4C494E4B2F555344000000000000000000000000000000000000000000000000

    LTC/USD

    0x4C54432F55534400000000000000000000000000000000000000000000000000

    MANA/USD

    0x4D414E412F555344000000000000000000000000000000000000000000000000

    MANTA/USD

    0x4D414E54412F5553440000000000000000000000000000000000000000000000

    MELANIA/USD

    0x4D454C414E49412F555344000000000000000000000000000000000000000000

    MNT/USD

    0x4D4E542F55534400000000000000000000000000000000000000000000000000

    MOVE/USD

    0x4d4f56452f555344000000000000000000000000000000000000000000000000

    MOVR/USD

    0x4d4f56522f555344000000000000000000000000000000000000000000000000

    NEAR/USD

    0x4E4541522F555344000000000000000000000000000000000000000000000000

    NGL/USD

    0x4E474C2F55534400000000000000000000000000000000000000000000000000

    PEPE/USD

    0x504550452F555344000000000000000000000000000000000000000000000000

    POL/USD

    0x504F4C2F55534400000000000000000000000000000000000000000000000000

    QUAI/USD

    0x515541492f555344000000000000000000000000000000000000000000000000

    RENDER/USD

    0x52454E4445522F55534400000000000000000000000000000000000000000000

    RLUSD/USD

    0x524C5553442F5553440000000000000000000000000000000000000000000000

    RON/USD

    0x524f4e2f55534400000000000000000000000000000000000000000000000000

    ROSE/USD

    0x524F53452F555344000000000000000000000000000000000000000000000000

    S/USD

    0x532F555344000000000000000000000000000000000000000000000000000000

    SAND/USD

    0x53414E442F555344000000000000000000000000000000000000000000000000

    SHIB/USD

    0x534849422F555344000000000000000000000000000000000000000000000000

    SOL/USD

    0x534F4C2F55534400000000000000000000000000000000000000000000000000

    STX/USD

    0x5354582F55534400000000000000000000000000000000000000000000000000

    SUI/USD

    0x5355492F55534400000000000000000000000000000000000000000000000000

    SUPER/USD

    0x53555045522F5553440000000000000000000000000000000000000000000000

    sUSDS/USD

    0x73555344532F5553440000000000000000000000000000000000000000000000

    TAO/USD

    0x54414F2F55534400000000000000000000000000000000000000000000000000

    TON/USD

    0x544F4E2F55534400000000000000000000000000000000000000000000000000

    TRUMP/USD

    0x5452554D502F5553440000000000000000000000000000000000000000000000

    TRX/USD

    0x5452582F55534400000000000000000000000000000000000000000000000000

    UNI/USD

    0x554E492F55534400000000000000000000000000000000000000000000000000

    USD0/USD

    0x555344302f555344000000000000000000000000000000000000000000000000

    USDS/USD

    0x555344532F555344000000000000000000000000000000000000000000000000

    VIRTUAL/USD

    0x5649525455414c2f555344000000000000000000000000000000000000000000

    WLD/USD

    0x574C442F55534400000000000000000000000000000000000000000000000000

    XLM/USD

    0x584C4D2F55534400000000000000000000000000000000000000000000000000

    XRP/USD

    0x5852502F55534400000000000000000000000000000000000000000000000000

    ZEREBRO/USD

    0x5a45524542524f2f555344000000000000000000000000000000000000000000

    base

    0x6D1713055B3060F67a999AfE491EA09a437a4CE9

    0xCcEad89c78F8B258D594e92BdA00E924983Cf53c

    eth_sepolia

    0x48A10FF4ea77A099Cc966b537b5efC5b15c1060A

    0xC6670092056e7bf56c3149FDE52A187b3e9f2e63

    mantle

    0x24a4569Df777A14027516b4ed02116c026ebE8B2

    0x1b4C2D4828C7040B9197718AfAc0A1408d362d84

    quai

    0x00211C841e8b76112a14e4EF282c9938Ee5C6016

    0x0069B5F77f4b9E2Deee35A43cA322958b942e7b7

    quai_orchard_testnet

    0x0076FaF63BB27e8c18FaaC92faE26125c42E08B9

    0x003905DD0636A20FE4f2294f26ECE55d00B2c700

    berachain

    5IRE/USD

    0x354952452F555344000000000000000000000000000000000000000000000000

    coingecko

    AAVE/USD

    0x414156452F555344000000000000000000000000000000000000000000000000

    coingecko

    ADA/USD

    0x4144412F55534400000000000000000000000000000000000000000000000000

    coingecko

    AIT/USD

    0x4149542F55534400000000000000000000000000000000000000000000000000

    python -c "import sys; print(\"0x%s\" % sys.argv[1].encode('ascii').ljust(32,b'\x00').hex())" NGL/USD
    cast format-bytes32-string NGL/USD
    0x293Eb14Cc1F3BfAEeB51Abc772852f8942846759
    0xf74570766569AB72b624b33A092143f1cE6CA56A
    0x9bBDea6b42014240328ec4ff31f80A940714164c
    0x293Eb14Cc1F3BfAEeB51Abc772852f8942846759
    0x996520f9717f6141e53D8083168027d7834c172f
    0xc0931aEE1064BD5245fEe76A2d740eab8436621e
    0x29DB51bd5c979aF4307e73611eFA56C3401F8013
    0x1Cb2Ba92285401fFaCd258f57635d436De55F460
    0x29DB51bd5c979aF4307e73611eFA56C3401F8013
    0x1Cb2Ba92285401fFaCd258f57635d436De55F460
    0xea8AfF5fA7d35ab8f77e018CB5073F9b4DCB9065
    0x24a4569Df777A14027516b4ed02116c026ebE8B2
    0x24a4569Df777A14027516b4ed02116c026ebE8B2
    0x1b4C2D4828C7040B9197718AfAc0A1408d362d84
    0xf74570766569AB72b624b33A092143f1cE6CA56A
    0xB2F863B68d85b198DDe2fE7da1D8baFdCFf199c0
    0x1Cb2Ba92285401fFaCd258f57635d436De55F460
    0xA7a8eAAA131dc4D2f70636F5F8796e640B119926
    0x293Eb14Cc1F3BfAEeB51Abc772852f8942846759
    0xf74570766569AB72b624b33A092143f1cE6CA56A
    0x293Eb14Cc1F3BfAEeB51Abc772852f8942846759
    0xf74570766569AB72b624b33A092143f1cE6CA56A
    0x108bbF719032d088D9c7f3d899738A3685757fd6
    0xFB36363e44aB688E2D104035941991166CAa00Af
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coinmarketcap
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko
    coingecko