Coder Social home page Coder Social logo

beaker's Introduction

Beaker

Beaker logo

Beaker is a versatile toolkit that simplifies interactions with CosmWasm smart contracts. It offers project scaffolding, seamless deployment, upgrades, execution, querying, an interactive console, task scripting capabilities and more for a streamlined development experience.


Table of Contents

Getting Started

Reference


Getting Started

This section is intended to give you an introduction to Beaker, for more detailed reference, you can find them here.

Prerequisites

  • Rust for building cosmwasm contract
    • Rustup for dealing with wasm target
  • Docker for running wasm rust-optimizer and spinning up LocalOsmosis
  • Node for frontend related stuffs and beaker-console
    • Yarn over NPM, since it will not have package resolving issue and causes weird errors down the road

Installation

Beaker is available via cargo which is a rust toolchain. Once cargo is ready on your machine, run:

cargo install -f beaker # `-f` flag for up-to-date version

Now beaker is ready to use!

Scaffolding your new dapp project

In the directory you want your project to reside, run:

beaker new counter-dapp

This gives you 2 template options to choose from. For the sake of this tutorial, let's use counter-example but you might want to use minimal option in your real work since it has zero assumption about your dapp logic or frontend.

? ๐Ÿคท   Which starting template would you like to use? โ€บ
  minimal
โฏ counter-example

This will generate new directory called counter-dapp which, by default, come from this template.

So what's in the template? Let's have a look...

.
โ”œโ”€โ”€ frontend
โ”œโ”€โ”€ contracts
โ”œโ”€โ”€ Cargo.toml
โ”œโ”€โ”€ Beaker.toml
โ”œโ”€โ”€ .gitignore
โ””โ”€โ”€ .beaker

frontend

This should be self explanatory, it's where frontend and contracts are stored.

With counter-example template, it demonstrate how frontend app can access deployed code/contract's info through .beaker. It does so by symlinking .beaker into frontend directory, and since states in .beaker are in json format, javascript code can just import them.

With minimal template, this directory does not exist, which means it does not assume your frontend choice. In that case, you might want to checkout create-cosmos-app for scaffolding your frontend or just create one from scratch.

contracts

This is where smart contracts are stored. Single workspace can contain multiple contracts.

With counter-example template, this should have counter contract pregenerated.

Cargo.toml

There is a Cargo.toml here which specifies cargo workspace.

[workspace]

members = [
  'contracts/*',
]

[profile.release]
...

All the crates (rust packages) in contracts directory are included, with unified release profile. With this, when we have to optimize multiple contracts deterministically, we can do that with ease (see Contracts as Workspace Members section in rust-optimizer).

Beaker.toml

This is our configuration file, you can find more information about it here.

.beaker

Last but not least, .beaker which is the most unusal part. It contains 2 files:

โ”œโ”€โ”€ state.json
โ””โ”€โ”€ state.local.json

These 2 files has similar functionality, which are containing beaker related state such as address, code-id, label for each contract on each network for later use.

While state.json is there for mainnet and testnet state. state.local.json is intended to use locally and being gitignored since its state will not make any sense on other's machine.

And I don't think we have to explain about .gitignore don't we?


Scaffolding new CosmWasm contract

We can scaffold new contract using the following command:

cd counter-dapp
beaker wasm new <contract_name>

Default template is from osmosis-labs/cw-minimal-template

The cw-minimal-template has no logic in it unlike cw-template, only the skeleton is provided, which makes it ideal to start writing new contract.

Now your new contract will be avaiable on contracts/multiplier.

If you want to use other contract template, you can change the configuration, for example:

# Beaker.toml

[wasm]
template_repo = "https://github.com/CosmWasm/cw-template"

This step is not required for the rest of the guide since counter contract is already in place, but you can just try it out.

Deploy contract on LocalOsmosis

LocalOsmosis, as it's name suggest, is Osmosis for local development. In the upcoming release, Beaker will have more complete integration with LocalOsmosis, it has to be installed and run separately.

You can use the osmosis installer and select option 3:

curl -sL https://get.osmosis.zone/install > i.py && python3 i.py

Or if you want to use a specific / modified version of LocalOsmosis, you can build from source by

git clone https://github.com/osmosis-labs/osmosis.git

make localnet-build # build docker image
make localnet-start # docker-compose up

Now, with LocalOsmosis up and running, counter contract can be deployed (build + store-code + instantiate) using the following command:

beaker wasm deploy counter --signer-account test1 --no-wasm-opt --raw '{ "count": 0 }'

What's happending here equivalent to the following command sequence:

# build .wasm file
# stored in `target/wasm32-unknown-unknown/release/<CONTRACT_NAME>.wasm`
# `--no-wasm-opt` is suitable for development, explained below
beaker wasm build --no-wasm-opt

# read .wasm in `target/wasm32-unknown-unknown/release/<CONTRACT_NAME>.wasm` due to `--no-wasm-opt` flag
# use `--signer-account test1` which is predefined.
# The list of all predefined accounts are here: https://github.com/osmosis-labs/LocalOsmosis#accounts
# `code-id` is stored in the beaker state, local by default
beaker wasm store-code counter --signer-account test1 --no-wasm-opt

# instantiate counter contract
# with instantiate msg: '{ "count": 0 }'
beaker wasm instanitate counter --signer-account test1 --raw '{ "count": 0 }'

The flag --no-wasm-opt is skipping rust-optimizer for faster development iteration.

For testnet/mainnet deployment, use:

beaker wasm deploy counter --signer-account <ACCOUNT> --raw '{ "count": 0 }' --network testnet
beaker wasm deploy counter --signer-account <ACCOUNT> --raw '{ "count": 0 }' --network mainnet

Instantiate message can be stored for later use:

mkdir contracts/counter/instantiate-msgs
echo '{ "count": 0 }' > contracts/counter/instantiate-msgs/default.json
beaker wasm deploy counter --signer-account test1 --no-wasm-opt

You can find references for beaker wasm subcommand here.

Contract Upgrade

Contract upgrade in CosmWasm goes through the following steps:

  1. store new code on to the chain
  2. broadcast migrate msg, targeting the contract address that wanted to be upgraded with the newly stored code

To make a contract migratable, the contract needs to have proper entrypoint and admin designated.

To create the contract entrypoint for migration, first, define MigrateMsg in msg.rs, this could have any information you want to pass for migration.

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct MigrateMsg {}

With MigrateMsg defined we need to update contract.rs. First update the import from crate::msg to include MigrateMsg:

use crate::msg::{CountResponse, ExecuteMsg, InstantiateMsg, QueryMsg, MigrateMsg};
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
    // perform state update or anything neccessary for the migration
    Ok(Response::default())
}

Now deploy the contract with admin assigned

# `--admin signer` use signer address (test1's address in this case) as designated admin
# raw address could be passed in as well
beaker wasm deploy counter --signer-account test1 --no-wasm-opt --raw '{ "count": 0 }' --admin signer

Now try to change the execute logic a bit to see if the upgrade works:

pub fn try_increment(deps: DepsMut) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        state.count += 1000000000; // 1 -> 1000000000
        Ok(state)
    })?;

    Ok(Response::new().add_attribute("method", "try_increment"))
}

With admin as test1, only test1 can upgrade the contract

beaker wasm upgrade counter --signer-account test1 --raw '{}' --no-wasm-opt

Similar to deploy, upgrade is basiaclly running sequences of commands behind the scene:

beaker wasm build --no-wasm-opt
beaker wasm store-code counter --signer-account test1 --no-wasm-opt
beaker wasm migrate counter --signer-account test1 --raw '{}'

And, like before, --no-wasm-opt only means for developement. For mainnet, use:

beaker wasm upgrade counter --signer-account test1 --raw '{}' --network mainnet

Migrate message can be stored for later use:

mkdir contracts/counter/migrate-msgs
echo '{}' > contracts/counter/migrate-msgs/default.json
beaker wasm upgrade counter --signer-account test1 --no-wasm-opt

You can find more information about their options here.

Execute Contract Messages

Contract messages can be executed using the beaker wasm execute subcommand. For example:

beaker wasm execute counter --raw '{ "increment": {} }' --signer-account test1

Query Contract State

You can query contract state by submitting query messages with the beaker wasm query command. For example:

beaker wasm query counter --raw '{"get_count": {}}'

Signers

Whenever you run command that requires signing transactions, there are 3 options you can reference your private keys:

  • --signer-account input of this option refer to the accounts defined in the config file, which is not encrypted, so it should be used only for testing
  • --signer-mnemonic input of this option is the raw mnemonic string to construct a signer
  • --signer-private-key input of this option is the same as --signer-mnemonic except it expects base64 encoded private key
  • --signer-keyring use the OS secure store as backend to securely store your key. To manage them, you can find more information here.

Tasks

Sometimes you want to run a series of commands in a single command. For example, you want to deploy a set of contracts that one contract instantiation depends on another contract. You can do this by defining a task in the tasks directory.

beaker task new deploy

This will create a new task file in tasks/deploy.rhai.

Task is written in Rhai which is an embedded scripting language in Rust. You can find example of how to write Rhai here.

Using Rhai as a scripting language makes exposing all existing functionality of Beaker to the task script relatively simple. Currently, all the subcommands of beaker wasm are exposed to the task script. So you can do things like:

let counter_contract = wasm::deploy(merge(
    #{
        signer_account: "test1"
        contract_name: "counter",
        msg: #{}
    }
));

let counter_proxy_contract = wasm::deploy(merge(
    #{
        signer_account: "test1"
        contract_name: "counter",
        msg: #{
            counter_contract_address: counter_contract.address
        }
    }
));

The interface of wasm::deploy the same as the beaker wasm deploy command. Other functions in wasm module are also similar to their corresponding subcommands so you can refer to the documentation for more information about what is avialable in the script.

Note that additional feature here is that msg can also be passed as an object rather than passing JSON string to raw.

There are also some additional helper function and macros that are exposed to the task script.

fs module

This module provides access to the file system. It is similar to the std::fs module in Rust. Morre information about the module can be found here. This is how it can be used in the task script:

file = fs::open_file("params.json");

match_args

Matching command line arguments passed to the script and returns a map of the arguments

// beaker task run deploy -- --signer test1 --build-flags no_wasm_opt
let cli_args = match_args(["signer", "build_flags"]);

print(cli_args) // => #{ signer: "test1", "build_flags": "no_wasm_opt" }

merge

Merges 2 objects together. If there are duplicate keys, the value from the second object will be used.

let a = #{ a: 1, b: 2 };
let b = #{ b: 3, c: 4 };

let merged = merge(a, b);

print(merged) // => #{ a: 1, b: 3, c: 4 }

@assert

Perform assertion on the given condition. If the condition is false, the script will exit with an error. This is useful for ensuring that the script is running as expected.

@assert(1 == 1); // pass
@assert(1 == 2); // fail

@assert(1 != 2); // pass
@assert(1 != 1); // fail

@assert(1 < 2); // pass
@assert(1 > 2); // fail

@assert(1 <= 2); // pass
@assert(1 >= 2); // fail

For more example on how to use task, you can refer to the example tasks.

Console

After deployed, you can play with the deployed contract using:

beaker console

It might prompt you like the following:

? Project's Typescript SDK seems to be missing, would you like to generate?

Press enter to proceed for now, and we will discuss about it in detail in the Typescript SDK Generation section.

This will launch custom node repl, where contract, account are available. contract contains deployed contract. account contains pre-defined accounts in localosmosis.

So you can interact with the recently deployed contract like this:

await contract.counter.signer(account.test1).execute({ increment: {} });
await contract.counter.query({ get_count: {} });

You can find avaialable methods for the aforementioned instances here:

You can remove contract and/or account namespace by changing config.

# Beaker.toml

[console]
account_namespace = false
contract_namespace = false
await counter.signer(test1).execute({ increment: {} });
await counter.query({ get_count: {} });

With the Typescript SDK which was previously mentioned, it is used to extend the Contract instance with method generated ftom execute and query messages. For example:

await counter.getCount();

sc = counter.signer(test1); // create signing client for `counter` with `test1`

await sc.increment();
await sc.getCount();

With this, it's more convenient than the previous interaction method since you can use tab completion for the methods as well.

Beaker console is also allowed to deploy contract, so that you don't another terminal tab to do so.

.deploy counter -- --signer-account test1 --raw '{ "count": 999 }'

.build, .storeCode, .instantiate commands are also available and has the same options as Beaker cli command, except that --no-wasm-opt are in by default since it is being intended to use in the development phase.

.help to see all avaiable commands.

Apart from that, in the console, you can access Beaker's state, configuration and sdk from state, conf and sdk variables accordingly.

Typescript SDK Generation

Beaker leverage ts-codegen to generate typescript client for cosmwasm contract. By default, Beaker's template prepare ts/sdk directory where typescript compiler and bundler are setup, so the generated client definition could be used by beaker-console, frontend or published as library for others to use.

To generate sdk for contract, run

beaker wasm ts-gen counter # replace `counter` with any of contract name

With this a package is avaiable in ts/sdk with name <project-name>-sdk which can be used by any node / js / ts project.

The underlying code that actually calls ts-codegen with configuration is located in ts/sdk/scripts/codegen.js.

Let's try adding multiply method to our contract and see how this works.

// msg.rs

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Increment {},
    Multiply { times: i32 }, // [1] add this enum variant
    Reset { count: i32 },
}
// contract.rs

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::Increment {} => try_increment(deps),
        ExecuteMsg::Multiply { times } => try_multiply(deps, times), // [2] add this match arm
        ExecuteMsg::Reset { count } => try_reset(deps, info, count),
    }
}

// [3] add this function
fn try_multiply(deps: DepsMut, times: i32) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        state.count *= times;
        Ok(state)
    })?;

    Ok(Response::new().add_attribute("method", "try_multiply"))
}

Then redeploy the contract:

beaker wasm deploy counter --signer-account test1 --no-wasm-opt --raw '{ "count": 0 }'

Then regenerate counter's client

beaker wasm ts-gen counter

Now we can test it out in the beaker console

sc = counter.signer(test1);

await sc.increment();
await sc.getCount();
// => { count: 1 }

await sc.multiply({ times: 2 });
await sc.getCount();
// => { count: 2 }

await sc.multiply({ times: 10 });
await sc.getCount();
// => { count: 20 }

sc is an instance of CounterContract which you can find it in ts/sdk/src/contracts/CounterContract.ts.

Frontend

Beaker project template also come with frontend template. But in order to interact with it you need:

Now we are good to go! Let's dive in

cd frontend
yarn && yarn dev

Then open http://localhost:3000/ in the browser.

In frontend directory, you will see that .beaker is in here. It is actually symlinked to the one in the root so that frontend code can access beaker state.


License

The crates in this repository are licensed under either of the following licenses, at your discretion.

Apache License Version 2.0 (LICENSE-APACHE or apache.org license link)
MIT license (LICENSE-MIT or opensource.org license link)

Unless you explicitly state otherwise, any contribution submitted for inclusion in this library by you shall be dual licensed as above (as defined in the Apache v2 License), without any additional terms or conditions.

beaker's People

Contributors

daniel-farina avatar dependabot[bot] avatar dzmitry-lahoda avatar iboss-ptk avatar miohtama avatar rrrliu avatar valardragon avatar vernonjohnson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

beaker's Issues

Test Keplr and LocalOsmosis

  • Detects Keplrs
  • Add localosmosis chainโ€™s config (chain-id, local endpoint)
  • Load one of the localOsmosis wallets (test1 account) (manually for now)
  • Keplr connects and gets the balance no problem

Nice to have adding to backlog

  • Automatically add wallets to Keplr

console: contract instance

  • contract with default label with props:
    • address
    • query
    • execute().by(account)
  • contract with other label
await contract.counter.execute({ increase: {}}).by(account.test1)
await contract.counter.query({ get_count: {} })

await contract.counter.$awesome.execute({ increase: {}}).by(account.test1)
await contract.counter.$awesome.query({ get_count: {} })

Contract Upgrades

We need to define the upgrade process for a contract. What are the requirements and steps to accomplish this? We should do this via CLI first.

This is currently blocked by #58 [it's closed, no longer blocked]

Getting started guide

Writing getting started guide to guide through the process user needs to go through.

This serves 2 purpose:

  1. as the name suggest; documentation for getting started with the tool
  2. design space to think in terms of the user how to use the tool

Mark work in progress section as WIP and link to the issue.

Definition of done

Narrate through the process of

  • scaffolding project workspace
  • create new contract in the workspace
  • contract deployment process
  • interactive console
  • configure target to testnet / mainnet
  • frontend integration

Changes are expected but this must serves as a skeleton for further modification


tips

beaker[local] โ—‡ contract.counter.query({ get_count: {} })
Promise {
  <pending>,
  [Symbol(async_id_symbol)]: 396,
  [Symbol(trigger_async_id_symbol)]: 97
}
beaker[local] โ—‡ await _
{ count: 101 }

console: setup

interactive console has the following purposes:

  • as oppose to writing integration test, which has the role to automate regression test, this provides a quick and straightforward way to understand how smart contract or set of smart contracts behave and inspect them.
    • when changing smart contract code, from code changes to updated behavior when interact with the console should flow smoothly
    • inspecting smart contract state should be simple, no need custom query command
    • client for the contract must be generated and if using beaker to instantiate, client for each contract instance must be provided, accessible via label

TODO

Governance Submission

Todo

  • try osimosisd to go through the process
  • start with gov store-code
    • reconstruct this msg in rust https://github.com/CosmWasm/wasmd/blob/ac92fdcf37388cc8dc24535f301f64395f8fb3da/proto/cosmwasm/wasm/v1/proposal.proto and try rpc-ing it

    • make gov proposal works

    • refactor types -> gen types -> get path

    • expose proposal related stuffs to the interface

    • check mainnet config with command provided by Dev & see plan about gov

    • [BLOCKED] try editing genesis.json remove permission to test the process (with for nico / adam response)

    • fix state file: non has config for local and shared network

      • serialize config for state variant
      • get state variant from context (check by network)
      • update state file based on state variant (pass as arg)
    • PropsoalStoreCodeResponse

    • make deposit works (for today: 7 Jun)

    • check deposit

    • extract module

    • update state for proposal

      • make code_id optional
      • add proposal_id
      • add update_proposal_id function
    • find the hash function for code_hash -> sha256sum

    • create query for proposal

    • refactor: extract modules

    • move ops into their own module

    • beaker wasm proposal vote store-code counter --amount 10000uosmo {{base_tx}}

      • create proposal/ops/vote.rs
      • copy code from store code
      • get the right message in, make sure code compiles
        • get_ref . proposal_store_code_id to query
      • update entry point with respective stuffs needed
    • beaker wasm proposal store-code sync-state

      • update_in! for handling nested struct (see [1], [2])
      • new struct for proposal
// ultimately
struct Code {
  id: u64,
  instances: Map<String, String>
}

struct Proposal {
   store_code: Option<u64>
}

struct WasmRef {
    code: Option<Code>
    proposal: Proposal,
}

Refactor to ts

  • build ts
  • try import built artefacts into console.js
  • start extracting lib type logic out
    • identify with comments
    • extracts

Improving error message for wasm proposal

Hitting this error when using mainnet (an account with no funds on mainnet) test1.

beaker wasm proposal store-code --title "Mainner Contract" --description "Official Contract for" --signer-account test1 --network mainnet counter --gas 100000uosmo --gas-limit 100000

The expected result should be something about not having enough funds.
Output:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: serde parse error

Caused by:
    expected value at line 1 column 1

Location:
    /Users/web/.cargo/registry/src/github.com-1ecc6299db9ec823/flex-error-0.4.4/src/tracer_impl/eyre.rs:10:9

Caused by:
   0: serde parse error
   1: expected value at line 1 column 1

Location:
    /Users/web/.cargo/registry/src/github.com-1ecc6299db9ec823/cosmrs-0.7.1/src/tx/raw.rs:34:12', /Users/web/.cargo/registry/src/github.com-1ecc6299db9ec823/beaker-0.0.4/src/support/cosmos.rs:246:77
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Contract instance with CosmWasm typescript-gen

  • fix cw-template type bug (test by cargo generate with local git)
  • beaker wasm ts-gen <contract_name>: leverage https://www.npmjs.com/package/cosmwasm-typescript-gen
    • call cargo schema
    • cosmwasm-typescript-gen generate \ --schema ./path/to/schema \ --out ./path/to/ts/sdk \ --name MyContractName
    • ts/sdk (> {{project-name}}-sdk}}) with ts boilerplate stuffs
  • options
    • cargo schema schema gen command
    • schema outout dir
    • client gen output dir
  • refactor
    • to ops
    • extract npx
  • upgrade console
    • link beaker-console
    • specify beaker-console version on npx
  • regen docs
await account.test1.sign(contract.counter).increase()
await contract.counter.getCount()

with global

await counter.with(test1).increase()
await counter.getCount()

Make a command to setup Rust dependencies

In docs.osmosis.zone, we note that users need to run

rustup target add wasm32-unknown-unknown
cargo install cargo-generate --features vendored-openssl
cargo install cargo-run-script

It'd be cool if any beaker command could set these up for you, if its not already handled. (Reduces the amount of installation steps folks have to do)

Change default CI for contracts to github actions

Is there a reason why the CI generated for contracts right now is circleCI vs github actions? (e.g. speed?)

Would be nice to have the normal flow "just work" when put on github, whereas circleCI requires some extra configuring.

Localosmosis wrapper

  • localosmosis subcommand
    • start
    • clean
    • update
    • setup-keplr
  • config:
    • path to store localosmosis code

Deploy

Deploy

The deployment process = code => [build, optimize, store-code, instantiate], which can have multiple instantiation.
Assumption is, if they use this method, they will just use the same signer...

$ beaker deploy counter --signing-account test1 
$ beaker deploy counter --signing-account test1 
$ beaker deploy counter --signing-account test1 --no-rebuild

args:

contract_name,
raw
chain_id,
signer_args,
gas_args,
timeout_height,
label

Assumptions

  • shared gas params (2 txs, so actual gas limit is doubled) make it better in #14
  • shared signer params
  • chain_id (change chain_id to network once working on #15 )

Todo

  • use instantiate args & copy instanitate code
  • add store-code logic before instanitate
  • make building and optimizing default, add it to the logic before all
  • add flag --no-rebuild and impl the logic

Cut release

  • templatize frontend
  • symlink on generate
  • fix .beaker: remove package
  • set package version (-rc)
  • publish on cargo
  • npm (waiting for permission)
  • test out fresh (potentially on gitpod)
  • write getting started guide

console: accounts

  • serialize config as json and pass it into console args
  • create wallets from mnemonics
    • args: menmonics, prefix, hdpath
  • create signing client
    • args: rpcEndpoint, gasPrice
  • Object.assign(globol, account) option with renaming to avoid scope polution
await contract.counter.increase().by(account.test1)
await contract.counter.getCount()

with global

await counter.increase().by(test1)
await counter.getCount()

Store code

  • Store code
  • Rename cw to wasm
  • Save code id in the state file (only local one for now, leave the non-local to #12 )
    • create support::state module
      • define struct
      • load (use it to load file relative to root $WORKSPACE_ROOT/.membrane/state.local.json
      • modify
      • save

Defaulted to local network ( = --network local but not implemented at the moment)

$ membrane wasm store-code counter
|-- .membrane
|    |-- state.json
|    |-- state.local.json // if chain-id is defined to be local (localosmosis)

use latest only until the need arise...

{
  "<chain-id>": {
    "counter": {
      "code-id": 1,
      "address": {
        "default": "..",
      }
    }
  }
}

state file utils:

Not in scope

  • #13
  • Support testnet & mainnet store code #12

[Research] CosmWasm path to production (mainnet)

This issue is for tracking the clarification of the path to production (mainnet) for CosmWasm. Since Osmosis implements permissioned CosmWasm, See what are the steps to take, who is involved in order to have clear understanding on what Beaker should support, who else needs to be involved, what system needs to eventually be upgraded and later we can have a clear documentation for the dapps developer.

The following is my attempt to flesh out the understandings along with โ“ questions and ๐Ÿ’ก ideas.

Grouping for wasm gov proposal types

According to the wasm gov docs, there are additional proposal types for wasm gov. Grouping by their functions for further reference:

  • Deployment and Migration (**main focus for this issue)

    • StoreCodeProposal
    • InstantiateContractProposal
    • MigrateContractProposal
  • Code Permission

    • UpdateAdminProposal
    • ClearAdminProposal
    • UpdateInstantiateConfigProposal
  • Code Pinning

    • PinCodes
    • UnpinCodes
  • Execution

[โ“ 1] on mainnet, which of the above are required to be execute through governance?
๐Ÿ“ Answer 1 by @czarcas7ic

[๐Ÿ’ก 1] Same wasm gov configuration as mainnet for testnet (stagenet?) and/or localosmosis variation would be ideal for testing. @czarcas7ic @nicolaslara

For Code Pinning and Execution, if the [โ“ 1] is clear, it doesn't seem to be important for this issue. Let's move on to the main topic.

Deployment and migration

StoreCode requirements

There was a discussion with @ValarDragon @daniel-farina about hash verification and contract-list

This is what I imagine would happen if there is a need to store code:

graph TD
    StoreCode[Submit `StoreCodeProposal`]
    SubmitRepo[Submit source and metadata]
    Val{validate}
    Voting[Gov Voting]

    StoreCode == wasm byte code ==> Val
    SubmitRepo == source code & build metadata ==> Val
    Val -->|passed| Voting
Loading

[โ“ 2] should we require hash validation before triggering the voting period of the proposal? if so it sounds like a chain upgrade, what else could be an alternative? @ValarDragon

๐Ÿ“ Answer 2 by @daniel-farina

The StoreCodeProposal already contains wasm byte code, one can get that by querying the proposal.
For Submit source and metadata this would trigger a question:

[โ“ 3] In what format should we store the source reference & build metadata (for deterministic build)?
๐Ÿ“ Answer 3 by @daniel-farina

[๐Ÿ’ก 3] Specific & special region in the proposal description for source reference & build metadata

[โ“ 4] Do we require public git repository? or just upload an archive somewhere?
๐Ÿ“ Answer 4 by @daniel-farina

[โ“ 5] Where does contract list update sits in the process?
๐Ÿ“ Answer 5 by @daniel-farina

Deployment

This is normally a 2 steps process of StoreCode -> InitiateContract, but common pattern of a dapp has the following:

  1. StoreCode -> InitiateContract tends to happen sequentially.
  2. A dapp can have more than 1 code/contract and could be depending on each other

The following graph is a general execution plan for a deploying a dapp.

image

[๐Ÿ’ก 6] Note that this structure is dependency graph so the process as code @daniel-farina mentioned in #48 could incorporate the whole flow like what terraform does.

[โ“ 7] Is it possible / how hard it is to have multiple related proposals (like in the process above) to go through the gov together as bundled proposal? Does it make sense to do so? I can imagine how this could simplify the flow... @ValarDragon @sunnya97

Migration

The following graph is a general execution plan for a migrating multiple contract for a dapp. It shares the same question as for the deployment.

image

Lastly:

[โ“ 8] Will we use https://commonwealth.im/osmosis/ for wasm governance?
๐Ÿ“ Answer 8 by @daniel-farina

Let me know your thoughts.

Instantiate

$ membrane wasm instantiate counter --raw '{ "counter": 0 }' # imply --label default
$ membrane wasm instantiate counter --raw '{ "counter": 0 }' --label "sth"

# won't work with --code-id
$ membrane wasm instantiate counter # use counter/instantiate-msgs/default.json
$ membrane wasm instantiate counter one # use counter/instantiate-msgs/one.json, imply --name "one"
  • instantiate with raw string
    • without name
      • test request (let's try cosmwasm js)
      • save address
      • check if same label can use twice or not?
      • return instantiate response
      • refactor
        • shared arguments
          • create SignerArg
          • implement SignerArg method
          • create GasArg
          • Implement GasArg method
          • compute fee logic before passing into ops (-> fix too many args)
          • create coin.rs
          • parse denom from gas input
          • remove denom global config
        • add gas input
        • shared logic
        • format result
          • Event formatter (create support/format)
          • marcro for formatter
          • Add important info, implications to result: address, code_id, label, creator, admin, (ibc_port_id could be separated part, IBC support)
    • with label
  • instantiate with file
    • default.json
    • {label}.json
  • fill all the mnemonics

[Research] List steps to verify contract hash

Inspecting contract

First, create new contract

https://docs.osmosis.zone/developing/dapps/get_started/cosmwasm-testnet.html
image

Once the contract is created we can check query the contract information. Assuming you are connected to the testnet.

contract_info

osmosisd query wasm contract osmo1mpf0guu0t363xrshhedandypq003ahzaxvsxzgu69n3ej03mh2zqx5gk8l

Output:
image

contract version

osmosisd query wasm contract-state raw osmo1mpf0guu0t363xrshhedandypq003ahzaxvsxzgu69n3ej03mh2zqx5gk8l 636F6E74726163745F696E666F --node https://rpc-test.osmosis.zone:443 --output json | jq  -r .data | base64 -d | jq

What in the world is 636F6E74726163745F696E666F? ๐Ÿ˜•

ContractInfo is must be stored under "contract_info" key which translates to "636F6E74726163745F696E666F" in hex format. As documented here.

Output:
image

Downloading the Contract from the network

osmosisd query wasm code 205 205_code.wasm --node https://rpc-test.osmosis.zone:443

Output:
image

Getting the hash

sha256sum 205_code.wasm

Output :
image

0b662785042cd938d0f0e8142f69d2d23fdf0addec965d1fbeacf44080330016

Verify hash

Now it's time to verify the hash with the source repos. All contracts should provide a repository with a hash for their contracts the same way that cw-plus does on their checksum as shown below:

10bc1a8cf82055106b26136f26137d6bf132df99c2d2098a75d03b64e7fe75a5  cw1155_base.wasm
539b62678532596c73b27764186623a2bb868f5e67c3e588508c4a28e105e8c9  cw1_subkeys.wasm
b67bc69fef770c28d48730feb800ea9c91eaae1a608e3ea7819aac64a6e99d92  cw1_whitelist.wasm
704890409d0e82f33951f0f4d06e42b27082d91b5c8c98853969296191244baf  cw1_whitelist_ng.wasm
db366741dcbad5f2e4933cda49133cd2a11fdb32b08c67cb1d22379bd392448e  cw20_base.wasm
ac452ac5c96ac843cad0267a0f465d39f6dd43d4e47631e6deefd23a4cf77a61  cw20_ics20.wasm
b3d44429dfb1e445a7ea3c0125b71efdc85185666f35e4e62581ffc1310905bd  cw3_fixed_multisig.wasm
62131b508b448dad7d7878188f55b674c24a1b705791179b87e85e0854538837  cw3_flex_multisig.wasm
163566b6f65819c2ea6cadddc847cbaaa59f5218dbbd895bcc2fcefe1afd7d0e  cw4_group.wasm
0c44f17035eb51c0115d95f14e83ce2cdfbcb804ffa95e1f8203d22300d6ba90  cw4_stake.wasm

Instantiate permission when store code

When store code, the code stored can have permission of who could instantiate the contract. The permission can be put in the StoreCodeMsg.

This issue is for tracking the implementation and pose the question of it's priority which depends on the discussion on #59
edit: since instantiation is permissionless, this is now important..

Use keyring for signing (Signer-account)

For the signer-account option I think having a few predefined ones works well for localosmosis but for testnet/mainnet it would be best to use:

  • use system keyring so that I can use my own keys
  • option to specify the keyring backend

https://docs.cosmos.network/master/run-node/keyring.html

I guess we could call them:
system-signer-account && beaker-signer-account?

This way we can allow people to request testnet tokens via the faucet for their own addresses, and eventually add an option to the faucet to approve contracts as well as we discussed yesterday.

console: redeploy command

Purpose:
when in console, if you want to keep the state and update stuffs without leaving console, you can hit .redeploy, it will just rebuild, store-code, instantiate everything that exists

  • option for global account & contract
  • .redeploy
.deploy counter test1

New dApp templates to demonstrate Beaker & tooling integrations

Currently, beaker only has the basic counter example. I believe there is a need to expand scaffolded-dApp variety to encourage more builders to build via a bit more structure. These additional examples can help demonstrate tooling (such as various requests for custom cosmwasm bindings) that you can integrate with beaker.

Current list

  • tokenfactory (already done, just needs to make beaker compatible)
  • Escrow test contract
  • CW20 Pot

Bug

  • item 1
  • item 2
  • item 3

Wasm proposal.yml

Submitting a proposal is currently done this way:

beaker wasm proposal store-code --title "Testnet Contract" --description "Testnet Contract" --signer-account test1 --network testnet counter --gas 25000000uosmo --gas-limit 25000000
  • We should be able hardcode maximum gas (In mainnet this won't be more than 1 OSMO)

I think we could simplify this by making a yaml file instead or json. This will be really useful as the description can be quite long.

beaker wasm proposal store-code --proposal proposal_407.yaml counter

Example proposal.yml idea

title: Proposal to allow DappName to be enabled in Osmosis
description: |
            A lengthy proposal description
            goes here  
            we expect this to be many lines...
code:
    github:   https://github.com/osmosis-labs/beaker/
    reviewed_by: https://....
settings: 
    gas:  25000000uosmo 
    network: testnet

Notes

  • create struct that has all proposal options
  • make the struct subcommand compatible and serde serializable
  • allow serialization for toml, yaml
  • put the code part as a metadata structure in the proposal description

Non local deployment

  • expose network flag, change chain_id flag to network flag
  • make client configuration base on network name
  • [-] change everything to grpc instead of rpc
  • test it on testnet (pending public testnet)
  • update non-local state instead of local state

Endpoints

Testnet

  • rpc-test.osmosis.zone
  • grpc-test.osmosis.zone:9090

Mainnet

  • rpc.osmosis.zone
  • grpc.osmosis.zone:9090

Clean up 1st round

  • impl --no-optimize
    • build: --optimize -> --no-optimize
    • store-code: add --no-optimize to store non-release target, faster build
    • deploy: add --no-optimize
  • optimizer
    • Extract workspace optimizer version to config
  • Instantiate
    • add funds
  • use non-local cosmos-proto

Configuration reference

The idea here is to get the config struct documentation at runtime to generate md file that has details

  • derive_get_docs
    • get docs from simple struct
    • move test to proper place > example
    • nested struct must be compatible with prev get docs
    • get docs from nested struct
  • refactor md gen into its own package so that md package only focus on generating md and use cli and get_docs as deps
  • gen README.md
  • treat doc strings as cmark structure
  • add type information
    • in general
    • take care of optional
    • take care of map
  • Brush up description
  • rename fn get_docs -> get_data_docs;
  • rename crate derive_get_doc -> data_doc_derive, get_docs -> data_doc
  • draft the config doc structure
  • generate config doc
struct Docs(Vec<Doc>);

struct DataDoc {
  ident: String,
  desc: Vec<String>,
  sub_docs: Vec<DataDoc>
};

trait GetDataDocs {
  get_data_docs() -> Vec<DataDoc>;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.