# Custom Smart Contracts

Users can deploy their own zero-knowledge contracts, written for the
DarkFi [zkVM](../zkas/index.md), becoming anonymous engineers
themselves!

More information about the smart contracts architecture can be found
[here](../arch/sc/sc.md).

## Hello World

For the porpuses of this guide, an example smart contract is provided,
which users can deploy to the testnet and interact with. This is a very
simple smart contract simulating a registration ledger, where users can
register or remove themselves from it, and each user is represented as
the [poseidon hash](../spec/crypto-schemes.md#poseidonhash-function) of their
public key.

First, open another terminal and navigate (from repo root) to the
example:

```shell
$ cd example/wasm-hello-world
```

Here, generate the contract `WASM` bincode by executing:

```shell
$ make

"../../zkas" proof/secret_commitment.zk -o proof/secret_commitment.zk.bin
Wrote output to proof/secret_commitment.zk.bin
RUSTFLAGS="" cargo build --target=wasm32-unknown-unknown \
        --release --package wasm_hello_world
...
    Compiling wasm_hello_world v0.0.1 (/home/anon/darkfi/example/wasm-hello-world)
    Finished `release` profile [optimized] target(s) in 15.90s
cp -f target/wasm32-unknown-unknown/release/wasm_hello_world.wasm wasm_hello_world.wasm
wasm-strip wasm_hello_world.wasm
```

Apart from the contract, an example client to interact with it is
provided, which we also need to compile:

```shell
$ cd client
$ make

RUSTFLAGS="" cargo build --target=x86_64-unknown-linux-gnu --release --package client
...
   Compiling client v0.0.1 (/home/anon/darkfi/example/wasm-hello-world/client)
    Finished `release` profile [optimized] target(s) in 2m 29s
cp -f target/x86_64-unknown-linux-gnu/release/client client
```

Now both the contract and its client are ready to use. Leave this
terminal open, as we will come back to it later in the guide, and
return back to your `drk` interactive shell.

## Creating contracts

Each contract is controlled by a secret key, from which its Contract ID
derives. To deploy a smart contract, we need to generate an authority
keypair first. The Contract ID shown in the outputs is a placeholder
for the one that will be generated from you. In rest of the guide, use
the one you generated by replacing the corresponding placeholder. We
can create our own contract authority by executing the following
command:

```shell
drk> contract generate-deploy

Generating a new keypair
Created new contract deploy authority
Contract ID: {CONTRACT_ID}
```

You can list your mint authorities with:

```shell
drk> contract list

 Contract ID   | Secret Key            | Locked | Lock Height
---------------+-----------------------+--------+-------------
 {CONTRACT_ID} | {CONTRACT_SECRET_KEY} | false  | -
```

## Deploy transaction

Now that we have a contract authority, we can deploy the example
contract we compiled earlier using it:

```shell
drk> contract deploy {CONTRACT_ID} example/wasm-hello-world/wasm_hello_world.wasm | broadcast

[mark_tx_spend] Processing transaction: d0824bb0ecb9b12af69579c01c570c0275e399b80ef10f0a9c645af65bdd0415
[mark_tx_spend] Found Money contract in call 1
Broadcasting transaction...
Transaction ID: d0824bb0ecb9b12af69579c01c570c0275e399b80ef10f0a9c645af65bdd0415
```

Now the transaction should be published to the network. When the
transaction is confirmed, the contract history will show its record:

```shell
drk> contract list {CONTRACT_ID}

 Transaction Hash | Type       | Block Height
------------------+------------+--------------
 {TX_HASH}        | DEPLOYMENT | 34
```

We can redeploy the contract as many times as we want, as long as it's
not locked. Each redeployment will show a new record in the contract
history. We can also export the deployed data by executing:

```shell
drk> contract export-data {TX_HASH} > wasm_hello_world.dat
```

The exported files contains the `WASM` bincode and instruction data
deployed by that transaction, encoded in `base64` as a tuple.

## Lock transaction

After we finished deploying our contract and don't require further code
changes, we can lock it. This will not allow further deployment
transactions, effectively locking the smart contract on-chain code. To
lock down the contract, execute:

```shell
drk> contract lock {CONTRACT_ID} | broadcast

[mark_tx_spend] Processing transaction: 9eee9799d77d0ef1dd115738982296c9c481b4412c75a0a0955fd67d87bfe6a0
[mark_tx_spend] Found Money contract in call 1
Broadcasting transaction...
Transaction ID: 9eee9799d77d0ef1dd115738982296c9c481b4412c75a0a0955fd67d87bfe6a0
```

After the transaction has been confirmed, we will see our contract
`Locked` status set to `true`, along with the block height it was
locked on:

```shell
drk> contract list

 Contract ID   | Secret Key            | Locked | Lock Height
---------------+-----------------------+--------+-------------
 {CONTRACT_ID} | {CONTRACT_SECRET_KEY} | true   | 36
```

We will also see the lock transaction in its history:

```shell
drk> contract list {CONTRACT_ID}

 Transaction Hash | Type       | Block Height
------------------+------------+--------------
 {TX_HASH}        | DEPLOYMENT | 34
 {LOCK_TX_HASH}   | LOCK       | 36
```

## Interacting with the smart contract

Now that the contract code is set on-chain and cannot be modified
further, let's interact with it using its client!

> NOTE: This is a very basic example client so secrets keys are used
> as plainext for simplicity. Do not run this in a machine with
> commands history or in a hostile environment where your secret key
> can be exposed.

First lets generate a new throwaway address to register:

```shell
drk> wallet keygen

Generating a new keypair
New address:
{DUMMY_ADDRESS}
```

Set it as the default one in the wallet and grab its secret key:

```shell
drk> wallet addresses

 Key ID                | Public Key       | Secret Key                  | Is Default
-----------------------+------------------+-----------------------------+------------
 1                     | {NORMAL_ADDRESS} | {NORMAL_ADDRESS_SECRET_KEY} | *
 ...
 {DUMMY_ADDRESS_INDEX} | {DUMMY_ADDRESS}  | {DUMMY_ADDRESS_SECRET_KEY}  |

drk> wallet default-address {DUMMY_ADDRESS_INDEX}
```

### List members

Let's go to the contract client terminal, and check current members:

```shell
$ ./client -c {CONTRACT_ID} list

{CONTRACT_ID} members:
No members found
```

No one has registered yet, so let's change that!

### Registration

Let's go to the contract client terminal, and register ourselves:

```shell
$ ./client -c {CONTRACT_ID} register {DUMMY_ADDRESS_SECRET_KEY} > register.tx
```

The produced transaction doesn't contain a fee, so we need to attach it
in our `drk` interactive shell:

```shell
drk> attach-fee < example/wasm-hello-world/client/register.tx | broadcast

[mark_tx_spend] Processing transaction: 23ea7d01ae16389e71d73fa27748ce1633d39c6b55a4aa31d8f5ba1017a4f840
[mark_tx_spend] Found Money contract in call 1
Broadcasting transaction...
Transaction ID: 23ea7d01ae16389e71d73fa27748ce1633d39c6b55a4aa31d8f5ba1017a4f840
```

After a while, we will see a new member in our contract registry:

```shell
$ ./client -c {CONTRACT_ID} list

{CONTRACT_ID} members:
1. 0x242d4a0dc358e0b61053c28352f666bace79889559b65e91efd1c83c7c817fdd
```

### Deregistration

To remove ourselves from the registry, we create a deregister
transaction with the contract client:

```shell
$ ./client -c {CONTRACT_ID} deregister {DUMMY_ADDRESS_SECRET_KEY} > deregister.tx
```

Then, we attach the fee again and broadcast it to the network:

```shell
drk> attach-fee < example/wasm-hello-world/client/deregister.tx | broadcast

[mark_tx_spend] Processing transaction: f3304e6f5673d9ece211af6dd85c70ec8c8e85e91439b8cffbcf5387b11de1d0
[mark_tx_spend] Found Money contract in call 1
Broadcasting transaction...
Transaction ID: f3304e6f5673d9ece211af6dd85c70ec8c8e85e91439b8cffbcf5387b11de1d0
```

When the transaction gets confirmed, our registry will not have members
again:

```shell
$ ./client -c {CONTRACT_ID} list

{CONTRACT_ID} members:
No members found
```
