Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📝 Creating a draft for upcoming cross-contract tutorial #857

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions docs/zkapps/tutorials/12-cross-contract-calls.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
---
title: 'Tutorial 12: Cross Contract Calls'
hide_title: true
sidebar_label: 'Tutorial 12: Cross Contract Calls'
description: Guided steps to learn about the ways to interact with a smart contract from another smart contract.
keywords:
- smart contracts
- zkapps
- zero knowledge proof programming
- zk proof
- zk
- cross contract call
- mina
---

:::info

Please note that zkApp programmability is not yet available on Mina Mainnet, but zkApps can now be deployed to Berkeley Testnet.

:::


# Tutorial 12: Cross Contract Calls

In this tutorial, you learn how smart contracts on a blockchain can interact by calling functions in each other's code, enabling building modular and complex decentralized applications.

Cross contract calls allow smart contracts on a blockchain to interact with each other. This enables the building of complex decentralized applications (Dapps) from multiple modular components. In a cross-contract call, a function in one smart contract can call a function in another smart contract to leverage existing code and functionality.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add an example of a complex stack that will benefit from this pattern (can we describe a use case?) @LuffySama-Dev

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the same !!
I was thinking of adding a image but an use case example sounds awesome.
Will check and add it in couple of days.

Thank You 🙌🏻


This tutorial demonstrates passing data between contracts, handling events, and returning values when contracts call each other.

The full example code is provided in the [12-cross-contract-calls/src/](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/12-cross-contract-calls/src) example files.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where are the example files? are they in this PR?
let's put the example files mentioned in the tutorial in a new folder here https://github.com/o1-labs/docs2/tree/main/examples/zkapps

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example files are added in initial commit in example folder.

7aa4b14#diff-40a308f55dcc34f6c479b6f2954062c4ef5bac47ad2928204dc9951e78eea6bc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once this PR get's merges the link will start working.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't recognize all three smart contracts as being present, since in a single file. Thanks @iregina for testing the code!


## Prerequisites

- Make sure you have the latest version of the zkApp CLI installed:

```sh
$ npm install -g zkapp-cli
```

- Ensure your environment meets the [Prerequisites](/zkapps/tutorials#prerequisites) for zkApp Developer Tutorials.

This tutorial has been tested with:

- [zkApp CLI](https://github.com/o1-labs/zkapp-cli) version `0.16.0`
- [o1js](https://www.npmjs.com/package/o1js) version `0.16.2`

## Create a new project

Now that you have the tooling installed, you can start building your application.

1. Create or change to a directory where you have write privileges.
1. Now, create a project using the `zk project` command:

```sh
$ zk project 12-cross-contract-calls
```

As you learned in earlier tutorials, the `zk project` command creates the `12-cross-contract-calls` directory that contains the scaffolding for your project.

1. Change into the `12-cross-contract-calls` directory.

Like all projects, you run `zk` commands from the root of the `12-cross-contract-calls` directory as you work in the `src` directory on files that contain the TypeScript code for the smart contract.

Each time you make updates, then build or deploy, the TypeScript code is compiled into JavaScript in the `build` directory.

### Prepare the project

Like earlier tutorials, you can prepare your project by deleting the default files that come with the new project and creating a smart contract called `Composability`.

## Write the ZkProgram

Now, the fun part! Write your smart contract in the `src/Composability.ts` file.

A final version of the smart contract is provided in the [Composability.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/12-cross-contract-calls/src/Composability.ts) example file.


### Copy the example

Use the existing code in the [Composability.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/12-cross-contract-calls/src/Composability.ts) example file.

1. First, open the [Composability.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/12-cross-contract-calls/src/Composability.ts) example file.

1. Copy the file's entire contents into your project `src/Composability.ts` file.

### Imports and Incrementer smart contract

First, bring in imports and set up the first smart contract `Incrementer`.

```typescript
import {
Field,
method,
Mina,
AccountUpdate,
PrivateKey,
SmartContract,
state,
State,
} from 'o1js';

// Contract which adds 1 to a number
class Incrementer extends SmartContract {
@method increment(x: Field): Field {
return x.add(1);
}
}

```
This Incrementer contract adds `1` to the `Field` argument, which is passed.

### Adder smart contract

Now bring in the second contract `Adder` that returns the addition of two numbers and adds `1` to the result.
The addition of `1` to the result is outsourced to the `Incrementer` smart contract by creating a new object by passing its address.

```typescript
// Contract which add two numbers and plus 1 to their sum and return the result
// Incrementing by one is outsourced to Incrementer contract
class Adder extends SmartContract {
@method addPlus1(x: Field, y: Field): Field {
let sum = x.add(y);
let incrementer = new Incrementer(incrementerAddress);
return incrementer.increment(sum);
}
}

```

### Caller smart contract

The final smart contract `Caller` calls the `addPlus1()` method of the `Adder` smart contract and emits the stored result that is returned.

```typescript
// Contract which calls the Adder contract, stores the result on chain & emits an event
class Caller extends SmartContract {
@state(Field) sum = State<Field>();
events = { sum: Field };

@method callAddAndEmit(x: Field, y: Field) {
let adder = new Adder(adderAddress);
let sum = adder.addPlus1(x, y);
this.emitEvent('sum', sum);
this.sum.set(sum);
}
}

```

The code to interact with the smart contract:

```typescript
const doProofs = true;

// Deploy and interact with smart contract locally
let Local = Mina.LocalBlockchain({ proofsEnabled: doProofs });
Mina.setActiveInstance(Local);

// Test account that pays all the fees, and puts additional funds into the zkapp
let feePayerKey = Local.testAccounts[0].privateKey;
let feePayer = Local.testAccounts[0].publicKey;

// The Incrementer contract's address
let incrementerKey = PrivateKey.random();
let incrementerAddress = incrementerKey.toPublicKey();

// The Adder contract's address
let adderKey = PrivateKey.random();
let adderAddress = adderKey.toPublicKey();

// The Caller contract's address
let callerKey = PrivateKey.random();
let callerAddress = callerKey.toPublicKey();

let callerZkapp = new Caller(callerAddress);
let adderZkapp = new Adder(adderAddress);
let incrementerZkapp = new Incrementer(incrementerAddress);

// When doProofs is true, compile contracts to generate prover and verifier keys
if (doProofs) {
console.log('compile (incrementer)');
await Incrementer.compile();
console.log('compile (adder)');
await Adder.compile();
console.log('compile (caller)');
await Caller.compile();
}

// Create transaction to deploy contracts
console.log('deploy');
let tx = await Mina.transaction(feePayer, () => {
AccountUpdate.fundNewAccount(feePayer, 3);
callerZkapp.deploy();
adderZkapp.deploy();
incrementerZkapp.deploy();
});
// Sign all four account updates by
// passing the corresponding private key for the mentioned public addresses
await tx.sign([feePayerKey, callerKey, adderKey, incrementerKey]).send();

// Create transaction to interact with the callAddAndEmit method of Caller contract
console.log('call interaction');
tx = await Mina.transaction(feePayer, () => {
zkapp.callAddAndEmit(Field(5), Field(6));
});
console.log('proving (3 proofs.. can take a bit!)');
await tx.prove();
console.log(tx.toPretty());
await tx.sign([feePayerKey]).send();

console.log('state: ' + zkapp.sum.get());

```

In this example, you spin up the Mina chain and deploy all three smart contracts locally.

Then you call the `callAddAndEmit` method from the `Caller` smart contract, which takes two numbers as arguments, then call the `Adder` smart contract, which adds these two numbers and passes the result in the `Incrementer` smart contract, which increments the result by 1.

When run successfully, the state is equal to 12.

## Conclusion

Congratulations! You have learned how to implement cross contract calls, allowing smart contracts to interact and unlocking new possibilities for modular blockchain applications.
23 changes: 23 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
jest: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:o1js/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
},
plugins: ['@typescript-eslint', 'o1js'],
rules: {
'no-constant-condition': 'off',
'prefer-const': 'off',
},
};
3 changes: 3 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Use line endings appropriate for the system. This prevents Git from
# complaining about project template line endings when committing on Windows.
* text=auto eol=lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#
# ci.yml
#
# Run tests for all pushed commits and opened pull requests on Github.
#

name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Set up NodeJS
uses: actions/setup-node@v4
with:
node-version: '16'
- name: Git checkout
uses: actions/checkout@v4
- name: NPM ci, build, & test
run: |
npm install
npm run build --if-present
npm test
env:
CI: true
13 changes: 13 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# NodeJS
node_modules
build
coverage

# Editor
.vscode

# System
.DS_Store

# Never commit keys to Git!
keys
4 changes: 4 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
11 changes: 11 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# TypeScript files
src

# Editor
.vscode

# System
.DS_Store

# Never reveal your keys!
keys
14 changes: 14 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# NodeJS
node_modules
build
coverage
.husky

# Editor
.vscode

# System
.DS_Store

# Misc
LICENSE
6 changes: 6 additions & 0 deletions examples/zkapps/12-cross-contract-calls/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading