Security Considerations when using Pull Oracles

DeFi Security Summit 2024 · 8 Nov 2024 · 22:45

0xmonsoon, a security researcher at OpenZeppelin, explains how pull oracles differ from push oracles and the risks they add for integrating protocols. Because the user transmits the price with the transaction, pull oracles are cheaper to run and reach more chains, but they bring integration errors, stale data and price manipulation. He walks through Pyth and Redstone integration patterns and how multicall flows update a price before a borrow.

Speakers

Topics

From DeFi Security Summit 2024, hosted by DeFi Security Summit.

Transcript

all right good morning um I'm zerx Monsoon um I'm a security researcher at open Zeppelin I'm also a member of seal 911 and um today I'll talk about po oracles um how to integrate them what are they and some security considerations uh when you're building or architecting your protocol and some tips this could also be useful for Auditors but this is uh mostly meant for developers all right let's start so blockchains are very good uh when you

only have to deal with intrinsic data so they're basically a computer a database without any internet connection uh so you cannot access external data there's no post methods or get methods in blockchains so so the problem is if you're building apps uh for normal users you'll have to get data from outside uh there's tons of data available u natively in blockchains but that would mostly be balances of users token prices using um uh amm but uh if you have

to imagine build a stock market mirroring platform you'll have to get you'll have to need you'll have to use an oracle to get those stock prices from outside if you're building a lending Market let's say you'll have to get asset prices um if you're if you're building a prediction Market you'll have to use an oracle to actually get the data transmitted to the blockchain uh that how that um what the outcome of that event was to settle the close the prediction market so so that's the that's the problem we're dealing with getting data to the blockchain because that uh makes it more

useful for everyday users so there have been multiple ways people have been trying to get um external data to the blockchain um it all started uh with push oracles then slowly uh different other types of oracles Al also came into the picture like Onin oracles and most recently pull oracles so uh let's first start about push oracles and how they work so a push Oracle is very simple um what happens is whenever a user needs to interact with an app uh they just send a transaction to the app

Smart contract and that in turn reads data from the Oracle smart contract the responsibility of updating the Oracle smart contract uh is with the with whatever Oracle Network you're using so let's say Chronicle or chain link they'll continuously um update the prices or whatever other data you're using uh in their Oracle smart contract and you can directly just call this so push oracles are basically the oldest uh uh they started it started with Chronicle that was the first push Oracle

then chain link came into the picture and tons of other other ones [Music] and they are responsible for the most tvl uh secured they are the easiest to integrate with because all you need to do is call a certain smart contract with their interface a specific function of a certain smart contract and you could get the data [Music] and um sorry yes so basically this makes it very easy to integrate like all you need to do is just call a certain smart contract and but the problem with push oracles is it's very expensive to

operate because someone needs to Bear the transaction cost cost of continuously updating the push oracles push oracles actually work on um either price deviation thresholds or time thresholds so the data on the Oracle smart contract will be let's say updated every 1 hour or something or if it let's say de the price deviates by 5% or something so uh the Oracle Network constantly needs to send transactions to the smart cont contract for every data feed that they have on every Network so it makes it very hard uh and very

expensive for them to um support a lot of different data feeds on a lot of different chains so um let's let's come to what are P oracles so what happens when you use a pull Oracle is the user the end user themselves are responsible for transmitting the data or Price whatever you want to use onto the blockchain itself so uh what happens is imagine I'm a user and I want to interact with a with a app with a Dap so I'll first get

the price from the Oracle networks Network or server I'll retrieve the price from there I'll bundle it with my transaction and I'll send it to my app Smart contract whatever app I'm uh I'm going to use and that app uh will verify the data the whatever the price load is the price uh the payload is uh using the Oracle Network smart contract or it verifies it internally there are two different modes we'll talk about it so the benefits of using a pull Oracle is um it can support a a higher number of chains and

um and pairs because uh the Oracle network isn't responsible for transmitting the data so it doesn't have to bear the cost the cost uh rests with the user so pull oracles are classified can be classified in two ways by either execution patterns or by the payload validation method so sometimes some types of Po oracles have Atomic execution so you deliver the price in the same transaction uh where the transaction is supposed to be executed so let's say I want to

borrow um from a lending protocol so I'll give the price of all the Assets in the same transaction and and I'll also borrow in the same transaction so the execution happens automically then there's also another pattern that's uh in which the execution is deferred so what happens is um I'll intent to the DB smart contract that I want to make such a certain transaction let's say I want to open a position on a certain market so I'll uh I'll send a transaction indicating so the uh the app will record uh that I want to make this

transaction and it will emit an event with all the data fields then anyone can act as a resolver and send a transaction in the next block with the price what this helps with is it prevents front running so this is uh popularly used by GMX so that uh the transactions that users send to GMX aren't front run then we can also classify pull oracles by the payload validation method sometime in some types of Po oracles uh when you send a update payload they are externally validated by an external smart contract which is

usually the Oracle Network smart contract so if I send an update um payload to a Dap the DAP will in turn call the oracle Network smart contract and that will uh validate the payload uh there's another way uh in which you can internally validate uh the payload some some po oracles support this in which you basically integrate a library uh um you do this by inheriting their smart contracts and their uh the smart the library smart contracts basically validate all the signatures that you have sent and if a certain threshold is met

uh the price is validated for you so this basically gives us like four types of polares so like pith is an example of a polar Oracle that's externally validated by the Oracle Network itself but supports Atomic execution um the chain link data stream used by GMX is an example of externally validated uh polar oricle in which uh the execution is deferred so the price is uh transmitted to the blockchain in another transaction and not in the same one then you have internally validated um polar orles so Redstone is a prime

example so the Redstone pull Oracle supports Atomic uh execution and the Redstone x uh works just like chain link data stream uh and it supports deferred execution the only difference is uh you have to inherit the smart contracts of redstone to do the validation inside your D itself so this is uh pseudo code basically to integrate pth so as you could see in this uh example method uh there are some inputs by the user let's say the user address and amount but you'll also notice another

argument which is an array of bytes call data price update so basically this is an array of all of all the price feeds you want to update so uh updating price feeds on pit can uh require sending them the native token of whatever blockchain you're on so basically in the first line you get whatever the update fees is and then you call the pit uh the uh smart contract of the pit Network and call the update price feeds method send them a value and then um in the arguments you send them the price update

array you do this because um pit actually caches uh the price for some amount of time probably it's three or 5 minutes so you can actually call The Pit smart contract just like a how you would call a push Oracle smart contract but uh if the price is stale the call Will revert so it's always better to just update the price and then read it uh by calling the multiple functions to get price um the recommended one is to get the get price no older than function pass in the price feed ID which is a byes 32 argument and

then the number of seconds right uh so this is how you would also use chain link data stream the only difference would be uh first you'll uh actually get your transaction stored in their smart contract in the dab smart contract that will emit an event and people will Mo anyone can uh observe that event and resolve it by calling another function in your smart contract and delivering the price and then your smart contract will will verify it uh with chain link this is how you integrate the Redstone orle uh basically you import uh

their contract and then just use a function they have called get Oracle numer numeric value from transaction message and uh you pass in the data feed ID so to use Redstone their uh price update payload is appended at the end of the call data so You' see uh uh there's no bytes are here it's appended at the end and it automatically fetches using assembly all right so things to keep in mind so uh when you're using pull oracles they are updated very frequently like sometimes multiple times a second so uh one problem could be that the

timestamp of the price update can be from the future so it could be greater than the blog. timestamp so if you're making as making an assumption that the price update timestamp will always be less than equal to blog. timestamp this may not hold and may cause problems and uh this can also be Pro problematic if you're uh mixing blocked out Tim stamp and the Oracle update timestamp in the accounting and business logic of your contract uh um if you're using any Oracle where you have to internally validate the data make sure you are um doing sufficient validation on the on

the price update payload because if you're uh because if you're not validating that people can use past prices so always validate that the price delivered to your smart contract the time stamp is always higher than whatever was delivered before because because um we've seen this in audits before where um protocols have implemented this uh um in a very buggy way also um if you're using uh any Oracle uh which internally validates the

payload uh make sure that uh in the same block you do not revert if anyone sends a payload with a older price Tim stamp because that could uh result in a Dos for that user so in the same block always remember do not revert if uh an older time stamp comes just return at that point and do not change the price another problem with P oracles is there can be multiple prices in the same transaction because all I need to do is provide the smart contract with a timestamp that's greater than the last updated timestamp

so if uh my dap or the Oracle Network smart contract was last updated yesterday I could use all the prices since yesterday to today and then I can use them in the same transaction and I could use them in a malicious way and even if the small in the difference between the prices is small it can be Amplified by using flash loans remember this all is happening in one transaction so you have the luxury to use Flash loans so if you're making um Perpetual or future protocols or syns and you allow Atomic minting and burning of

sins uh attackers can use this to drain part of uh part of your funds plus um if you plan on making an immutable protocol using internally validated pull oracles can be problematic because they use public keys of um of signers of uh to see if whether the price the payload has a sufficient certain threshold of signers or not so if the private keys of those signers get gets compromised there's no way for the Oracle Network to actually update it without you having to

upgrade your smart contracts uh in case of externally validated P oracles uh this can be done but uh internally validated po oracles this is not possible if your protocol is immutable you'll have to upgrade it plus if you plan on using multiple types of oracles um in your protocol like let's say a push Oracle uh different types of pull oracles you'll notice you canot use the same uh function signature for all of them because different types of polar orles would require different uh encoding methods a push Oracle does not require you to send the prices along with it so you'll actually have to

abstract away the price EXT extraction mechanism into a separate um price Oracle or asset Oracle contract and you'll have to have a a a contract for each asset you want to obtain the price for so what will happen is you'll have to make multiple calls imagine if I want to borrow something I'll first have to call that asset orical contract update the price then I'll have to call the borrow um function in the main contract so this could cause compatibility with EAS because EAS cannot make multiple calls by Def

default so to allow the euas to make multiple calls you'll have to use a multi call and you'll have to uh add some authentication functionality to it so uh you could you call the multi the E can call the multi call uh update the price and then call the borrow function um of the main uh main protocol and the protocol can rest assured that the user was authenticated by the multicol so it can be trusted because the message. sender for the protocol would be the multicol address and this is how um Oiler does it um using the ethereum Vault connector

which is basically multicol with authentication in it so U Can older protocols um that were made before po oracles and were made to you function with push oracles uh can they be integrated with pull oracles um let's say compound V3 and actually the answer is yes because compound has some special functions that allows um anyone to operate on behalf of a user so it has Supply from transfer from transfer asset from and withdraw from functions and the liquidate function does not require the

end user to to be the message. sender so a multic call can actually do everything on the behalf on the behalf of a user on the behalf of a ea and can also update price so so that's it mostly from it from me uh if you want to uh learn more about oracles uh and different types of oracles you can look into oev oracles basically OE is a subset of meev but but it uh revolves around the extractable value whenever an oracle is updated so like oval and API 3 you could read into that you can read

into ZK oracles and hybrid oracles 2 which is basically a hybrid of push plus pull used by by synthetics so that's it from me any questions [Applause] yes please thanks um so in your example about P Oracle uh which is atomic uh I was just curious to like know how it's possible like to call the update function then have the of chain Oracle updating the price and getting the price

if it's what I've understood uh I'm sorry can you repeat that um like how is it possible for a nchain um service like uh the price Oracle Pi for example to update the price automically if it's oh it's working that is possible and but that would actually make it a push Oracle if there's a service that um updates the price at a certain interval right thanks yes please can ask all right thank guys