We’re going to create a project where users can collaborate to write a short story. We’ll call it “Nonce Upon A Time”…

This first step will be to initialize a Clevis project. This can be done in a number of different ways. The easiest method is to just fire up a docker container with one command:

docker run -ti --rm --name clevis -p 3000:3000 -p 8545:8545 -v ~/nonce-upon-a-time:/dapp austingriffith/clevis:latest

This method will also bring up ganache-cli and your react app for you.

Once Clevis initializes (it can take several minutes depending on your machine), we can fire up a web browser and navigate to:

http://localhost:3000

Make sure MetaMask is unlocked and the network is http://localhost:8545

Let’s jump right in and create our main smart contract called Stories:

clevis create Stories

Remember, if you are using a Docker container, you only run Clevis command line actions in the container. If you want to edit your code, use your favorite editor. For example:

atom ~/nonce-upon-a-time

Clevis creates an empty smart contract scaffolding for you.

Our smart contract will be incredibly simple. We’ll just have a write function that emits a Write event with the line of the story and what address wrote it.

function write(string line) external {

emit Write(msg.sender, line);

}

event Write(address sender, string line);

Now we can compile it and make sure everything is solid:

clevis compile Stories

You will see a bunch of information including the bytecode and metadata, but as long as you don’t see any errors, you should be good to go. Again, if you haven’t used Clevis & Dapparatus before you should start with the intro.

Let’s go ahead and deploy the contract to our private chain:

clevis deploy Stories 0

Remember, the 0 here stands for account 0. This is the address that pays the gas to deploy the contract.

Now let’s publish our deployed contract into our frontend with:

clevis test publish

Next, let’s uncomment the contract loader in src/App.js:

Dapparatus’ ContractLoader will automatically load in all Clevis contracts.

In the frontend, you can look at the console to verify that our contract is now loading into React:

Notice the write(string) function is listed in the Stories contract.

Next, let’s go ahead and uncomment the Transactions component:

After hitting save we will now see the blocks as they are mined in the bottom right corner. Transactions will show up here too eventually:

Finally, let’s build a simple UI for adding lines to the story with a title:

if(contracts){

contractsDisplay.push(

<div key="UI" style={{padding:30}}>

<h1>

Nonce Upon A Time...

</h1>

<input

style={{verticalAlign:"middle",width:800,margin:6,marginTop:20,maxHeight:20,padding:5,border:'2px solid #ccc',borderRadius:5}}

type="text" name="writeText" value={this.state.writeText} onChange={this.handleInput.bind(this)}

/>

<Button size="2" onClick={()=>{}}>

Write

</Button>

</div>

)

}

This will give a nice little UI, but it won’t be wired up yet:

Let’s have that Write button actually fire off a transaction when it is clicked:

tx(contracts.Stories.write(this.state.writeText),(receipt)=>{

console.log("TX CALLED BACK",receipt)

this.setState({writeText:""})

})

And if we test it out…

Oh no, Insufficient funds.

Okay, we’ll need to send this account a little test ETH each time we deploy our contracts. Find the metamask() section in the tests/clevis.js file and add in your MetaMask address:

You can run just this test with:

clevis test metamask

Now you should have some test ETH.

This will happen every time you deploy too. So from now on this MetaMask account should have plenty of ETH to play around. Let’s try out the UI:

We can see that the transaction went through:

BUT, we aren’t displaying anything yet. We need to add in an event parser:

At first, let’s set it up where hide:false so we can make sure it’s working.

<Events

config={{hide:false}}

contract={contracts.Stories}

eventName={"Write"}

block={block}

onUpdate={(eventData,allEvents)=>{

//console.log("EVENT DATA:",eventData)

this.setState({events:allEvents})

}}

/>

After we save it should auto-reload and show us our event:

Cool, it worked, but that’s really ugly. Let’s hide that component and just have it update the state.

Then, let’s add in some UI to display the lines from each event:

let lines = []

for(let e in this.state.events){

let anEvent = this.state.events[e]

lines.push(

<div key={e}style={{position:"relative"}}>

<Blockie config={{size:2.5}} address={anEvent.sender}/>

<span style={{paddingLeft:10}}>

{anEvent.line}

</span>

</div>

)

}

Don’t forget to add in the lines array into your UI:

And there we go, we should have our lines of the story added into the UI. Let’s add a few more to make sure it’s solid. Bonus points if you can figure out how to supply multiple accounts with ETH and write a collaborative story:

Sweet, our dApp #BUIDL is complete. 🚢#SHIPL it……….