Links
Youtube link: https://www.youtube.com/watch?v=jZsWp1sBnwQ
Project website: www.tellor.io
Twitter: https://twitter.com/WeAreTellor?s=20
Discord: https://discord.com/invite/n7drGjh
Summary
This week's community call was about a complete walkthough of the Tellor X source code. Tim went over and explained Tellor master and the controller and everything that the controller inherits, the oracle, governance and the treasury.
Whole discussion
Nick: Hey everyone, welcome to Tellor community call, October... something. Early October. October 5th. We are going to do our Tellor X code walkthrough. Some initial announcements on some things; as some of you might follow the Ampleforth piece, they are kicking off a governance vote soon. That’s the word on the streets, so get your FORTH tokens ready, go vote for us! Should be a clean integration. Don’t know what that actually means for timelines and integrating as far as when it goes live but we’ll be voted in. If you’re holding FORTH make sure you pull it off from a centralized exchange, like whenever you are voting with TRB, if you’re holding your TRB on a centralized exchange, you can’t vote with it. As you should hold it in your personal wallet.
BG: If you say, it has to be in your own wallet before the vote starts?
Nick: They’re using snapshot voting, similar to Tellor, they’re looking at a snapshot of one block and then take it. That’s preventing you from voting on one account and then transferring it. Other than that, hackathon still going on, lot of people building on Tellor, lots of cool stuff. If you need some more ideas, if you need any help, feel free to reach out to us. Other things on the dev side, the new Telliot coming along great, will do a code walkthrough with that probably within a few weeks. Little house-keeping announcement before I hand it over to Mike; next week there will be no community call on Tuesday. Probably we’ll move it to Thursday or Friday, because we’ll bring the whole team up, will have a lot more of us here at the office, so will be fun.
Mike: One thing we could do, regardless if the team is all here in person or not, and I was going to propose this before you said that, but we’re ready to do a walkthrough of the new Tellor X website/front-end thing. I think it would be really cool to have Ben or Ryan to walk through. It won’t be too long, so we can do that with the whole team here in person. That’s our big update this week, that we nailed it all down and we’re ready to share it with you guys, we’ve been talking about it for weeks now, but we’re excited about it. Handing over to Tim.
Nick: Tim, so the floor is yours, you have as much time as you need. Ryan, if you want to let him share and excited to see what you got.
Tim: Just so everyone knows, if anyone has any questions as I go through this, feel free to cut me off and then also if there’s any questions at the end hopefully, we’d love to hear them. I’m actually going to share my screen. Alright, so we are going to start with the Tellor master contract. This is the main master contract of the whole Tellor system and this is already deployed, it’s already being used by Tellor X, I mean Tellor 3, and it is not new with Tellor X. This is a contract through which we’ll be doing our upgrade. So, the master contract in Tellor 3 delegates its calls to a Tellor contract and as we’ll see in a minute, in Tellor X it delegates its calls to the controller contract. Let’s look at the controller, or actually first let’s look at the Tellor storage contract which like master is already deployed. It is also not new with Tellor X. It handles the storage of lots of different variables in the Tellor system. It holds information about disputes from Tellor 3 and about information on requests. Also, as we’ll see shortly, we’ll be moving the storage data, I mean the dispute data and oracle data to their own contracts in Tellor X. In the storage contract the storage exists at the Tellor master address and it’ll still be using many variables in Tellor X and TRB balances allowances etc.
Moving on to the controller, where again the master delegates calls to this controller contract. The controller handles changing the addresses of the different contracts in the Tellor system. It also handles minting and migrating old TRB to the newer TRB. And I’ll just note that there will not be a new TRB token for Tellor X. This is just for migrating the very old TRB tokens to the somewhat less old TRB tokens. The controller has a few functions for changing contract addresses, and these functions can only be called by the governance contract and governance call these by going through a proposal and a vote which we’ll see in a little bit, but here you can see it has functions for changing the controller contract, governance, the oracle, the treasury, changing some UINT variables, migrating and minting TRB. The controller inherits from Tellor staking and transition and basically that means that everything in the transition and Tellor staking contracts, all of that is actually in the controller. There’s no separate Tellor staking or transition contract. First, let’s look at the transition. Transition is used to create a smooth migration from Tellor 3 to Tellor X. It links to the Tellor 3 oracle data and Tellor 3 data disputes. It also has some functions for retrieving values from the oracle, so as we’ll see down below, some of those functions for retrieving values they will first try and see whether the value exists in Tellor X, and if not, it will try to look for that value in Tellor 3. Basically, transition just allows any parties that are already using Tellor to continue using Tellor as they were before. Here we can see some functions for getting different variables in the Tellor system address variables. Some information about disputes. Here is one function, getLastNewValueByID, which uses the logic I mentioned before; it will try to find a value in Tellor X, in the new oracle contract and if it can’t find it, it will look for that value in Tellor 3, in the older data. Further down below we have some more functions for retrieving data that use similar checks for finding Tellor X data or Tellor 3 data. The bottom here, you can just see where transition gives access to multiple functions from Tellor 3. Let’s say in Tellor 3 some miners dispute or submit some values and then we make our upgrade to Tellor X, and then someone wants to dispute one of those recent Tellor 3 values, that can still happen. Through the Tellor master address which delegates that call to the controller for the transition. And then back to the controller real quick. Remember, controller inherits from transition like we just went over and it also inherits from Tellor staking. Let’s look at the Tellor staking contracts. This staking handles the logic for Tellor reporters to deposit their stake to become a reporter and it has some logic for reporters to unlock their stake. Here you can see the deposit stake function, which is used by a user to first become a reporter. So, anyone who wants to be a reporter has to have 100 TRB in their account and then they can call deposit stake and then they’ll become a staker or reporter. Then once a reporter wants to no longer be a reporter and retrieve their tokens they can call requestTakingWithdraw, and that begins a lock period of seven days. During that time people can still dispute the reporter’s data and their stake is still locked up, so the disputer can still claim the stake after a successful dispute. If a reporter has requested a withdrawal and the waiting period has expired, then they can finally call withdrawStake to actually claim their stake. In this contract there’s also a slashMiner function which is only called by governance in the case of a successful dispute.
Nick: Time, I want to ask some questions. I noticed you do, since we went through everything that inherits in the controller, which is the fallback, I notice you do the staking on the current Tellor address, but the reporting will not be on the current Tellor address.
Tim: Yeah, that’s a good point to bring up.
Nick: And I saw there were some reading functions, like you can get last new value by ID and things like that, that would be in using Tellor portion. How do you see people using it? Do you see a lot of people going directly to the oracle contract or do you see them all still reading from this master?
Tim: I think existing users of Tellor 3, they have a high chance of continuing to use the existing master address. Obviously, anyone who’s using Tellor data within a contract that’s already been deployed, that can’t be upgraded, they have to use that same logic which is great that they can. The controller and the transition contract, when you’re calling data or retrieving data from there, it’s actually converting that data to UINT values and also when you are retrieving data from there, you’re inputting UINT value as a request ID. So, anyone who is still using UINT values, could definitely still use the master address, but since Tellor X is moving to using bytes 32 values for IDs and bytes values for the actual data for the values, anyone who’s using those bytes and maybe converting them to something other than UINT 256 values, I think they would want to use the oracle contract address. Just because at the master address that value will be converted back to UINT values.
Nick: Awesome, thanks Tim!
Tim: So, controller inherits from Tellor staking, Tellor staking inherits from the token. Let’s look at the token contract which contains some of the normal logic for ERC-20 tokens. You can see it has user’s allowance. We also have the allowedToTrade function, which tells you whether a user can transfer their TRB. In the case that the user is a reporter with 100 TRB staked, that user cannot transfer their TRB without first unlocking it and going through the correct process. Also, if a reporter has been disputed their tokens are locked. So, this function tells you whether a user’s TRB can be transferred. We have some more standard ERC-20 functions. There’s also the balanceOfAt function, with an input of a user address and a block number. We use checkpointing for the TRB token and that is used for any votes. When someone creates a dispute or someone creates a proposal, we take a snapshot of everyone’s TRB balances, so when users vote, we look at the user’s balance at the time that the vote was initiated or the dispute or the proposal was initiated. That prevents people from transferring their tokens to different addresses in attempt to vote multiple times with the same token. Then we have some more standard ERC-20 functions. We’ve just gone over the controller, and everything that is inherited by the controller, and also the master. Since the master delegates calls to the controller, we can think of everything we’ve just gone over as kind of all coupled together.
Next, we move on to the oracle which is not quite as coupled with everything we’ve just gone over. It still is controlled by the controller and by governance but it also is kind of standalone in that it has its own storage. Like Nick just mentioned, users can interact with the oracle directly through this oracle contract address. The oracle contract handles the logic for tips and making a data request and for reporters submitting values. Let’s look at the addTip function. In Tellor we’ve had this addTip function, but in Tellor X there are some updates to it. First of all, you can see the bytes32 ID value which is a new thing where we used to use UINT256 values. Now for any existing request IDs, like request ID2, before you would use 2. Those values will still be mapped to 2. If you convert the UINT value 2 to bytes32 then that is where request ID 2 values will reside. Then we have the tipAmount and then finally we have the bytes data argument which is a new feature in Tellor X. This argument is going to be used for the new Tellor X data specs. Basically, this is bytes data so it’s open ended. It can be any length and it can contain different types of data converted to bytes that can be converted back to other different types of data and this data will be used by reporters to fulfill requests when just the specification of our quest ID isn’t sufficient. This data will only be emitted in an even, in this tipAdded event, and it will not be stored on chain, so that saves some money on gas by not storing all that data. Since it’s in an event, it is still available to reporters who want to fulfill a request. For example, if we have some sort of a bridge standard and Tellor X, where the reporters need to know the sender address and the token address and maybe a token quantity, someone can request that Tellor reporters submit data to Eth network, bridging tokens from Polygon for example. The reporters need to know which user address is allowed to unlock some tokens, they need to know what token address is being transferred and what token amount. Those might be some examples of values or data that would go in this fightsDataField. That’s a new feature in Tellor X.
Here you can see the changeMiningLock function which can only be called by governance. We’ll see shortly in the governance contract the process by which this type of function can be called. The mining lock at least for now is 12 hours, so that is the amount of time that a reporter has to wait after submitting a value to submit another value. If any reporters want to submit more frequently, they can stake at another address another 100 TRB, so then from that address they can submit another value. Below the changeMiningLock we have changeTimeBasedReward, again only callable by governance. RemoveValue is also only able to be called by governance. Next, we have the submitValue function. This is the function where reporters will be submitting their values and again, we have bytes32 ID, the bytes value. So, that bytes value is more open-ended than UINT256. It could represent UINT values still, it can represent streams, bytes, all sorts of things. That will allow Tellor X to support many more different types of data, different types of applications and the third argument is submitValue, is an announced value. That is a new feature in Tellor X. The purpose of the announced value is to prevent someone from wasting gas on a request ID whose reward has already been claimed by someone else. If someone adds a tip for a request ID, two reporters both see that and want to report the value, if the first reporter submits the value and the second reporter submits the value, that’s similar time. Without announced value the second reporter would waste money on gas but with announced value that transaction would fail, and the second reporter won’t waste their gas money. Down here we have some getters for the oracle contract so you can see, you can get the current reward, this will return how much of a drip reward is available and how many tips are available for a given request ID. We also have some getters for retrieving values from the oracle. Some information about reporters and reports. That was the oracle contract.
Next let’s look at governance. The governance contract handles disputes. Someone wants to dispute some value and governance also handles proposals for changing different parameters in the Tellor system, for changing contract addresses. We can see in the constructor, governance is deployed with a whitelist of functions that are allowed to be called by a proposal. These functions we’ve already seen in other contracts. We just saw a changeMiningLock in the oracle contract, there’s also a function setApprove for adding new functions to this whitelist. All these functions can be called by creating a proposal, which we’ll see below. But first we have the beginDispute function. If someone wants to dispute a reporter’s value they can input the request ID and timestamp. In order to dispute a value the user must have a TRB balance. Now that dispute fee depends on some conditions. The more disputes there are on a given request ID, the higher the fee is. The more disputes are ongoing in general the more the dispute fee is. Also, when someone does call this beginSpeed function, 10% of the dispute fee goes to tip the request ID that’s being disputed. The intent of that is to incentivize someone to quickly add another value to this request ID, since some value in that request ID has been made unavailable by the dispute. After someone has successfully called beginDispute, a dispute is active and then let’s go down to the vote function. TRB holders can call this vote function to vote on the dispute. They input the disput ID and the bool value whether or not they support the dispute, and there’s also the option of choosing invalid query. The invalid option is only available for disputes and it is not available for proposals. For a dispute, sometimes things can be hazy, sometimes, you could have a very highly volatile day in the ether price for example and it can be unclear what the correct price should be at a given time at that day. So, we don’t want to discourage reporters from submitting data on volatile days or in other hazier conditions. So if a vote results to invalid, then the reporter gets the stake back and can continue reporting again and the disputer gets the dispute fee back minus the 10%. That went to a tip. Then after the dispute or after the dispute voting period is over, which is two days then someone can call tallyVotes. For disputes there is a zero quorum. This tallyVotes functions is going to figure out what the outcome of the vote was. If most people voted invalid then vote will resolve to invalid, and if it’s mostly in support, then we’ll go and support etc. After tallyVotes is called there is another waiting period in which someone can dispute the outcome of the dispute and start another voting round. In order to start another voting round, someone will call beginDispute once again and input the same parameters of the original dispute. Once we finally pass the waiting period after tallyVotes, which is one day, then someone can call executeVote. Which will look at the outcome of the vote and if the vote passed then executeVote will slash the miner and give the stake to the disputer in the first round. And it will also give that disputer the dispute fee back. If there are multiple rounds on this dispute, then the other disputers will just get their dispute fee back. If the dispute resolves to against, then the reporter will get the dispute fee back and the reporter will get his stake back and will be able to continue reporting.
Ryan: A quick question Tim. It seems like most of the dispute mechanism seems pretty similar to Tellor 3 outside of the invalid inquiry, which is cool. Is there anything else that’s like notable? It just seems like the speed mechanism was pretty good as it was.
Tim: No, you’re right, it is very similar. Actually, off the top of my head I can’t think of any other big difference other than invalid.
Nick: I think the other thing too to note. If you had complaints about the current dispute system, we wish there was an invalid, we realized that, and then it’s really expensive to dispute, we’re hoping that gets fixed as well.
Tim: Yeah. Since we’re lowering the stake amount, I think you can logically lower the cost to dispute and take someone’s stake amount.
Nick: Yeah, I think that was a big hesitation for people and now submitting disputes Is that it’s a month’s salary, or even more, it’s a lot of money to dispute somebody. If we can lower it now, it’s similar to the last one, it’s based upon the number of stakers in the system. If we get more stakers because we’re lowering the amount and adding in some incentives to get more stakers, then the stake amount or the dispute amount will lower down to something like 10 TRB, which will be way way more affordable. Even for us it’s feasible for a lot of people to get 10 TRB to be able to submit a dispute. We’re not too concerned about that.
Tim: We want people to be able to dispute bad values, but we also don’t want people to be able to attack our system and try to hang it up. That’s why as there’s more disputes active then that cost goes up. We’re trying to deal with those trade-offs.
Nick: How much is it to propose a vote. To upgrade?
Tim: That is this proposeVote...
Nick: It’s 10. There’s also a quorum in here as well. Which you’re probably going to go over I would assume. This is probably different than a lot of other systems. If you look at Uniswap, it costs you know a year’s salary or something like that to propose a change or any sort of these upgrades. We wanted to keep it affordable. At the same time, you don’t want too many because it costs money to vote these things down. People are trying to save you system.
Tim: So, how much is that?
Nick: 10 TRB.
Tim: As the number of active vote rounds goes up then that TRB gets multiplied by two to the number of vote rounds. There’s a distinction between disputes and proposals. We just went through disputes and then this propoosedVote function is used to create a proposal. The argument for this function is the contract. That’s the contract address, where the function resides that we’re going to call. The bytes4 function identifier. This would be from that whitelist we saw in the constructor. There’s a bytes data argument which would be the arguments that go into the actual function we’re proposing to call. Then there’s a timestamp argument which is used basically for identifying a unique proposal so when someone wants to challenge the outcome of a proposal vote, they can call this proposedVote function and they have to make sure they input all the same parameters, including this timestamp. Then from here it’s a similar process to the dispute process. Once again TRB holders call the vote function and input the ID and true or false whether they support the proposal. But in this case, there is no invalid outcome. This invalid argument is ignored. After the voting period once again, someone can call talyVotes function, but in the case of a proposal, the vote period is 7 days, whereas in a dispute the vote period was 2 days. Then for a proposal there is a quorum of five percent of TRB supply. So tallyVotes determines the outcome of the proposal vote and then there’s another waiting period which is 1 day for proposals as well. In that time someone can challenge the proposal vote and put it up to another vote. Then once the waiting period successfully passes, someone can call executeVote which will call whatever function was being proposed to be called. If the vote passes. That is the main functionality of the governance contract. And again, this contract has some getters which allow you to retrieve some information about disputes, about voters.
Mike: Did you show the delegate function? That voters can delegate their vote?
Tim: Oh right, I didn’t. Good point. We also have this delegate function. TRB holders can delegate their voting power to some other address. The Tellor team could vote on behalf of people or anyone else could.
Nick: Question; is there a default delegator?
Tim: I don’t believe so.
Nick: There isn’t, I’m just quizzing you. So, a lot of systems, some of them will have where you’re automatically delegated to someone unless you take it back. We decided against that. And can you delegate and then that person delegate everybody’s votes?
Tim: No, we do not have chained delegation.
Ryan: Why not?
Tim: I guess we technically could, some people do, but it gets messy because expensive chaining lots of delegations.
Mike: It’d also be lame if everybody just ended up delegating and I feel it would just reach the top of the pyramid eventually and it would just be one person voting.
Nick: Yeah, because that was my biggest, thing is you lose a little bit of the feel of it. You want to trust the person you’re delegating to. You don’t want to have a delegate of a delegate of a delegate... What is this? You want to make sure that they can’t sell your votes as easily.
Tim: That’s the governance contract. We can move on to the treasury. This contract handles buying and issuing Tellor treasuries. Basically, Tellor governance can vote to issue some treasuries quarterly or really whenever they want. If that vote passes, then TRB holders are able to buy the treasury which locks up their tokens for a period of time. As you’ll see, as long as they vote, as long as the treasury investors vote in Tellor governance votes during the treasury duration, then they’ll get the full treasury return rate plus their initial investment. The treasury life cycle starts with a governance proposal, like what we just went through in the governance contract. That proposal would propose to call the treasury’s issueTreasury function. Which has a few inputs; the maxAmount, which is the maximum amount of TRB that can be locked in this given treasury, there’s the returnRate, which is the maximum amount that the treasury investors can earn for investing in the treasury, and then the duration which is a timestamp of when the treasury funds can be unlocked. Once governance calls issueTreasury, there will be an active treasury available for TRB holders to purchase. TRB holders will call the buyTreasury function, inputting the treasury ID and the amount that they want to purchase. Remember, there’s a limited amount of TRB that can be purchased in a given treasury. Once the user buys the treasury their TRB amount is locked until the treasury period expires. Once we reach that expiration date anyone can call this payTreasury function, it has the inputs of the investor address and the treasury ID. Once again, treasury investors are expected to participate in voting during the time that they’re invested in the treasury. If an investor participates in 90% of the votes that occurred during the treasury period, then they’ll only get 90% of the treasury returnRate, when they call this payTreasury function. Anyone who participates in all the votes will get all of the return rates plus their initial investment. Then this treasury contract has some getter functions for retrieving some information about treasury investors, about a given treasury. That is basically the treasury contract. That’s basically the whole Tellor X system.
We went over Tellor master and the controller and everything that the controller inherits. Like I said, those are all kind of coupled together. Then we also have three more contracts, which are kind of standalone but also are controlled by the whole Tellor system by governance and by the controller. We went over the oracle, governance and the treasury. That’s it.
Nick: You guys want to say something?
Brenda: Yeah, so, Tim, on the treasury, when they buy a treasury, do they actually get a token, or how does it work?
Tim: They do not get a token. No receipt token or anything like that.
Nick: Why not?
Tim: Well, why not? It’s a good question.
Brenda: The main reason is that we want the tokens to be out of circulation, so they’re going to be out. They shouldn’t be circulating.
Tim: But even though they don’t get a receipt token, they can retrieve some information about their investments from getTreasuryAccount, inputting a treasury ID and their address. That will tell them how much they’ve invested in a given treasury. They can also see the total amount that they have in all treasuries with getTreasuryFundsByUser. There are a few ways that investors can keep track of the treasuries they’ve invested in, see how much they have invested.
Nick: Tim, this was an excellent walkthrough. Thank you for taking us through all the code and the various contracts. If anybody else wants to go through this and in any more detail or has any questions, definitely just let us know. We’re excited, for those of you that don’t know the Tellor X is currently out in an audit. We’ve gotten a lot of feedback, our auditor actually just feeds us the feedback as he finds it, and we’ve implemented most of the changes, we should be getting that back next week and then we’ll share with all and make any final changes before we deploy it on Rinkeby for full testing. Anything else guys?
Brenda: Great job Tim!
Tim: Thanks for listening!
Nick: There’s a pretty extensive testing suite in this thing as well so, if you want to go and poke around any of the tests to see how it actually works. It’s another work of art I would say.
Thank you, guys, very much for coming on. We’ll let you know if we’re going to have a call next week or what we’re going to be doing. Thanks for helping on and talk to you guys soon! Bye!