Cerberus Wallet. Part 2. Development of a smart contract and external adapter for ChainLink

Mikael Lazarev
6 min readNov 5, 2019

--

This is a continuation of the article on the development of Cerberus Wallet, the beginning can be read at the link: Cerberus Wallet. Part 1. Concept.

Architecture
Developing the contract, I initially wanted to create a large contract that would manage the funds of many users. However, as we know — the more funds on the contract — the higher the chance that it will become a target for hackers.

Therefore, as an implementation, I chose the option in which each user deploys his own wallet and integrates it with the Cerberus Wallet system. In the future, it is planned to add a bytecode control system in which Cerberus Wallet will verify that the user has installed the correct bytecode.

Why a reliable ChainLink oracle system is crucial for this solution

Smart Contracts provide the ability to execute tamper-proof digital agreements, which are considered highly secure and highly reliable. In order to maintain a contract’s overall reliability, the inputs and outputs that the contract relies on also need to be secure. Chainlinks provide a reliable connection to external data that is provably secure end-to-end.

In order to receive transaction confirmation, it is very important to have an oracle service that you can trust. Moreover, in order to increase the reliability of the system, this service should be independent of Cerberus Wallet, so that in the event of a hacking of Cerbrus Wallet, attackers do not gain access to the entire system.

Another ChainLink advantage is its large community and team, which is working on improving the service and checking it for possible volnurabilities.

It’s also important that if the Cerberus Wallet service is unavailable or a DDOS attack is carried out on it, user funds will not be affected — after all, a smart contract will not transfer without receiving confirmation.

First draft of smartcontract
So, the idea is that user who signed a transaction would have to give confirmation within a specified period (3–5 minutes) and if confirmation is given, then the smart contract would do the transfer.

I decided to use the ChainLink Alarm Clock to implement confirmation delay. This problem can be solved through a repeated transaction, which the user will send after a specified time. However, such a solution greatly spoils the Customer Experience and makes the product complicated and inconvenient.

After the expiration of the confirmation time, the contract must verify that the confirmation has been received and transfer the funds, if everything is ok.

In order not to complicate, we will limit the current version of the contract to two functions: deposit money on it and transfer funds to other accounts.

Implementation

To start development with ChainLink you could download a convenient truffle box:

truffle unbox smartcontractkit/chainlink

After that you can modify a contract which is provided in the box. I hope you are familiar with Solidity, so let’s focus on interactions with oracles. Here ChainLink is similar to many frameworks for generating requests (requests (python), fetch (js), Alamofire (Swift), etc.).

Let’s check how to interact with ChainLink Alarm Clock as an example. At first, you should create a request:

Chainlink.Request memory req = buildChainlinkRequest(cerberusJobId, this, this.fulfillPaymentRequest.selector);

Here:
AlarmJobId — the identifier for the oracle function (numeric value). You can find it in the documentation, for your services you will receive it during deployment.

this.fulfillConfirmationRequest.selector — callback function of your contract, which will be called after execution.

After then, you can add parameters for you request:

req.add("id", bytes32ToStr(_requestId));

These parameters would be added to request which will be made by oracle to extrenal API. At the end, you should send the request using the command and get request id which could be used to recognise response:

bytes32 reqID = sendChainlinkRequestTo(cerberusOracle, req, cerberusPayment);

Here:
alarmOracle — oracle address to which the request is sent
alarmPayment — the amount of compensation in LINK tokens for its execution (1 LINK per request for now).

It’s very convenient way to make requests to external API.
If you are going to use your own API, you have to provide specifications (a JSON file which is described here and deploy your bridge to ChainLink node).

Sending Bytes32 values

Developing this smartcontract I had one interesting issue — I needed to use bytes32 value as request parameter. There is no way to simply add bytes32 as request parameters, so I had to convert bytes32 to string.

Dy default solidity 4.24 doesn’t provide such function from the box, so I had to write my own function to convert bytes32 to string which could be compatible with URL. My implementation:

function bytes32ToStr(bytes32 _bytes32) public pure returns (string) {

bytes memory bytesArray = new bytes(64);
for (uint256 i; i < 32; i++) {
bytesArray[2*i] = bytes1(uint8(_bytes32[i] & 240 ) / 16 + 65);
bytesArray[2*i+1] = bytes1(uint8(_bytes32[i] & 15) + 65);

}
return string(bytesArray);
}

How contract works

The full version of the contact can be found on GitHub: https://github.com/MikaelLazarev/cerberus/blob/master/contract/contracts/CerberusWallet.sol

Deposit money flow
Everything is simple here — the usual function for receiving funds.

Sending money flow

  1. To send funds, the user calls method sendMoney(address _to, uint256 _amount)

2. The sendMoney method, in turn, emits a NewPaymentRegistered event, which is used to monitor transactions.

3. sendMoney method also calls ChainLink Alarm Oracle and asks to call the fulfillConfirmationRequest method after the specified time (time to sign the transaction). The method also writes transaction parameters to mapping orders by the key that it received during the request (reqId)

4. After the specified time has passed, the fulfillConfirmationRequest method is called, which sends a request to Cerberus Oracle to find out if the user has signed the transaction.

5. The oracle calls the fulfillPaymentRequest method and passes the result of the confirmation request to the server as the _data parameter. If the answer is yes, then the funds are transferred to the specified address.

External Adapter

The task of the external adapter is to make a GET request to the Cerberus Server and pass the received value back to the oracle. For this, the project uses the Bridges framework (https://github.com/linkpoolio/bridges), which makes this task elementary.

You need to add add bridges library and inherit two methods Run & Opts. Full code could be found at: https://github.com/MikaelLazarev/cerberus/tree/master/adapter

In the next article we’ll discuss mobile app design!

Stay tuned!

All Cerberus Wallet articles:

Part 1. Concept
Part 2. Development of a smart contract and external adapter for ChainLink
Part 3. Designing a mobile application
Part 4. Backend
Part 5. Demo wallet
Part 6. Conclusion. Future of the project

About Cerberus Wallet:

Cerberus Wallet is open source project which adds two factor authentification for your crypto wallet. Even if your private key would be stolen, hacker would not be able to transfer your assets without your confirmation.

This application was designed from scratch especially for Chainlink + CoinList Hackathon.

Official site: https://cerberus.ledger-labs.com/

Video presentation: https://www.youtube.com/watch?v=4S8OyUf7cIA

If you like this project, please vote for it: https://coinlist.co/build/chainlink/projects/44b65d6e-02f3-40de-b3cc-40d905da76cf

Join Cerberus Wallet team:

CerberusWallet is an open source project. If you are interested in join the team, please contract me at t.me/@mikael_l. Together, we could create a much-needed technology and make crypto currency safer.

--

--