UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

89 lines (72 loc) 2.57 kB
import { SmartContract, method, state, PublicKey, UInt64, Experimental, } from '../../../../../index.js'; export { offchainState, StateProof, ExampleContract }; const { OffchainState } = Experimental; const offchainState = OffchainState( { accounts: OffchainState.Map(PublicKey, UInt64), totalSupply: OffchainState.Field(UInt64), }, { logTotalCapacity: 10, maxActionsPerProof: 5 } ); class StateProof extends offchainState.Proof {} // example contract that interacts with offchain state class ExampleContract extends SmartContract { @state(OffchainState.Commitments) offchainStateCommitments = offchainState.emptyCommitments(); // o1js memoizes the offchain state by contract address so that this pattern works offchainState = offchainState.init(this); @method async createAccount(address: PublicKey, amountToMint: UInt64) { // setting `from` to `undefined` means that the account must not exist yet this.offchainState.fields.accounts.update(address, { from: undefined, to: amountToMint, }); // TODO using `update()` on the total supply means that this method // can only be called once every settling cycle let totalSupplyOption = await this.offchainState.fields.totalSupply.get(); let totalSupply = totalSupplyOption.orElse(0n); this.offchainState.fields.totalSupply.update({ from: totalSupplyOption, to: totalSupply.add(amountToMint), }); } @method async transfer(from: PublicKey, to: PublicKey, amount: UInt64) { let fromOption = await this.offchainState.fields.accounts.get(from); let fromBalance = fromOption.assertSome('sender account exists'); let toOption = await this.offchainState.fields.accounts.get(to); let toBalance = toOption.orElse(0n); /** * Update both accounts atomically. * * This is safe, because both updates will only be accepted if both previous balances are still correct. */ this.offchainState.fields.accounts.update(from, { from: fromOption, to: fromBalance.sub(amount), }); this.offchainState.fields.accounts.update(to, { from: toOption, to: toBalance.add(amount), }); } @method.returns(UInt64) async getSupply() { return (await this.offchainState.fields.totalSupply.get()).orElse(0n); } @method.returns(UInt64) async getBalance(address: PublicKey) { return (await this.offchainState.fields.accounts.get(address)).orElse(0n); } @method async settle(proof: StateProof) { await this.offchainState.settle(proof); } }