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

feat(cli/docs): introduce devnet quickstart guide #1080

Merged
merged 8 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
47 changes: 41 additions & 6 deletions cli/cmd/develop.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package cmd

import (
"bytes"
"context"
"os"
"os/exec"
"strings"

"github.com/omni-network/omni/lib/errors"

Expand All @@ -25,22 +27,29 @@ func newDeveloperCmds() *cobra.Command {
}

func newForgeProjectCmd() *cobra.Command {
var cfg developerForgeProjectConfig

cmd := &cobra.Command{
Use: "new",
Short: "Scaffold a Forge project",
Long: `Scaffold a new Forge project with a XGreeter contract
accompanied by simple mocked testing and a multi-chain deployment script.`,
Args: cobra.NoArgs,
Long: `Scaffold a new Forge project accompanied by simple mocked testing and a multi-chain deployment script.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return newForgeProjectTemplate()
return newForgeProjectTemplate(cmd.Context(), cfg)
},
}

bindDeveloperForgeProjectConfig(cmd, &cfg)

return cmd
}

type developerForgeProjectConfig struct {
templateURL string
}

// newForgeProjectTemplate creates a new project using the forge template.
func newForgeProjectTemplate() error {
func newForgeProjectTemplate(_ context.Context, cfg developerForgeProjectConfig) error {
// Check if forge is installed
if !checkForgeInstalled() {
// Forge is not installed, return an error with a suggestion.
Expand All @@ -50,8 +59,16 @@ func newForgeProjectTemplate() error {
}
}

sanitizedInput, err := sanitizeInput(cfg.templateURL)
if err != nil {
return &cliError{
Msg: "failed to sanitize input",
Suggest: "Please provide a valid URL",
}
}

// Execute the `forge init` command.
cmd := exec.Command("forge", "init", "--template", "https://github.com/omni-network/omni-forge-template.git")
cmd := exec.Command("forge", "init", "--template", sanitizedInput)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
Expand All @@ -70,3 +87,21 @@ func checkForgeInstalled() bool {

return err == nil // If there is no error, forge is installed.
}

// sanitizeInput validates and sanitizes the input to prevent command injection.
func sanitizeInput(input string) (string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to do this? They're running this on their own machine.

Also if we are askibng for urls shouldnt' ths allow :

Copy link
Contributor Author

Choose a reason for hiding this comment

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

true that was me fighting the pre-commit runner without questioning it

// Replace any characters that are not alphanumeric or allowed special characters.
// You might need to adjust this based on what characters are allowed in your URLs.
// This example allows alphanumeric characters, slashes, dots, and hyphens.
var allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-./"
var sanitized strings.Builder
for _, char := range input {
if strings.ContainsAny(string(char), allowedChars) {
if _, err := sanitized.WriteRune(char); err != nil {
return "", errors.Wrap(err, "failed to write sanitized input")
}
}
}

return sanitized.String(), nil
}
4 changes: 4 additions & 0 deletions cli/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ func bindAVSAddress(cmd *cobra.Command, addr *string) {
cmd.Flags().StringVar(addr, "avs-address", *addr, "Optional address of the Omni AVS contract")
}

func bindDeveloperForgeProjectConfig(cmd *cobra.Command, cfg *developerForgeProjectConfig) {
cmd.Flags().StringVar(&cfg.templateURL, "template", "https://github.com/omni-network/hello-world-template.git", "URL of the forge template to use")
Copy link
Contributor

Choose a reason for hiding this comment

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

This works - that way they can use any template they like. But we could also just use the name of it, and try to fetch https://github.com/omni-network/{template}.git

}

func bindDevnetAVSAllowConfig(cmd *cobra.Command, cfg *devnetAllowConfig) {
bindRPCURL(cmd, &cfg.RPCURL)
bindAVSAddress(cmd, &cfg.AVSAddr)
Expand Down
119 changes: 119 additions & 0 deletions docs/site/docs/develop/quickstart/quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
sidebar_position: 1
---

# 3-Minute Cross-Chain dApp

This QuickStart guide will run through how to start an Omni cross chain dApp in less than three minutes.

In this guide you will:

- Install the Omni CLI, scaffold a new project and run a local devnet
- Deploy contracts using foundry to the local devnet and test their functionality

## Steps

### Step 1: Install the Omni CLI

First, install the Omni CLI by running the following command:

```bash
curl -sSfL https://raw.githubusercontent.com/omni-network/omni/main/scripts/install_omni_cli.sh | sh -s
```

You may otherwise install from source by following the steps shown in the [Omni CLI Tools section](../../tools/cli/cli.md).

### Step 2: Scaffold a new project

Next, create a new directory for your project and scaffold a new project using the Omni CLI:

```bash
mkdir my-omni-dapp
cd my-omni-dapp
omni developer new
```

Note: this requires [foundry](https://github.com/foundry-rs/foundry) to be installed on your machine.

<details>
<summary>Test the Contracts with Forge</summary>

You can test the contracts with Forge by running the following command:

```bash
forge test
```

</details>

### Step 3: Run a local devnet

Start a local devnet by running the following command:

```bash
omni devnet start
```

Note: this requires [Docker](https://docs.docker.com/get-docker/) to be installed on your machine.

### Step 4: Deploy contracts

Deploy the contracts to the local devnet using foundry:

<details>
<summary>Obtaining Parameter Values</summary>

You can obtain RPC URL values and portal addresses for the running devnet chains by running the following command:

```bash
omni devnet info
```

And you the private key value is the first anvil private key, found by running:

```bash
anvil
```

These values are kept in `./script/bash/.env.example` and are used to deploy the contracts. You can rename the file to `.env` and fill in the values for other networks.

</details>

```bash
bash script/bash/deploy.sh
```

### Step 5: Perform a Cross-Chain Greet

You can now perform a cross-rollup greet by running the following command:

<details>
<summary>Obtaining Deployment Addresses</summary>

You can obtain the XGreeter deployment addresses from the output of the previous forge script deployment.

Because the devnet has just been started, the addresses will be the same as the ones shown below:

```bash
omni_evm: 0x8464135c8F25Da09e49BC8782676a84730C318bC
mock_op: 0x8464135c8F25Da09e49BC8782676a84730C318bC
mock_arb: 0x8464135c8F25Da09e49BC8782676a84730C318bC
```

</details>

```bash
cast send 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 'greet(string)' 'Yay in 3 minutes!' --private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d --rpc-url http://localhost:8001 --value 1ether
```

### Step 6: Check the Greet

You can check the greet has been saved on the Omni EVM global state by running the following command:

```bash
cast call 0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82 "lastGreet():(uint64,uint256,uint256,address,address,string)" --rpc-url http://localhost:8000
```

### 🎉 Done 🎉

You have successfully deployed and interacted with an Omni cross-chain dApp in less than three minutes!
20 changes: 18 additions & 2 deletions docs/site/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,13 @@ const sidebars: SidebarsConfig = {
},
{
type: "category",
label: "Testnet",
label: "Quickstart",
className: "sidebar-title",
collapsible: false,
items: [
{
type: "autogenerated",
dirName: "develop/testnet",
dirName: "develop/quickstart",
}
]
},
Expand All @@ -232,6 +232,22 @@ const sidebars: SidebarsConfig = {
type: "html",
value: "<div class='sidebar-separator'></div>",
},
{
type: "category",
label: "Testnet",
className: "sidebar-title",
collapsible: false,
items: [
{
type: "autogenerated",
dirName: "develop/testnet",
}
]
},
{
type: "html",
value: "<div class='sidebar-separator'></div>",
},
"develop/contracts",
],
operateSidebar: [
Expand Down
Loading