Skip to content

Commit

Permalink
architecture and milestones
Browse files Browse the repository at this point in the history
  • Loading branch information
chadoh committed Feb 13, 2024
1 parent 487345d commit 46b6825
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 1 deletion.
111 changes: 111 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
97 changes: 97 additions & 0 deletions environments.toml
Original file line number Diff line number Diff line change
@@ -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..."

2 changes: 1 addition & 1 deletion initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 46b6825

Please sign in to comment.