Let’s BUIDL: SmartWeave Contracts

Photo by Markus Spiske on Unsplash

A few months ago, the Arweave team released an amazing feature called SmartWeave contracts. Before we start BUIDLing, make sure to check out this article about SmartWeave contracts to learn what they are. Here, we will instead focus on helping you get started on coding your own on top of the Arweave ecosystem.

Most of the devs coming to Arweave are already part of the world of crypto and most come from Ethereum and the smart contracts world, so they understand what a SmartWeave contract is, but most of the time find it hard to understand the differences between both projects.

The first difference between Ethereum smart contracts and SmartWeave (SW) contracts is that SmartWeave contracts are coded in JavaScript, you don’t need to learn a new programming language like you had to do with Solidity. If you know how to build a website or a Node.js project, then you know how to build a SmartWeave contract.

This also makes it super flexible, since you can use a SmartWeave contract to do pretty much anything you can do with JavaScript.

Another huge difference between the two contract types is that on Ethereum, the client that updates to the latest state the contracts are the miners, while on Arweave, the states are updated every time on the client, which most of the time is the visitor’s web browser. This is something very important to keep in mind while building a SmartWeave contract — they are not your only option, and shouldn’t be used for everything.

Since the SW contract itself is updated on the client, to get the latest state of a contract, the client needs to go through each interaction to find its latest valid state. It can be slow compared to other options like using ardb to grab transactions from Arweave.

An example of that are the Opportunities on CommunityXYZ. Opportunities are normal transactions, which makes them much faster to load since we only have to do a request which returns all the necessary fields without having to go through multiple transactions to find it. While loading a Community takes longer, we had to set a cache in place to help with that one.

How SmartWeave contracts are built

  • The contract source
  • The state
  • The executor (SmartWeaveJS)

The contract source

The contract source never changes, this is what guarantees your users that what they are using today, will always be true. It’s always good, as a dev user, to read the contract source, so we know what the owner (or anyone else) can do with the projects you’re using.

Multiple projects can use the same contract source. An example of that are Profit Sharing Communities, by creating a Community on https://community.xyz you’re using the same contract source as all the others, even CommunityXYZ itself uses the same contract source. However, each is separated by their own states and that state is deployed by the founder of that Community.

Let’s BUIDL!

In this test, let’s write some simple code which will increase the caller’s balance every time they call the increment function. Caller is the wallet address that interacts with this contract source.

export function handle(state, action) {
const balances = state.balances;
const input = action.input;
const caller = action.caller;

if(input.function === 'increment') {
// If the caller already is a key of balances, increment, if not, set it to 1.
if(caller in balances) {
balances[caller]++;
} else {
balances[caller] = 1;
}
}
}

All the SmartWeave contracts must start with export function handle(state, action){} since this is the function that is called by the executor. Everything else should be inside that handle function. Right now the handle itself is confusing since we don’t know what the state and action params are. Let’s first explain the action.

The action param

We will see the input again when talking about the executor (SmartWeaveJS).

The action param also has the caller as a key of that object. The caller, again, is who is running the function. These are the two only keys in action: input and caller.

The state

When we first create a contract, we also need to send a state with it, which is the initial state.

Let’s BUIDL!

{
balances: {
"BPr7vrFduuQqqVMu_tftxsScTKUq9ke0rx4q5C9ieQU": 1000
}
}

And this means that when the first person goes and reads our contract, the first state is that we have 1,000 of this token balance.

Both the state and the contract must be separate transactions sent to Arweave, and both are deployed only once. After that, the state is updated by sending little transactions that includes input interactions.

Deploying

import Arweave from 'arweave';const arweave = Arweave.init({
host: 'arweave.net',
protocol: 'https',
port: 443
});
async function createContract() {
// Let's first create the contract transaction.
const contractTx = await arweave.createTransaction({ data: contractSource }, wallet);
contractTx.addTag('App-Name', 'SmartWeaveContractSource');
contractTx.addTag('App-Version', '0.3.0');
contractTx.addTag('Content-Type', 'application/javascript');

// Sign
await arweave.transactions.sign(contractTx, wallet);
// Let's keep the ID, it will be used in the state transaction.
const contractSourceTxId = contractTx.id;

// Deploy the contract source
await arweave.transactions.post(contractTx);

// Now, let's create the Initial State transaction
const initialStateTx = await arweave.createTransaction({ data: initialState }, wallet);
initialState.addTag('App-Name', 'SmartWeaveContract');
initialState.addTag('App-Version', '0.3.0');
initialState.addTag('Contract-Src', contractSourceTxId);
initialState.addTag('Content-Type', 'application/json');

// Sign
await arweave.transactions.sign(initialState, wallet);
const initialStateTxId = initialState.id;
// Deploy
await arweave.transactions.post(initialState);
}
createContract();

Congratulations! You have just deployed your first SmartWeave contract.

What we will use to interact with your newly-created SW contract is that last initialStateTxId, so make sure to keep it somewhere safe, since we will need it later.

Next time, we have to learn how “the executor” works, since this is what we need to use to read our contract’s latest states, and also to update the states by sending transactions to Arweave with it.

Thanks for reading and if you like these Let’s BUIDL series let me know by giving it a thumb up and sharing. I’ll make sure to keep doing more of these!

If you have further questions or simply want to join the fun, join us on the Arweave Discord, and follow me on twitter.

EDIT: Second part is out. Keep reading here: https://cedriking.medium.com/lets-buidl-smartweave-contracts-2-16c904a8692d

Software Engineer. NodeJS & Javascript Lover.