Skip to content

Files

Latest commit

8db1d83 · Oct 11, 2024

History

History
145 lines (127 loc) · 6.77 KB

deployIn10min.md

File metadata and controls

145 lines (127 loc) · 6.77 KB

Deploy and interact with your first zkAPP under 10 minutes:

Used this playlist and official docs.

Initial setup:

  1. Install Node js and verify your version with
node --version // Example output: v18.18.0
  1. Verify npm is installed
npm --version // Example output: 10.4.0
  1. Install zkApp Cli
npm install -g zkapp-cli
  1. Verify zkApp Cli is installed
zk --version // Example output: 0.17.2
  1. Check the whole environment configurations and versions
zk system 

Create your first project:

  1. Move to a desired directory and create a new project. It automatically will install also 01js
zk project myFirstProject 
  1. Select none as the project template when asked and open it in your IDE
  2. Install dependencies in project folder
npm install
  1. A dummy contract named Add.ts will be generated in the /src folder. This contract allows to set 1 as the value for the state variable num and update it adding 2 when calling the update().
import { Field, SmartContract, state, State, method } from 'o1js';

/**
 * The Add contract initializes the state variable 'num' to be a Field(1) value by default when deployed.
 * When the 'update' method is called, the Add contract adds Field(2) to its 'num' contract state.
 */
export class Add extends SmartContract {
  @state(Field) num = State<Field>();

  init() {
    super.init();
    this.num.set(Field(1));
  }

  @method async update() {
    const currentState = this.num.getAndRequireEquals();
    const newState = currentState.add(2);
    this.num.set(newState);
  }
}
  1. Another file named interact.ts will be generated in the /src folder. This file takes care of interacting with Add.ts and is where ZKP is actually generated using tx.prove() method.
  2. Build the smart contract
npm run build

Deploy the Verifier contract:

  1. Create a local test network and give it a name when asked (e.g. testnet)
zk config 
  1. Set the network type between testnet/mainnet when asked
  2. Set an API URL to interact with it (e.g https://api.minascan.io/node/devnet/v1/graphql but this may change in the future)
  3. Set tx fee (e.g 0.1)
  4. Select the account that should pay for fees. You can also create one directly when asked, giving it an alias (e.g. testpayer). A private key and public key will be generated and stored in the testpayer.json file stored in the xkapp-cli folder somewhere in your computer.
  5. Done! A link will be prompted in the console with a link to a faucet to get some tMINA tokens for testing to the newly created account. Request them and wait for the tx to be processed.
  6. Deploy the contract and select the newly created network when asked
zk deploy myFirstProject
  1. The console will log all the informations and addresses related to the deployment together with a link to the testnet explorer of the deploy tx
  2. Open that link and wait till the tx will be processed (example tx). In it you can find:
    • the appState of the Add.ts contract just deployed with 1 in appState[0]
    • the verificationKeyHash (if you can't find it enable Raw JSON toggle on the top-right corner of the page and search it in the page). This hash is used to identify if an account on Mina is a zkApp. While deploying this contract we actually created a Verifier contract which live on-chain and must have a verification key. Important: the contract code is not stored on chain, the zkApp can only verify the proof you send it through the verification Key.

Interactions

Within the file interact.ts there is the code for interacting with the on-chain state. Interaction take place between the Prover (the feepayer) and the Verifier (the zkApp deployed).

Let's explore the file interact.ts (some lines are omitted here):

// reads privateKey and publickKey fields from testnet.json file
let zkAppKeysBase58: { privateKey: string; publicKey: string } = JSON.parse(
  await fs.readFile(config.keyPath, 'utf8') 
);
// creates a PrivateKey object converting from Base58 representation
let zkAppKey = PrivateKey.fromBase58(zkAppKeysBase58.privateKey)
// retrieves the corresponding public key of the zkApp
let zkAppAddress = zkAppKey.toPublicKey();

// creates a new instance of the Add contract and compile it
let zkApp = new Add(zkAppAddress);
await Add.compile();

// creates a tx object executing the Add.update() method locally and waits for its result
// then the tx object containing the result of the computation is used to generate a ZKP
// lastly the feepayer signs the tx and sends the proof on chain
  console.log('build transaction and create proof...');
  let tx = await Mina.transaction(
    // feepayerAddress should be specified and its data are read from the file which path is stored in config.json . In this example are read from testpayer.json we created during deployment
    { sender: feepayerAddress, fee },
    async () => {
      await zkApp.update();
    }
  );
  await tx.prove(); // generates the ZKP
  const sentTx = await tx.sign([feepayerKey]).send();

The command to execute interact.ts is:

    npm run build && node build/src/interact.js DEPLOY_ALIAS // for this example DEPLOY_ALIAS=testnet

After it if we look to the appState of the zkApp we will see 3 in the field 0 since the update() method increased the initial state, which was 1, by 2.

Testing

TO-DO: