On-chain state
A smart contract can contain on-chain state. Declare it as a property on the class with the @state decorator:
class HelloWorld extends SmartContract { @state(Field) x = State<Field>();
// ...}Here, x is of type Field. Like with method inputs, only o1js structs can be used for state variables. The state can consist of at most 8 fields of 32 bytes each. These states are stored on the zkApp account.
Some structs take up more than one Field. For example, a PublicKey needs two of the eight fields.
States are initialized with the State() function.
A method can modify on-chain state by using this.<state>.set():
class HelloWorld extends SmartContract { @state(Field) x = State<Field>();
@method async setX(x: Field) { this.x.set(x); }}As a zkApp developer, if you add this method to your smart contract, you are saying: “Anyone can call this method to set x on the account to any value they want.”
Try it out
Add the following Smart Contract:
class HelloWorld extends SmartContract { @state(Field) x = State<Field>();
@method async setX(x: Field) { this.x.set(x); }}Add our local blockchain implementation so we can interact with our Smart Contract:
const Local = await Mina.LocalBlockchain({ proofsEnabled: false });Mina.setActiveInstance(Local);
const deployerKey = Local.testAccounts[0].key;const deployerAccount = deployerKey.toPublicKey();
const zkAppPrivateKey = PrivateKey.random();const zkAppAddress = zkAppPrivateKey.toPublicKey();const zkAppInstance = new HelloWorld(zkAppAddress);Initialize the Smart Contract and deploy it:
const txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount); zkAppInstance.deploy();});
await txn.prove();await txn.sign([deployerKey, zkAppPrivateKey]).send();To update our local zkApp account with a transaction, add the following code:
const txn1 = await Mina.transaction(deployerAccount, async () => { zkAppInstance.setX(Field(9));});await txn1.prove();const transaction = await txn1.sign([deployerKey]).send();This code creates a new transaction that attempts to update the field to the value 9 using the setX() function.
Now log the value of our transaction:
Provable.log(transaction)Build and run the script in the terminal:
npm run build && node build/src/index.jsThis will log similar transaction details like this:
[ { label: 'feePayer', publicKey: '..uyzV', fee: '0', nonce: '1', authorization: '..zFoR' }, { label: 'HelloWorld.setX()', publicKey: '..z1zm', update: { appState: '["9",null,null,null,null,null,null,null]' }, mayUseToken: { parentsOwnToken: false, inheritFromParent: false }, authorizationKind: { isSigned: false, isProved: true, verificationKeyHash: '3392518251768960475377392625298437850623664973002200885669375116181514017494' }, authorization: { proof: '..KQ==' } }]- Installing dependencies