How to sign raw Ethereum contract transactions with Elixir

The state of Ethereum libraries for Elixir

I’m a huge fan of Elixir and Phoenix, to the point where I could hardly imagine writing a backend web application in anything else. Especially not in Javascript. So when I began experimenting with smart contracts and Ethereum, I was dismayed to see the lack of fleshed out elixir libraries for interacting with the blockchain. Nothing came close to the state-of-the-art Web3.js available for javascript enthusiasts. ExW3 was a good candidate, but I found myself forking the repository almost immediately and even needing to fork and update it’s dependencies. Not to mention the nested rust requirements and its problems with more recent versions of Elixir.

Furthermore, these libraries did not operate well with Infura. Infura will not store your private keys, so signing raw transactions with these libraries became a stressful hassle of hacking together several frameworks, all of which seemed to come up short. It became so stressful in fact, that I actually gave up on trying to do any of this in Elixir.

Add a twist of Python

The first part of this tutorial may come as a surprise, in that we’re not actually going to use Elixir to build and sign transactions. The libraries sadly just aren’t there yet (as of June 2021). Instead we’re going to use python and the web3.py library to talk to the blockchain, but we’re going to facilitate this conversation through our Elixir application with the help of the :erlport dependency. Essentially, we will start up python in an Elixir process, and send messages to trigger our python functions.

Let’s start out by creating a python file called contracts.py. We’ll also need to make sure we have the web3.py library installed, which can be done with pip.

pip install web3

Assuming you have a local blockchain running through a service such as Ganache, we can begin to setup our web3 python module. I’m using a previously deployed contract, and have included the private key as an environment variable.

Sending the raw transaction will return a hex value, but we’ll want to send a string back to our elixir process, which can be done by calling .hex(). I’ve named this file contracts.py and I’ve placed it in a priv/python/ directory.

Now we just need to call this function from our Elixir app. The first step is adding the :erlport dependency, allowing us to talk to python.

defp deps do
[{:erlport, "~> 0.10.1"}]
end

Next we need a module which will create the python processes and talk to our blockchain functions.

We start the python process with python.start, giving it the python module directory and the version of python we want to run. Next, python.call sends a function call to the process, accepting the process_id, python module name, function name, and function arguments respectively. We then stop the process when we are done with it.

If you’ve run this code, you might encounter an error when trying to call PythonContract.call_hello("name").

Could not identify the intended function with name 'sayHello', positional argument(s) of type '(<class \'bytes\'>)

This is because python will accept the string argument as a binary, we’ll need to convert it to an ascii string before using it as such.

name_string = name.decode('ascii')

Voila! We are able to talk to the blockchain through python in our Elixir application.

I discovered this process while working on Nifty Media, a platform that makes it easier than ever for content creators to mint and share NFTs with their top followers.

Follow us on twitter for more updates! @nifty_media

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store