# 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 ``` 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 | Address | Public Key | Secret Key | Is Default -----------------------+------------------+-----------------------------+-----------------------------+------------ 1 | {NORMAL_ADDRESS} | {NORMAL_ADDRESS_PUBLIC_KEY} | {NORMAL_ADDRESS_SECRET_KEY} | * ... {DUMMY_ADDRESS_INDEX} | {DUMMY_ADDRESS} | {DUMMY_ADDRESS_PUBLIC_KEY} | {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 ```