One sample use case for the Tellor Pull flow: borrow TRB against Sepolia ETH collateral, then repay TRB to reclaim collateral. The frontend pulls ETH/USD and TRB/USD from the Tellor Layer API, automatically updates the DataBridge validator set if needed (skip relay), and includes attestations in the borrow transaction. The contract verifies via Tellor's DataBridge and applies an 80% LTV.
- Connect wallet (Sepolia)
- Enter collateral (ETH) and borrow amount (TRB)
- Borrow runs: check bridge validator set → pull oracle data → encode for EVM →
borrow(amount, ethAttest, trbAttest, validators, ethSigs, trbSigs) - Repay runs: approve TRB spend →
repay(amount)→ collateral returned proportionally
- User clicks Borrow in the frontend.
- Frontend reads the DataBridge's
validatorTimestamp()and compares with the Tellor Layer API's current validator set timestamp. - If the bridge is behind, the frontend fetches validator set update data and calls
dataBridge.updateValidatorSet()— using skip relay logic to jump as far forward as possible in a single update. - Frontend calls Tellor Layer API for both ETH/USD and TRB/USD:
getPullPayload(queryId, TELLOR_LAYER_API)→encodeBridgeCallArgsFromPayload(payload). - Frontend sends tx:
contract.borrow(amountTrbWei, ethAttestData, trbAttestData, validators, ethSigs, trbSigs, { value: collateralWei }). - Contract verifies both attestations via
dataBridge.verifyOracleData(...), decodes prices, checks LTV, tracks the position, and transfers TRB to the user.
- User clicks Repay in the frontend.
- Frontend approves the borrow contract to spend TRB (if needed).
- Frontend sends tx:
contract.repay(amountTrbWei). - Contract returns ETH collateral proportionally (partial or full repay supported).
The pull oracle model means the frontend is responsible for keeping the DataBridge's validator set current. If the bridge falls behind by multiple validator rotations, the skip relay logic:
- Reads the bridge's current trusted state (timestamp, power threshold, checkpoint)
- Tries to jump directly to the latest validator set
- If not enough signing power from the bridge's current trusted set, walks backward to find the furthest reachable target
- Repeats until fully caught up (up to 10 hops)
See tellorPull.js → getValsetUpdatePayloads() for the implementation.
SampleTellorUserPull/
├── README.md
├── docs/
│ └── borrow-ui.png
├── hardhat/
│ ├── contracts/
│ │ ├── BorrowWithTellorPull.sol
│ │ ├── interfaces/ITellorDataBridge.sol
│ │ └── testing/ # MockERC20, MockTellorDataBridge
│ ├── scripts/deploy.js
│ ├── test/BorrowWithTellorPull.test.js
│ ├── hardhat.config.js
│ ├── .env # SEPOLIA_PRIVATE_KEY, ETHERSCAN_API_KEY, etc.
│ └── package.json
└── frontend/
├── src/
│ ├── App.jsx # Connect + Borrow + Repay + position display
│ ├── tellorPull.js # Oracle pull helpers + skip relay
│ ├── contracts/
│ │ ├── borrowAbi.json
│ │ └── dataBridgeAbi.json
│ └── index.css
├── vite.config.js # Dev proxy for CORS
├── .env # VITE_BORROW_CONTRACT_ADDRESS, VITE_TRB_ADDRESS, etc.
└── package.json
cd hardhat
npm install
npx hardhat testDeploy to Sepolia:
# Set in hardhat/.env:
# SEPOLIA_PRIVATE_KEY=<deployer wallet private key>
# SEPOLIA_RPC_URL=https://1rpc.io/sepolia
# ETHERSCAN_API_KEY=<your etherscan api key>
# TRB_ADDRESS=<sepolia TRB address, or leave blank to deploy MockERC20>
npx hardhat run scripts/deploy.js --network sepoliaOn Sepolia, deploy uses TellorPlayground (TRBP) at 0x06BA179F22Bb34314ade96E96fa41C7951b2A731 — shows on Etherscan. Local Hardhat still deploys MockERC20.
The script funds the borrow pool with 10,000 TRBP by default (10× faucet calls). Override with FUND_AMOUNT=50000.
# Deploy (Sepolia → TellorPlayground + auto-fund pool)
npx hardhat run scripts/deploy.js --network sepolia
# Re-fund pool
BORROW=<borrow> TRB=0x06BA179F22Bb34314ade96E96fa41C7951b2A731 npx hardhat run scripts/fund.js --network sepolia
# Faucet TRBP to your wallet (1000 per call; for repay)
FAUCET_TO=<wallet> FAUCET_TIMES=2 npx hardhat run scripts/faucet.js --network sepoliaFrontend: “Get 1000 TRBP (TellorPlayground faucet)” after connecting wallet.
cd frontend
npm installSet in frontend/.env:
VITE_BORROW_CONTRACT_ADDRESS=<deployed borrow contract>
VITE_TRB_ADDRESS=<TRB token address>
VITE_TELLOR_LAYER_API=<tellor layer REST API base URL>
VITE_SEPOLIA_RPC_URL=https://1rpc.io/sepolia
npm run devOpen the URL, connect wallet (Sepolia), and test borrow + repay.
- Tellor Layer pull: tellor-io/tellor-layer-pull
- DataBridge: Deployed per Tellor Layer chain. The bridge's
VALIDATOR_SET_HASH_DOMAIN_SEPARATORis chain-specific (keccak256(abi.encode("checkpoint", CHAIN_ID))). - Skip relay pattern: See
docs/SKIP_VALSET_RELAYS.mdfor the full spec on validator set skip relays. - Sample structure: sample-tellor-layer-pull
