Let’s BUIDL: SmartWeave contracts (2)
Last time, we saw how to create a SmartWeave contract by manually creating the contract source, the initial state and the even how to submit the transactions with the right tags so your contracts are being used as expected.
This time we will learn about the executor, the third (but just as important) part of the SmartWeave contracts. This is what we use to read the latest state of your contract, and to interact with your contract source.
The executor
The executor is the program that runs your contract source on the client against the initial state, and then updates that state based on the inputs sent to the contract.
executor -> initial state tx -> sw contract tx
executor -> inputs -> run contract source per tx input -> latest state
So the only and most important task of the executor is to get you and your users the latest state of your contract.
In this example we will use SmartWeaveJS. SmartWeaveJS is just a JavaScript library, which executes other JavaScript (the contract source).
Let’s first read the contract to get the latest state, on your project, you first have to install the SmartWeaveJS dependency:
yarn add smartweave
And from there you can execute it:
import {readContract} from 'smartweave';
import Arweave from 'arweave';// Init an arweave instance just like before.
const arweaveInstance = Arweave.init({...});async function getLatestState() {
const latestState = await readContract(arweaveInstance, contractIntialStateTx);
console.log(latestState);
}
getLatestState();
readContract
will automatically grab the contract source from your initial state, it will read the source and the initial state, and from there it will search for all the input
updates sent to this state, it will execute those changes and returns the latest state after the changes are done to your initial state.
In this example, it will return the initial state object, since we haven’t done any updates to the contract yet.
It’s time to update the contract state, we will use SmartWeaveJS for this, but remember that all of these are just normal Arweave transactions, with special tags:
import {interactWrite} from 'smartweave';
import Arweave from 'arweave';// Init an arweave instance just like before.
const arweave = Arweave.init({...});async function update() {
// Remember `handle(state, action)` on our contract source
// and that we mentioned input?
// here's the input we were talking about!
// each write action requires an input
const input = {
function: 'increment'
};
// `interactWrite` will return the transaction ID.
const txid = await interactWrite(arweave, wallet, contractInitialStateTx, input);
}
update();
This creates an Arweave transaction with an Input
tag and a few others. Manually doing this with ArweaveJS will result into these tags (remember that tag values are always a string, even the input object is a string here):
App-Name: SmartWeaveAction
App-Version: 0.3.0
Contract: InitialStateTxId
Input: {function: 'increment'}
After this transaction ID is confirmed, next time we call readContract
we will have the state updated with the new and latest state, which in this case will increase our own tokens to 1001, since we are using the same wallet key file to run this code. We will get (as the latest state):
{
balances: {
"BPr7vrFduuQqqVMu_tftxsScTKUq9ke0rx4q5C9ieQU": 1001
}
}
That’s all there is to it! SmartWeave contracts are simple to understand when we grasp the basics. If you know JavaScript, you just need to learn how ArweaveJS works and how to create transactions, and from there you already know how to create SmartWeave transactions, how to interact with them, and how to update and show the states!
Keep in mind that the latest state isn’t stored on the permaweb, but the inputs are, so every time that someone executes your contract, it will go through each transaction and keep updating the state up to the latest one. Remember to always set conditions to prevent something we don’t want to happen, for example preventing users from incrementing more than 1,000.
Also remember to use functions that will always return the same value. We don’t want to use Math.random()
for example, where we will get always a new random value, if I execute it from my client and if you execute it from yours, we will both receive different results, and every time we read that contract, the result will always be different, so in that case the contract will be broken (most probably, unless this is what we want for some strange idea).
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.