By the end of this guide, you will be all set up with a development environment that uses Truffle and Tenderly to speed up your Smart Contract development process.

Note: The proxy command is now deprecated in favor of the more powerful and versatile export command. You can read more about the export command here.

What are we going to make

To showcase the power of the Tenderly CLI we are going to make a simple calculator and use it to debug any problems we might encounter.

Installing and configuring Truffle

If you already have Truffle installed and configured, you can skip to the Contract section below.

To install the Truffle framework just run the following command:

$ npm install -g truffle

Now let’s create the directory for our calculator project and initialize truffle:

$ mkdir calculator

$ cd calculator

$ truffle init

Downloading...

Unpacking...

Setting up...

Unbox successful. Sweet! Commands: Compile: truffle compile

Migrate: truffle migrate

Test contracts: truffle test

The Contract

Our calculator supports just addition, subtraction, multiplication and division.

We add this to ./contracts/Calculator.sol

We can check if our code is correct by running the compile Truffle command:

$ truffle compile

Compiling ./contracts/Calculator.sol...

Compiling ./contracts/Migrations.sol...

Writing artifacts to ./build/contracts

Deploying the Calculator Contract

We have no use of our contract if it just lays there on our filesystem! Let’s deploy it to a local Ganache node and test it out! To install Ganache run the following command:

$ npm install -g ganache-cli

Now that we have Ganache installed, we can set up our network configuration in truffle.js :

Before we deploy our Smart Contract we have to start Ganache by running:

$ ganache-cli Ganache CLI v6.2.3 (ganache-core: 2.3.1)



Available Accounts

==================

(0) 0xa439c978fab0e2b13a874dc6c48dbc79c6f6655e (~100 ETH) ...

Then we make a new migration under ./migrations/2_deploy_calculator.js :

And finally to deploy the Calculator Smart Contract we can run:

$ truffle migrate --network ganache

Using network 'ganache'.



Running migration: 1_initial_migration.js

Deploying Migrations...

... 0x92039ee2c2f057dfb2b180bb532fb767626d4e1092a98125209f8f51c300818b

Migrations: 0x492649777fbe2e25f0470834f7ab50291c329391

Saving successful migration to network...

... 0xd57f3537cc224426ee86c0d0ada172c0a5c7a4f40921b1bb8d5997d5e8ffde01

Saving artifacts...

Running migration: 2_deploy_calculator.js

Deploying Calculator...

Interacting with the Smart Contract

Later on, we are going to write some tests, but for now, let’s interact with our contract directly:

$ truffle console --network ganache

truffle(ganache)> var calculatorInstance;

truffle(ganache)> Calculator.deployed().then(instance => calculatorInstance = instance)

truffle(ganache)> calculatorInstance.mul(10,5)

truffle(ganache)> calculatorInstance.getResult()

BigNumber { s: 1, e: 1, c: [ 50 ] }

As we can see we got the correct result! It’s an expensive calculator, but damn it it’s a distributed one!

However, what happens if we call the contract with invalid arguments? What if we maybe divide by zero?

$ truffle console --network ganache

truffle(ganache)> var calculatorInstance;

truffle(ganache)> Calculator.deployed().then(instance => calculatorInstance = instance)

truffle(ganache)> calculatorInstance.div(10,0)

Error: VM Exception while processing transaction: invalid opcode

at XMLHttpRequest._onHttpResponseEnd (/Users/user/.config/yarn/global/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1)

at XMLHttpRequest._setReadyState (/Users/user/.config/yarn/global/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:354:1)

...

If you look at the error we received you will see that there isn’t much helpful information. In the next section, we will write tests for the div function and use Tenderly to see how it helps with cases like this one.

Installing Tenderly

The Tenderly CLI is a Go program, so we compile just a single binary that you can download and use. The basic installation process would be to download the latest binary from the releases page and move it somewhere in your $PATH so you can use it globally.

For everyone’s convenience, we have simplified the process explained above so you can install the Tenderly CLI just by running the following commands.

Installing on macOS

Via Homebrew:

$ brew tap tenderly/tenderly

$ brew install tenderly

Alternatively, via cURL (the command downloads the latest release and moves it to /usr/local/bin ):

$ curl https://raw.githubusercontent.com/Tenderly/tenderly-cli/master/scripts/install-macos.sh | sh

Installing on Linux

The command downloads the latest release and moves it to /usr/local/bin :

$ curl https://raw.githubusercontent.com/Tenderly/tenderly-cli/master/scripts/install-linux.sh | sh

Installing on Windows

Go to the tenderly-cli release page, download the latest version and put it somewhere in your $PATH .

Using Tenderly for debugging

Now that we have the CLI all set up we can easily find why the smart contract is failing. First, we start the CLI with the proxy command which proxies requests to an Ethereum node and turns unusable errors which we saw into stack traces that we can use for easier debugging.

For the sake of speed, I’m going to use Ganache locally, but you can use Kovan or any other testnet if you want. You can see which options are supported by the CLI by running tenderly proxy --help :

$ tenderly proxy --help

Creates a server that proxies rpc requests to Ethereum node and builds a stacktrace in case error occurs during the execution time



Usage:

tenderly proxy [flags]



Flags:

-h, --help help for proxy

--path string Path to the project build folder. (default ".")

--proxy-host string Call host. (default "127.0.0.1")

--proxy-port string Call port. (default "9545")

--target-host string Blockchain rpc host. (default "127.0.0.1")

--target-port string Blockchain rpc port. (default "8545")

--target-schema string Blockchain rpc schema. (default "http")

Because I’m using Ganache with the default options, I won’t pass any arguments, and will just run the proxy command from the root of the project:

$ tenderly proxy

server will run on 127.0.0.1:9545

redirecting to 127.0.0.1:8545

Now that we have everything set up let’s go back to the console and try out our contract again, but this time we pass --network tenderly when starting the console:

$ truffle console --network tenderly

truffle(tenderly)> var calculatorInstance;

truffle(tenderly)> Calculator.deployed().then((instance) => calculatorInstance = instance)

truffle(tenderly)> calculatorInstance.div(10, 0)

Error: 0x0 Error: INVALID OPCODE, execution stopped

at a / b

in Calculator:19



at XMLHttpRequest._onHttpResponseEnd (/Users/user/.config/yarn/global/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1)

...

Finally, information we can act upon!