From 46b6825ce6b59325f40be3c00174f78a50e158f6 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:37:29 -0500 Subject: [PATCH] architecture and milestones --- README.md | 111 ++++++++++++++++++++++++++++++++++++++++++++++ environments.toml | 97 ++++++++++++++++++++++++++++++++++++++++ initialize.js | 2 +- 3 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 environments.toml diff --git a/README.md b/README.md index e7ffeb5..8351b04 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,114 @@ Goals: - `cp .env.example .env` - `npm install` - `npm run dev` + +# Architecture + +The Loam architecture will consist of two main elements: + +1. `loam-cli` +2. The frontend template + +The frontend template can be generated two ways: + +- `loam init` +- `soroban contract init [project-name] --frontend-template https://github.com/loambuild/template` + +Using the `soroban contract init` variant will automatically install `loam-cli` +using a `post-init` hook that we will add to soroban-cli as part of our initial +grant. + +The differentiating feature of Loam's frontend template: a declarative +`environments.toml` configuration file. In this file, you describe the network +settings, accounts, and contracts for each environment your team builds +against. `loam-cli` handles the rest. + +Check out [an example `environments.toml` here](./environments.toml). + +Aside from `loam init`, `loam-cli` will ship with two main commands: + +1. `loam dev` +2. `loam build` + +The most complex of these is `loam dev`. Let's break it down. + +## `loam dev` + +1. Defaults to `development` environment. This environment setting can be + changed with either the `--env` flag or with the `LOAM_ENV` environment + variable. + +2. Inspects the `environments.toml` file and gets things to the specified + predictable starting state: + + - starts the specified network + - creates and/or funds accounts + → on mainnet, will instead check that accounts exist and are funded + - For specified contracts: + - For an environment which uses a **local network**: + - For contracts which have **`workspace = true`**: + - **build** & **deploy** the contracts, saving the IDs so that on + subsequent runs it can instead + verify contracts are deployed and update them if needed. + - **initialize** the contracts: runs any specified `init` commands + (see `environments.toml` below) + - [Beyond the scope of initial grant]: For contracts which instead + specify an `environment`, `address`, and `at-ledger-sequence`: + - **spoon** the specified contract's state, at time of specified + ledger sequence, into the current environment's network. + - For an environment which uses **futurenet**, **testnet**, **mainnet** + or some other live network: + - **check** that the contracts exist on that network. Note: Loam does + not yet have plans to help with deploying the contracts. It only + checks that you have successfully done so yourself. + - For all environments: + - **bind** the contracts + - run `soroban contract bindings typescript` for each + - save each generated library to gitignored `packages/*`, part of the + [NPM workspace](https://docs.npmjs.com/cli/v10/using-npm/workspaces), + using the name specified in `environments.toml` + - **modify `networks` export** for each, to include all networks + specified in `environments.toml` + - **import** the contracts for use in the frontend. That is, create + gitignored `src/contracts/*` files for each, which import the + `Contract` class and `networks` object and export an instantiated + version for the current environment's network. + +3. Watch the `contracts/*` directory for changes, re-running all startup + logic when anything changes, to make sure the frontend stays up-to-date + with the contracts. + +This gets the frontend server ready to run. If using strict TypeScript, it also +means the frontend logic will be type-checked against the contract clients +generated for the given environment. If a production contract is slightly +different than a development/staging contract but has the same name, app +authors will need to add `LOAM_ENV` checks to their app logic, and build & +deploy separate frontends for each environment. + +`loam build` flows easily out of this. + + +## `loam build` + +This has the same behavior as `loam dev`, but defaults to +`LOAM_ENV=production`. It also only runs once, rather than watching +`contracts/*` for changes + + +# Milestones + +Given the above, within our initial grant roadmap, we have the following milestones: + +1. Create `loam-cli` with three subcommands: + - `loam init` + - `loam dev` + - `loam build` +2. Update `soroban contract init` command to safely honor a `post-init` hook + specified by the target `--frontend-template`, so that Loam's template can + install `loam-cli` +3. Expand the `loambuild/template` frontend template to include an example + `environments.toml` + +In a future grant, we have the following milestone: + +4. Allow specifying live contracts to spoon into local network diff --git a/environments.toml b/environments.toml new file mode 100644 index 0000000..adc9ef3 --- /dev/null +++ b/environments.toml @@ -0,0 +1,97 @@ +[development] +# If given `run-locally = true`, `network` will be launched with: +# +# soroban network start local +# +# You can use a shorthand version for `local`: +# +# network = "local" +network = { name = "local", run-locally = true } + +accounts = [ + # If you provide a string, an identity with this name will be created with + # `soroban keys`, which saves the mnemonic in `.soroban/identity`. + "alice", + + # Alternatively, you can provide an expanded definition. + # - `name`: the only required field, same behavior as string value above. + # - `default`: whether to use this account as the `--source` for commands + # that need one. See `init` below. Can only have one default. + # - `mnemonic`: a BIP39 mnemonic for the account. If not provided, a new + # keypair will be generated and saved in the `.soroban/identity` directory. + { name = "me", default = true, mnemonic = "boots and cats and boots and cats..." }, +] +default-account = "me" + +[development.contracts] +# Auto-build, -deploy, -bind, and -import all contracts in Cargo workspace +# Only supported in development & test environments +cargo-workspace = true + +# Instead of `cargo-workspace`, you can list each contract individually. +# `workspace = true` indicates that this project is part of the local cargo +# workspace. In dev & test environments, workspace contracts will be +# automatically built, deployed, initialized, bound, and imported. +soroban-atomic-swap-contract = { workspace = true } +soroban-auth-contract = { workspace = true } +soroban-errors-contract = { workspace = true } +soroban-hello-world-contract = { workspace = true } +soroban-increment-contract = { workspace = true } + +# If contracts need more settings, you can list them the long way. +[development.contracts.soroban-token-contract] +workspace = true + +# Initialization steps for the contract, to be run after deployment. +# Only supported in `development` and `test` environments. +# You only need to specify the slop (everything after the `--`) for calls to +# `soroban contract invoke` for the given contract. Uses `default-account` +# by default; to use another, prefix with `SOROBAN_ACCOUNT=other-account`. +init = """ +initialize --symbol ABND --decimal 7 --name abundance --admin me +mint --amount 2000000 --to me" +""" + +# Specify live contracts to bind & import in this project using the given name. +# During initialization, these contracts will also be "spooned" into the development network, +# meaning that their data will match the live network at the given sequence number. +[development.contracts.eurc] +environment = "production" +address = "C..." +at-ledger-sequence = 50153603 + + +[staging] +rpc-url = "https://soroban-testnet.stellar.org" +network-passphrase = "Test SDF Network ; September 2015" + +# or, to run your own network locally: +network = { name = "testnet", run-locally = true } + +accounts = [ + { name = "testnet-user", default = true }, +] + +[staging.contracts] +soroban-atomic-swap-contract = "C123..." +soroban-auth-contract = "C234..." +soroban-errors-contract = "C345..." +soroban-hello-world-contract = "C456..." +soroban-increment-contract = "C567..." +soroban-token-contract = "C678..." +eurc = "C789..." + +[production] +rpc-url = "https://our-custom-rpc-provider.cool" +network-passphrase = "Public Global Stellar Network ; September 2015" +default-account = "official-team-account" + +[production.contracts] +soroban-atomic-swap-contract = "C987..." +soroban-auth-contract = "C876..." +soroban-errors-contract = "C765..." +soroban-hello-world-contract = "C654..." +soroban-increment-contract = "C543..." +soroban-token-contract = "C432..." +eurc = "C321..." + diff --git a/initialize.js b/initialize.js index 2e37360..4bcc6a3 100644 --- a/initialize.js +++ b/initialize.js @@ -20,8 +20,8 @@ function exe(command) { } function fund_all() { + // will also fund the account since .env sets SOROBAN_NETWORK_PASSPHRASE && SOROBAN_RPC_URL exe(`${soroban} keys generate ${process.env.SOROBAN_ACCOUNT}`); - exe(`${soroban} keys fund ${process.env.SOROBAN_ACCOUNT}`); } function build_all() {