#ScriptIt: An Ethereum NodeJs oracle that executes JavaScript directly from Solidity

CaptainJS
Coinmonks
7 min readDec 28, 2018

--

There are so many Ethereum oracles out there. Oraclize is the most famous one. But I needed a more simple and straight forward oracle for my projects. Thus, I created my own one: I simply wanted to invoke JavaScript directly from Ethereum’s Solidity. I just wanted to #ScriptIt — not more.

How it works

The Ethereum oracle is called CaptainJS. It waits for your JavaScript requests and executes them in a NodeJS container. If your contract is usingCaptainJS
then you can make use of callback and JavaScript execution functionalities.

The captain needs some budget to transfer your results or call your contract back. This budget (gas * gas price) will be transferred to the CaptainJS core contract and will be used to invoke your contract.

The simple callback {use.case.1}

In some cases it is necessary to have a mechanism to call the contract back. For example a fond which withdraws its budget every year to specific people. But Solidity can’t call itself.

Therefore extend from usingCaptainJS and start coding…

Use a unique integer jobId to identify your callback. Invoke RingShipsBell with enough gas and receive the callback in method RingRing. That’s it.

To make sure that RingRing will only be called by the captain himself and not a pirate, add onlyCaptainsOrdersAllowed to its declaration.

Simply use Mathjs {use.case.2}

Now let’s look at a simple JavaScript job. JavaScript’s mathjs library has multiple useful functions such as the conversion of centimeter to inch.

In order to use this library you need to call the Run function and hand over the JavaScript code that is necessary to convert centimeters to inch.

The JavaScript code you want to submit must be written the following way:

CaptainJS will invoke your code within a container by calling the default function. CaptainJSIn will contain your inputs of the JavaScript function. Then CaptainJS will return the result of your code. If your JavaScript code was successful: CaptainsResultwill be invoked. The return result is always a string.

If your JavaScript code was not successful or its result couldn’t be send back (it failed or there was not enough gas orwhatever happened) then CaptainsError will be invoked.

To make sure that both CaptainsResult and CaptainsError will only be called by the captain himself and not a pirate, add onlyCaptainsOrdersAllowed to its declaration.

A runtime slice has a duration of 10 seconds and it includes the download and install of all required npm modules. At the moment 6 runtime slices are the maximum.

Here’s the complete code snippet:

Call external resources like WolframAlpha {use.case.3}

If you want to call external resources such as WolframAlpha it’s pretty easy, too. Let’s ask WolframAlpha anything it knows about a country like France. Therefore you design your code the same way like you did in the 2nd use case.

To query WolframAlpha you use JavaScript’s axios library. The default function must be async so that you can wait for a result when you invoke axios.get(…). axios will return a JSON object but we need to flatten it to a string:

Again, CaptainJS will invoke your code within a container by calling this default function. CaptainJSIn will contain your inputs such as “France”.

Again, if your JavaScript code was successful: CaptainsResult will be invoked. Otherwise CaptainsError will be invoked.

And because Solidity sometimes is such a crappy programming language you will use a very expensive concat function to make your JavaScript code more readable.

Here’s the complete code snippet.

Requsting JSON, XML/XPath or HTML/jQuery {use.case.4}

A classic oracle request is a simple JSON, XML/XPath or HTML/jQuery request. Instead of writing a full-blown JavaScript code which does the query for you the newest release has predefined queries.

To invoke a simple query just use the Run method in the same way as you did it in the previous 2 use cases. But instead of submitting JavaScript code send an URL that has either a html:, xml: or json: prefix. The input parameter of the Run method is either a JSON, XPath or jQuery expression. Typically 1 runtime slice is enough.

If your JavaScript code was successful: CaptainsResult will be invoked. Otherwise CaptainsError will be invoked.

(The client libraries now include a test module to see if your code works — before you submitted to the blockchain)

Encrypting Your Data {use.case.5}

For those seamen who like to encrypt their data which is stored in the blockchain I’ve added an encryption module to the latest release. This allows you to send encrypted data to the Captain’s NodeJS containers. There it will be decrypted and executed. (The string result will not be send encrypted back)

For example you want to send a mail after a transaction happened then you could make use of nodemailer, login to your mail account and send the mail. In this case your code will look similar to this one:

The bad side of the story is, that your account details will be stored within your code. And these account details will be stored in Ethereum’s blockchain forever. That’s bad. But there’s hope!

In the client libraries I’ve added the https://github.com/CaptainJavaScript/Seaman-Client/blob/master/CaptainJS-Encryption.jswhich help you to encrypt your data before you include them in your contract:

  • just simply add your module to a file like MailSample.js
  • encrypt the file using EncryptFile from CaptainJS-Encryption.js
  • add the encrypted code to your contract

Encrypt your code:

And add your encrypted code to the Solidity-based contract:

The Captain will never read your code! It just gets executed in a fresh new container. In other words: if you encrypt your data then it will stay encrypted until it’s executed in a container (and the container will vanish after execution). The encryption uses the public/private key of the Captain’s contracts. Allthough the captain could read your encrypted data for private purposes, he won’t do it. That’s a promise and a proof of trust.

That’s it! :-)

--

--