From 129710498d984fb14469091dd0636615fc6a3f86 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 13:29:21 +0100 Subject: [PATCH 1/8] feat(cli): add hello world template --- cli/cmd/develop.go | 31 ++++++++++++++++++++++++++++--- cli/cmd/flags.go | 4 ++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cli/cmd/develop.go b/cli/cmd/develop.go index 04c513cf7..d46a50533 100644 --- a/cli/cmd/develop.go +++ b/cli/cmd/develop.go @@ -2,6 +2,7 @@ package cmd import ( "bytes" + "context" "os" "os/exec" @@ -25,6 +26,8 @@ func newDeveloperCmds() *cobra.Command { } func newForgeProjectCmd() *cobra.Command { + var cfg developerForgeProjectConfig + cmd := &cobra.Command{ Use: "new", Short: "Scaffold a Forge project", @@ -32,15 +35,21 @@ func newForgeProjectCmd() *cobra.Command { 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 { + templateName 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. @@ -50,8 +59,24 @@ func newForgeProjectTemplate() error { } } + // Map the template name to the forge template URL. + templateURLs := map[string]string{ + "hello-world": "https://github.com/omni-network/hello-world-template.git", + "xgreeter": "https://github.com/omni-network/omni-forge-template.git", + } + + // Check if the template name is valid. + templateURL, ok := templateURLs[cfg.templateName] + if !ok { + // The template name is invalid, return an error with a suggestion. + return &cliError{ + Msg: "invalid template name.", + Suggest: "Valid template names are: hello-world, xgreeter", + } + } + // 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", templateURL) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { diff --git a/cli/cmd/flags.go b/cli/cmd/flags.go index 93327338a..8ef1fc657 100644 --- a/cli/cmd/flags.go +++ b/cli/cmd/flags.go @@ -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.templateName, "template", "hello-world", "Name of the forge template to use") +} + func bindDevnetAVSAllowConfig(cmd *cobra.Command, cfg *devnetAllowConfig) { bindRPCURL(cmd, &cfg.RPCURL) bindAVSAddress(cmd, &cfg.AVSAddr) From 3ea110d5a971db83106a786b493b441924a7c7e4 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 14:48:42 +0100 Subject: [PATCH 2/8] docs(quickstart): introduce quickstart section --- .../docs/develop/quickstart/quickstart.md | 119 ++++++++++++++++++ docs/site/sidebars.ts | 20 ++- 2 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 docs/site/docs/develop/quickstart/quickstart.md diff --git a/docs/site/docs/develop/quickstart/quickstart.md b/docs/site/docs/develop/quickstart/quickstart.md new file mode 100644 index 000000000..09322329f --- /dev/null +++ b/docs/site/docs/develop/quickstart/quickstart.md @@ -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. + +
+Test the Contracts with Forge + +You can test the contracts with Forge by running the following command: + +```bash +forge test +``` + +
+ +### 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: + +
+Obtaining Parameter Values + +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.sh` and are used to deploy the contracts. + +
+ +```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: + +
+Obtaining Deployment Addresses + +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: 0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82 +mock_op: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +mock_arb: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +``` + +
+ +```bash +cast send 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 'greet(string)' 'Yay in 5 minutes!' --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --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! diff --git a/docs/site/sidebars.ts b/docs/site/sidebars.ts index 270b360b6..d1aed760b 100644 --- a/docs/site/sidebars.ts +++ b/docs/site/sidebars.ts @@ -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", } ] }, @@ -232,6 +232,22 @@ const sidebars: SidebarsConfig = { type: "html", value: "", }, + { + type: "category", + label: "Testnet", + className: "sidebar-title", + collapsible: false, + items: [ + { + type: "autogenerated", + dirName: "develop/testnet", + } + ] + }, + { + type: "html", + value: "", + }, "develop/contracts", ], operateSidebar: [ From eb70642ff6eb823ba51b74270c060a128ba9e262 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 17:28:45 +0100 Subject: [PATCH 3/8] docs(quickstart): use .env file naming --- docs/site/docs/develop/quickstart/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/site/docs/develop/quickstart/quickstart.md b/docs/site/docs/develop/quickstart/quickstart.md index 09322329f..34b33cfb1 100644 --- a/docs/site/docs/develop/quickstart/quickstart.md +++ b/docs/site/docs/develop/quickstart/quickstart.md @@ -75,7 +75,7 @@ And you the private key value is the first anvil private key, found by running: anvil ``` -These values are kept in `./script/bash/env.sh` and are used to deploy the contracts. +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. From ca30731d84469fd4a4d95d48f208ca0dc63a69e7 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 19:17:45 +0100 Subject: [PATCH 4/8] feat(cli): use url for templating --- cli/cmd/develop.go | 39 +++++++++++++++++++++++++-------------- cli/cmd/flags.go | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/cli/cmd/develop.go b/cli/cmd/develop.go index d46a50533..e7800fed0 100644 --- a/cli/cmd/develop.go +++ b/cli/cmd/develop.go @@ -5,6 +5,7 @@ import ( "context" "os" "os/exec" + "strings" "github.com/omni-network/omni/lib/errors" @@ -45,7 +46,7 @@ accompanied by simple mocked testing and a multi-chain deployment script.`, } type developerForgeProjectConfig struct { - templateName string + templateURL string } // newForgeProjectTemplate creates a new project using the forge template. @@ -59,24 +60,16 @@ func newForgeProjectTemplate(_ context.Context, cfg developerForgeProjectConfig) } } - // Map the template name to the forge template URL. - templateURLs := map[string]string{ - "hello-world": "https://github.com/omni-network/hello-world-template.git", - "xgreeter": "https://github.com/omni-network/omni-forge-template.git", - } - - // Check if the template name is valid. - templateURL, ok := templateURLs[cfg.templateName] - if !ok { - // The template name is invalid, return an error with a suggestion. + sanitizedInput, err := sanitizeInput(cfg.templateURL) + if err != nil { return &cliError{ - Msg: "invalid template name.", - Suggest: "Valid template names are: hello-world, xgreeter", + Msg: "failed to sanitize input", + Suggest: "Please provide a valid URL", } } // Execute the `forge init` command. - cmd := exec.Command("forge", "init", "--template", templateURL) + cmd := exec.Command("forge", "init", "--template", sanitizedInput) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -95,3 +88,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) { + // 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 +} diff --git a/cli/cmd/flags.go b/cli/cmd/flags.go index 8ef1fc657..6127fb110 100644 --- a/cli/cmd/flags.go +++ b/cli/cmd/flags.go @@ -25,7 +25,7 @@ func bindAVSAddress(cmd *cobra.Command, addr *string) { } func bindDeveloperForgeProjectConfig(cmd *cobra.Command, cfg *developerForgeProjectConfig) { - cmd.Flags().StringVar(&cfg.templateName, "template", "hello-world", "Name of the forge template to use") + cmd.Flags().StringVar(&cfg.templateURL, "template", "https://github.com/omni-network/hello-world-template.git", "URL of the forge template to use") } func bindDevnetAVSAllowConfig(cmd *cobra.Command, cfg *devnetAllowConfig) { From c38fedeb078797d3802fa70713ac107c1bc32916 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 19:21:04 +0100 Subject: [PATCH 5/8] fix: description in cli developer new cmd --- cli/cmd/develop.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cli/cmd/develop.go b/cli/cmd/develop.go index e7800fed0..50d1d0a72 100644 --- a/cli/cmd/develop.go +++ b/cli/cmd/develop.go @@ -32,9 +32,8 @@ func newForgeProjectCmd() *cobra.Command { 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(cmd.Context(), cfg) }, From 829c95f2aa1ce774c22a3d5f574ee5a27f7cf85b Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 19:33:29 +0100 Subject: [PATCH 6/8] fix(docs): use anvil pkey 2 --- docs/site/docs/develop/quickstart/quickstart.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/site/docs/develop/quickstart/quickstart.md b/docs/site/docs/develop/quickstart/quickstart.md index 34b33cfb1..1df17683d 100644 --- a/docs/site/docs/develop/quickstart/quickstart.md +++ b/docs/site/docs/develop/quickstart/quickstart.md @@ -95,15 +95,15 @@ You can obtain the XGreeter deployment addresses from the output of the previous Because the devnet has just been started, the addresses will be the same as the ones shown below: ```bash -omni_evm: 0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82 -mock_op: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 -mock_arb: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +omni_evm: 0x8464135c8F25Da09e49BC8782676a84730C318bC +mock_op: 0x8464135c8F25Da09e49BC8782676a84730C318bC +mock_arb: 0x8464135c8F25Da09e49BC8782676a84730C318bC ``` ```bash -cast send 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 'greet(string)' 'Yay in 5 minutes!' --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8001 --value 1ether +cast send 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 'greet(string)' 'Yay in 3 minutes!' --private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d --rpc-url http://localhost:8001 --value 1ether ``` ### Step 6: Check the Greet From 05db2c1ddf985317e2afd40c4436b36b173e85d8 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 19:38:19 +0100 Subject: [PATCH 7/8] fix: address fix --- docs/site/docs/develop/quickstart/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/site/docs/develop/quickstart/quickstart.md b/docs/site/docs/develop/quickstart/quickstart.md index 1df17683d..6f19d81ec 100644 --- a/docs/site/docs/develop/quickstart/quickstart.md +++ b/docs/site/docs/develop/quickstart/quickstart.md @@ -103,7 +103,7 @@ mock_arb: 0x8464135c8F25Da09e49BC8782676a84730C318bC ```bash -cast send 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 'greet(string)' 'Yay in 3 minutes!' --private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d --rpc-url http://localhost:8001 --value 1ether +cast send 0x8464135c8F25Da09e49BC8782676a84730C318bC 'greet(string)' 'Yay in 3 minutes!' --private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d --rpc-url http://localhost:8001 --value 1ether ``` ### Step 6: Check the Greet @@ -111,7 +111,7 @@ cast send 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 'greet(string)' 'Yay in 3 m 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 +cast call 0x8464135c8F25Da09e49BC8782676a84730C318bC "lastGreet():(uint64,uint256,uint256,address,address,string)" --rpc-url http://localhost:8000 ``` ### 🎉 Done 🎉 From 8ebac07d4081aef4c3239a0bc2ab5a81d77c5b2d Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 21 May 2024 19:45:39 +0100 Subject: [PATCH 8/8] fix: passing template name --- cli/cmd/develop.go | 32 +++----------------------------- cli/cmd/flags.go | 2 +- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/cli/cmd/develop.go b/cli/cmd/develop.go index 50d1d0a72..5f7d2d7ff 100644 --- a/cli/cmd/develop.go +++ b/cli/cmd/develop.go @@ -5,7 +5,6 @@ import ( "context" "os" "os/exec" - "strings" "github.com/omni-network/omni/lib/errors" @@ -45,7 +44,7 @@ func newForgeProjectCmd() *cobra.Command { } type developerForgeProjectConfig struct { - templateURL string + templateName string } // newForgeProjectTemplate creates a new project using the forge template. @@ -59,16 +58,9 @@ func newForgeProjectTemplate(_ context.Context, cfg developerForgeProjectConfig) } } - 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", sanitizedInput) + // #nosec G204 + cmd := exec.Command("forge", "init", "--template", "https://github.com/omni-network/"+cfg.templateName+".git") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -87,21 +79,3 @@ 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) { - // 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 -} diff --git a/cli/cmd/flags.go b/cli/cmd/flags.go index 6127fb110..86f8ca08f 100644 --- a/cli/cmd/flags.go +++ b/cli/cmd/flags.go @@ -25,7 +25,7 @@ func bindAVSAddress(cmd *cobra.Command, addr *string) { } 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") + cmd.Flags().StringVar(&cfg.templateName, "template", "hello-world-template", "Name of the forge template repo to use found in the omni-network github organization") } func bindDevnetAVSAllowConfig(cmd *cobra.Command, cfg *devnetAllowConfig) {