# Quickstart: Build a decentralized app with Nautilus (Solidity, Hardhat)

This quickstart is for web developers who want to start building **decentralized applications** (dApps) using Nautilus. It makes no assumptions about your prior experience with Ethereum, Nautilus, or Solidity. Familiarity with JavaScript and `yarn` is expected. If you're new to Ethereum, consider studying the [Ethereum documentation](https://ethereum.org/en/developers/docs/) before proceeding.

### What we're building

We're going to build a digital cupcake vending machine using Solidity smart contracts. Our vending machine will follow two rules:

1. The vending machine will distribute a cupcake to anyone who hasn't recently received one.
2. The vending machine's rules can't be changed by anyone.

Note that although this vending machine appears to follow the rules, it doesn't follow them as much as we'd like. The vending machine's business logic and data are hosted by a **centralized service provider**. We're trusting that this service provider isn't malicious, but:

1. Our centralized service provider can deny access to particular users.
2. A malicious actor can change the rules of the vending machine at any time, for example, to give their friends extra cupcakes.

Centralized third-party intermediaries represent a **single point of failure** that malicious actors may become incentive to exploit. To mitigate this type of risk, we can decentralize our vending machine's **business logic and data**, rendering this type of exploitation infeasible.

This is Nautilus's core value proposition to you, dear developer. Nautilus makes it easy for you to deploy your vending machines to Ethereum's permissionless, trustless, *decentralized* network of nodes while keeping costs low for you and your users.

Let's implement the "web3" version of the above vending machine using Nautilus.

### Prerequisites

* **VS Code**: The IDE we'll use to build our vending machine. See [code.visualstudio.com](https://code.visualstudio.com/) to install.
* **Metamask**: The wallet we'll use to interact with our vending machine. See [metamask.io](https://metamask.io/) to install.
* **Yarn**: The package manager we'll use to install our dependencies. See [yarnpkg.com](https://yarnpkg.com/) to install.

We'll install the rest of our dependencies as we go.

### Review our JavaScript vending machine

Here's our vending machine implemented as a JavaScript class:

VendingMachine.js

```js
   class VendingMachine {
        // state variables = internal memory of the vending machine
        cupcakeBalances = {};
        cupcakeDistributionTimes = {};

        // Vend a cupcake to the caller
        giveCupcakeTo(userId) {
            if (this.cupcakeDistributionTimes[userId] === undefined) {
                this.cupcakeBalances[userId] = 0;
                this.cupcakeDistributionTimes[userId] = 0;
            }

            // Rule 1: The vending machine will distribute a cupcake to anyone who hasn't recently received one.
            const fiveSeconds = 5000;
            const userCanReceiveCupcake = this.cupcakeDistributionTimes[userId] + fiveSeconds <= Date.now();
            if (userCanReceiveCupcake) {
                this.cupcakeBalances[userId]++;
                this.cupcakeDistributionTimes[userId] = Date.now();
                console.log(`Enjoy your cupcake, ${userId}!`);
                return true;
            } else {
                console.error("HTTP 429: Too Many Cupcakes (you must wait at least 5 seconds between cupcakes)");
                return false;
            }
        }

        getCupcakeBalanceFor(userId) {
            return this.cupcakeBalances[userId];
        }
    }
```

The `VendingMachine` class uses *state variables* and *functions* to implement *predefined rules*. This implementation is useful because it automates cupcake distribution, but there's a problem: it's hosted by a centralized server controlled by a third-party service provider.

Let's decentralize our vending machine's business logic and data by porting the above JavaScript implementation into a Solidity smart contract.

### Configure your project directory

Create a `decentralized-cupcakes` directory for your project and install [hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#overview) using VS Code's integrated terminal:

```
mkdir decentralized-cupcakes
cd decentralized-cupcakes
yarn init -y
yarn add hardhat @nomicfoundation/hardhat-toolbox -D
```

This installs two packages: `hardhat` lets us write, test and deploy our smart contracts, and `hardhat-toolbox` is a bundle of popular Hardhat plugins that we'll use later.

Next, run `yarn hardhat` to configure Hardhat. Select `Create a JavaScript project` when prompted. Make sure you specify your `decentralized-cupcakes` directory as the project root when asked.

At this point, you should see the following items (among others) in your `decentralized-cupcakes` project directory:

| Item                | Description                                                                                               |
| ------------------- | --------------------------------------------------------------------------------------------------------- |
| `contracts/`        | Contains your smart contracts. You should see the `Lock.sol` contract here.                               |
| `scripts/`          | Contains scripts that you can use to interact with your smart contracts. You should see `deploy.js` here. |
| `hardhat.config.js` | Contains the configuration settings for Hardhat.                                                          |

Replace the contents of `hardhat.config.js` with the following:

hardhat.config.js

```javascript
require("@nomicfoundation/hardhat-toolbox");

// NEVER record important private keys in your code - this is for demo purposes
const NAUTILUS_TESTSNET_PRIVATE_KEY = "";

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.18",
  networks: {
    hardhat: {
      chainId: 1337
    },
    NautilusTestnet: {
      url: "https://triton.api.nautchain.xyz",
      chainId: 91002,
      //accounts: [NAUTILUS_TESTSNET_PRIVATE_KEY]
    },
  }
};
```

Run `yarn hardhat compile` to compile the default `contracts`. You may be prompted to install additional dependencies - follow those instructions until this command runs successfully. You should see `Compiled 1 Solidity file successfully` in the terminal output. You should also see a new `decentralized-cupcakes/artifacts/` directory. This directory contains the compiled smart contract.

Open `scripts/deploy.js` and replace its contents with the following:

scripts/deploy.js

```javascript
const hre = require("hardhat");

async function main() {

  const VendingMachineFactory = await hre.ethers.getContractFactory("VendingMachine");
  const vendingMachine = await VendingMachineFactory.deploy();
  await vendingMachine.deployed();

  console.log(
    `Cupcake vending machine deployed to ${vendingMachine.address}`
  );
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

We'll use this to deploy our smart contract in a moment. Next, delete `contracts/Lock.sol` and replace it with `contracts/VendingMachine.sol`, the smarter alternative to our Javascript implementation:

VendingMachine.sol

```solidity
pragma solidity ^0.8.9;

// Rule 2: The vending machine's rules can't be changed by anyone.
contract VendingMachine {
    // state variables = internal memory of the vending machine
    mapping(address => uint) private _cupcakeBalances;
    mapping(address => uint) private _cupcakeDistributionTimes;

    function giveCupcakeTo(address userAddress) public returns (bool) {
        // this code is unnecessary, but we're keeping it here so you can compare it to the JS implementation
        if (_cupcakeDistributionTimes[userAddress] == 0) {
            _cupcakeBalances[userAddress] = 0;
            _cupcakeDistributionTimes[userAddress] = 0;
        }

        // Rule 1: The vending machine will distribute a cupcake to anyone who hasn't recently received one.
        uint fiveSecondsFromLastDistribution = _cupcakeDistributionTimes[userAddress] + 5 seconds;
        bool userCanReceiveCupcake = fiveSecondsFromLastDistribution <= block.timestamp;
        if (userCanReceiveCupcake) {
            _cupcakeBalances[userAddress]++;
            _cupcakeDistributionTimes[userAddress] = block.timestamp;
            return true;
        } else {
            revert("HTTP 429: Too Many Cupcakes (you must wait at least 5 seconds between cupcakes)");
        }
    }

    // Getter function for the cupcake balance of a user
    function getCupcakeBalanceFor(address userAddress) public view returns (uint) {
        return _cupcakeBalances[userAddress];
    }
}
```

Note that this smart contract is written in Solidity, a language that compiles to [EVM bytecode](https://blog.chain.link/what-are-abi-and-bytecode-in-solidity/). This means that it can be deployed to any Ethereum-compatible blockchain, including Ethereum mainnet and Nautilus.

Run `yarn hardhat compile` again. You should see `Compiled 1 Solidity file successfully` in the terminal output. You should also see a new `decentralized-cupcakes/artifacts/contracts/VendingMachine.sol` directory.

### Deploy the smart contract locally

To deploy our `VendingMachine` smart contract locally, we'll use two terminal windows and a wallet:

1. We'll use the first terminal window to run Hardhat's built-in local Ethereum node
2. We'll then configure a wallet so we can interact with our smart contract after it's deployed to (1)
3. We'll then deploy our smart contract to (1)'s node

#### Run a local Ethereum network and node

Run `yarn hardhat node` from your `decentralized-cupcakes` directory to begin running a local Ethereum network powered by a single node. This will mimic Ethereum's behavior on your local machine by using Hardhat's built-in [Hardhat Network](https://hardhat.org/hardhat-network/docs/overview).

You should see something along the lines of `Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/` in your terminal. You should also see a number of test accounts automatically generated for you:

```
...
Account #0: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
...
```

*NEVER SHARE YOUR PRIVATE KEYS*

*Your wallet's private key is the password to all of your money. Never share it with anyone; avoid copying it to your clipboard.*

Note that in the context of this quickstart, "account" refers to a public wallet address and its associated private key.

#### Configure Metamask

Next, open Metamask and create or import a wallet by following the displayed instructions. By default, Metamask will connect to Ethereum mainnet. To connect to our local "testnet", enable test networks for Metamask by clicking `Show/hide test networks` from the network selector dropdown. Then select the `Localhost 8545` network.

Your mainnet wallet won't have a balance on your local testnet's node, but we can import one of the test accounts into Metamask to gain access to 10,000 fake ETH. Copy the private key of one of the test accounts (**excluding** the `0x` prefix, so eg `ac0..f80`) and import it into Metamask:

You should see a balance of 10,000 ETH. Keep your private key handy; we'll use it again in a moment.

Next, click Metamask's network selector dropdown, and then click the `Add Network` button. Click "Add a network manually" and then provide the following information:

### Nautilus Triton Testnet

| Chain Name          | Nautilus Triton Testnet            |
| ------------------- | ---------------------------------- |
| Chain ID            | 91002                              |
| Block Explorer      | <https://triton.nautscan.com>      |
| Public RPC Endpoint | <https://triton.api.nautchain.xyz> |
| Currency Symbol     | tZBC                               |

As we interact with our cupcake vending machine, we'll use Metamask's network selector dropdown to determine which network our cupcake transactions are sent to. For now, we'll leave the network set to `Localhost 8545`.

#### Deploy the smart contract to your local testnet

From another terminal instance, run `yarn hardhat run scripts/deploy.js --network localhost`. This command will deploy your smart contract to the local testnet's node. You should see something like `Cupcake vending machine deployed to 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512` in your terminal. `0xe7...512` is the address of your smart contract in your local testnet.

Ensure that the `Localhost` network is selected within Metamask. Then copy and paste your **contract address** below and click `Get cupcake!`. You should be prompted to sign a transaction that gives you a cupcake.

### Deploy the smart contract to the Nautilus testnet

We were able to deploy to a local testnet for free because we were using [Hardhat's built-in Ethereum network emulator](https://hardhat.org/hardhat-network/docs/overview#hardhat-network). Because Nautilus's testnet is powered by a real network of real nodes, we'll need to pay a small transaction fee to deploy our smart contract. This fee can be paid with the Nautilus testnet's token, tZBC.

First, update the `hardhat.config.js` file to specify the private key of the test account that you'll use to deploy your smart contract (and pay the transaction fee):

hardhat.config.js

```javascript
// ...
const TESTNET_PRIVATE_KEY = ""; // <- this should **not** begin with "0x"
// ...
accounts: [TESTNET_PRIVATE_KEY] // <- uncomment this line
// ...
```

*CAUTION*

*Note that we're adding a private key to a config file. This is **not** a best practice. Consider using environment variables instead.*

Next, let's deposit some tZBC into the wallet corresponding to the private key we added to `hardhat.config.js`. You can acquire some testnet Token in <https://faucet.nautchain.xyz/>.

Once you've acquired some tZBC, you'll be able to deploy your smart contract to Nautilus's testnet by issuing the following command:

```bash
yarn hardhat run scripts/deploy.js --network Nautilus
```

This tells hardhat to deploy the compiled smart contract through the RPC endpoint corresponding to `Nautilus in` hardhat.config.js\`. You should see the following output:

```bash
Cupcake vending machine deployed to 0xff825139321bd8fB8b720BfFC5b9EfDB7d6e9AB3
```

Congratulations! You've just deployed **business logic and data** to Nautilus. This logic and data will be hashed and submitted within a transaction to all nodes in the Nautilus network.

Select `Nautilus` from Metamask's dropdown, paste your contract address into the `VendingMachine` below, and click `Get cupcake!`. You should be prompted to sign a transaction that gives you a cupcake.

### Summary

In this quickstart, we:

* Identified **two business rules**: 1) fair and permissionless cupcake distribution, 2) immutable business logic.
* Identified a **challenge**: These rules are difficult to follow in a centralized application.
* Identified a **solution**: Nautilus makes it easy for developers to decentralize business logic and data (using Ethereum mainnet as a settlement layer).
* Converted a vending machine's JavaScript business logic into a **Solidity smart contract**.
* **Deployed our smart contract** to Hardhat's local development network, and then Nautilus's testnet.

If you have any questions or feedback, reach out to us on [Discord](https://discord.com/invite/pgkrEqRdqV) , we're listening!
