Mina Protocol: Create a Simple zkApp with Mina Protocol and IPFS
Learn how to create a simple zkApp with Mina Protocol and IPFS.
What is Mina Protocol?
Mina Protocol is a lightweight, compact blockchain protocol that uses a recursive composition of zk-SNARKs (Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge) to enable participants to validate the entire chain's state in a single, small proof. This allows for extremely fast and efficient verification, which makes Mina Protocol highly scalable.
What is a zkApp?
"zkApp" stands for Zero-Knowledge Application, which is a type of decentralized application that uses zero-knowledge proofs to enhance privacy and security.
Zero-knowledge proofs are a cryptographic technique that allows one party to prove to another party that a certain statement is true, without revealing any additional information beyond the fact that the statement is indeed true. This means that a zkApp can allow users to perform certain actions or transactions without revealing their underlying data or identity to the network.
Read below to learn how to create a simple zkApp with Mina Protocol and IPFS.
1. First, download and install S3FS-FUSE on your local environment.
This tool is available on a Linux or macOS system.
2. Set up an Access Key file for use with S3FS-FUSE.
Set up a credentials file for S3FS at ${HOME}/.passwd-s3fs
. You will need to save your Filebase Access and Secret keys to this file and give it owner permissions. You can do so with the following commands:
echo ACCESS_KEY_ID:SECRET_ACCESS_KEY > ${HOME}/.passwd-s3fs
chmod 600 ${HOME}/.passwd-s3fs
ACCESS_KEY_ID is your Filebase Access key, and SECRET_ACCESS_KEY is your Filebase Secret key. For more information on Filebase access keys, see here.
3. Mount your bucket.
You can mount a Filebase IPFS bucket with the command:
s3fs mybucket /path/to/mountpoint -o passwd_file=${HOME}/.passwd-s3fs -o url=https://s3.filebase.com
mybucket: name of your Filebase bucket
/path/to/mountpoint
4. Now, navigate into the mounted Filebase bucket.
Create a new folder for your project:
mkdir minaProtocolZKApp
5. Next, install the Mina zkApp CLI tool:
npm install -g zkapp-cli
6. Create a new project with the command:
zk project zkapp
7. Then, remove a few of the default files that come with a new project with the command:
rm src/Add.ts
rm src/Add.test.ts
rm src/interact.ts
8. Then, generate some new files that we’ll be using:
zk file src/Square
touch src/main.ts
9. Open the src/index.ts
file, then insert the following content:
src/index.ts
file, then insert the following content:import { Square } from './Square.js';
export { Square };
10. Next, compile and build your project with the commands:
npm run build
node build/src/main.js
11. Now it’s time to write the smart contract for the zkApp. Open the src/Square.js
file and insert the following smart contract code:
src/Square.js
file and insert the following smart contract code:import {
Field,
SmartContract,
state,
State,
method,
} from 'snarkyjs';
export class Square extends SmartContract {
@state(Field) num = State<Field>();
init() {
super.init();
this.num.set(Field(3));
}
}
this.num.set(Field(3));
}
@method update(square: Field) {
const currentState = this.num.get();
this.num.assertEquals(currentState);
square.assertEquals(currentState.mul(currentState));
this.num.set(square);
}
}
This is a simple smart contract that retrieves the current state of the network, which is then used to update the zkApp’s current state on-chain.
12. Then open the src/main.ts
file and insert the following code:
src/main.ts
file and insert the following code:import { Square } from './Square.js';
import {
isReady,
shutdown,
Field,
Mina,
PrivateKey,
AccountUpdate,
} from 'snarkyjs';
await isReady;
console.log('SnarkyJS loaded')
const useProof = false;
const Local = Mina.LocalBlockchain({ proofsEnabled: useProof });
Mina.setActiveInstance(Local);
const { privateKey: deployerKey, publicKey: deployerAccount } = Local.testAccounts[0];
const { privateKey: senderKey, publicKey: senderAccount } = Local.testAccounts[1];
const zkAppPrivateKey = PrivateKey.random();
const zkAppAddress = zkAppPrivateKey.toPublicKey();
const zkAppInstance = new Square(zkAppAddress);
const deployTxn = await Mina.transaction(deployerAccount, () => {
AccountUpdate.fundNewAccount(deployerAccount);
zkAppInstance.deploy();
});
await deployTxn.sign([deployerKey, zkAppPrivateKey]).send();
const num0 = zkAppInstance.num.get();
console.log('state after init:', num0.toString());
console.log('Shutting down')
await shutdown();
13. Now if we compile and build our project again, we should get the following output:
npm run build && node build/src/main.js
...
SnarkyJS loaded
state after init: 3
Shutting down
14. Next, we’ll add a transaction to our zkApp. In the src/main.js
code, add the following portion:
src/main.js
code, add the following portion:console.log('state after init:', num0.toString());
// ----------------------------------------------------
const txn1 = await Mina.transaction(senderAccount, () => {
zkAppInstance.update(Field(9));
});
await txn1.prove();
await txn1.sign([senderKey]).send();
const num1 = zkAppInstance.num.get();
console.log('state after txn1:', num1.toString());
// ----------------------------------------------------
console.log('Shutting down')
await shutdown();
15. Then, compile and build the project again. This time, you should get the following output:
npm run build && node build/src/main.js
...
SnarkyJS loaded
state after init: 3
state after txn1: 9
Shutting down
You’ve just created your first zkApp!
Last updated
Was this helpful?