How to implement Chainlink without implementing Chainlink

image.png

Another totally random post... :D Today: Chainlink

I started with solidity development recently and shortly after came across Chainlink, which claims to solve a crucial problem of smart contracts: fetching data from outside.
As I was more and more thrilled about learning and understanding solidity and smart contracts and understanding the value of something like Chainlink, I decided now to not use it in my own project, for several reasons. The title of this post might be a bit misleading. :P Chainlink certainly has it's advantages in certain scenarios but in some it might be more reasonable to implement your own little "oracle".

Integration

Integration is a bit cumbersome due to some conflicts when used with for example Openzeppelin (contract names conflict) or when you try to test it in Truffle (contract names conflict with internal node objects.). Not really a Chainlink problem but still a blocker that lies inside of a dependency. There will even be a note on the Truffle website about this btw.
I went now through trying to actually fix these issues and submitting pull requests and talking to the guys. I ended up working with a modified local copy of chainlink/evm-contracts/src/v0.6.

Cost

Each Chainlink request costs LINK. Your contract needs to be always funded with LINK and it's your responsibility to make sure it is. So to work autonomously, the contract has to receive LINK as some form of payment to ensure those requests can be made. I can easily imagine justified monetization in my project but does that need to be in LINK? I'd prefer ETH but then I have to convert it to LINK in some automated way, which is possible using Uniswap but how reliable is that really? And anyway... it adds additional costs again.

Dependency

As a rule of thumb I always try to avoid unnecessary dependencies. Now Chainlink can offer decentralized tamperproof outside API access. But the decentralization has to be implemented manually (afaik) and as soon as you need more complex data requests than simple price feeds, that becomes tricky. (Please correct me if I just overlook something here.)
I need to write a custom external adapter, I also need to make sure the respective nodes are running, communicate with the operators or run my own Chainlink node, at least my contract has to provide a method for changing the oracle. So is it really worth it having Chainlink as a dependency? In my case maybe not.

Chainlink Basics

So now that I understand how Chainlink works, I decided to implement the mechanic myself. But first... how does Chainlink work? What does it boil down to in the end?
Basically it's restricted contract methods. Every Chainlink node has a corresponding contract on the Ethereum blockchain. The so called Oracle contract. This contract emits an event whenever it receives a request from your (consumer) contract, together with the amount of LINK the node wants to have for a single request. The node listens for these events, executes the request (an API call or whatever), and sends the result back to the oracle contract, which forwards it to your contract. So the node itself has an Ethereum account. This ethereum account is the owner of the oracle contract and the oracle contract accepts request fullfillments only from its owner (or other accounts authorized by the node operator).
So now you can receive data from your favourite trusted Chainlink node. But as mentioned before, decentralization does not come out of the box. Each Chainlink request is bound to a specific oracle/node. If you want to use multiple oracles and crosscheck results, you CAN do.

This is how I understand the system so far and again... please correct me if I'm wrong with something.

My Implementation

So the mechanic is pretty simple. You have a contract that emits requests in the form of events and you have one or more authorized accounts that can respond to those requests and send data back.
In my case, for example, I need on-chain verification that an Ethereum account owns a given GitHub account. To check this I ask the user to create a repository with their Ethereum address as its name and then click a Register button in my app.

mergepay-register.gif

The Register button triggers a transaction to the contract with the GitHub user ID. At the same time the app starts to listen for the registerRequest event that my contract will emit when the transaction is done. On this event the app calls my internal API that checks the existance of that repository through the GitHub API and then sends a confirmation to my contract via the owner account of the contract.
If you know exactly when and how your requests are triggered, you don't even need the event. In my case I can just run the API call right after the transaction was successful, without listening for the event.

Of course this approach is not decentralized or anything. BUT it is reliable. It's ME who's in control of the "oracle" or owner account and it is ME who can guarantee data integrity because MY account only does things when MY API allows it. As long as my app runs, this implementation will work. A registration in my service will actually cost a bit of ETH to cover the confirmation gas cost. Since you only register to withdraw ETH deposits I think this is acceptable.

If you are interested in my experimental project, take a look here.
I created a UI prototype that you can try and see some of the use cases. See also here for the repositories for the web app and the contracts.

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Ecency