Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
feat: set up client structure

add command skeleton and table migrations

lints and remove testing prints

fmt]

add log to crate

testing feature so that PoW in seed grinding does not take long

addressing reviews

map_err

fix deserialization

remove further unwraps

add test

address further reviews

use new functions

address reviews

prettier table

replace tabled with no std alt

add SQL relations

align comments

feat: add github ci workflow

feat: introduce input notes db and list command

prettier wrapping table
  • Loading branch information
bobbinth authored and juan518munoz committed Nov 28, 2023
0 parents commit 86b39cb
Show file tree
Hide file tree
Showing 16 changed files with 1,355 additions and 0 deletions.
69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: CI
on:
push:
branches:
- main
pull_request:
types: [opened, repoened, synchronize]

jobs:
test:
name: Test Rust ${{matrix.toolchain}} on ${{matrix.os}}
runs-on: ${{matrix.os}}-latest
strategy:
fail-fast: false
matrix:
toolchain: [stable, nightly]
os: [ubuntu]
steps:
- uses: actions/checkout@main
- name: Install rust
uses: actions-rs/toolchain@v1
with:
toolchain: ${{matrix.toolchain}}
override: true
- name: Test
uses: actions-rs/cargo@v1
env:
RUSTFLAGS: -C debug-assertions
with:
command: test
args: --release

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: Install minimal stable with clippy
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
components: clippy
override: true

- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all --all-targets -- -D clippy::all -D warnings

rustfmt:
name: rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: Install minimal stable with rustfmt
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
components: rustfmt
override: true

- name: rustfmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
43 changes: 43 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-toml
- id: pretty-format-json
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: detect-private-key
- repo: https://github.com/hackaugusto/pre-commit-cargo
rev: v1.0.0
hooks:
# Allows cargo fmt to modify the source code prior to the commit
- id: cargo
name: Cargo fmt
args: ["+stable", "fmt", "--all"]
stages: [commit]
# Requires code to be properly formatted prior to pushing upstream
- id: cargo
name: Cargo fmt --check
args: ["+stable", "fmt", "--all", "--check"]
stages: [push, manual]
- id: cargo
name: Cargo check --all-targets
args: ["+stable", "check", "--all-targets"]
- id: cargo
name: Cargo check --all-targets --no-default-features
args: ["+stable", "check", "--all-targets", "--no-default-features"]
- id: cargo
name: Cargo check --all-targets --all-features
args: ["+stable", "check", "--all-targets", "--all-features"]
# Unlike fmt, clippy will not be automatically applied
- id: cargo
name: Cargo clippy
args: ["+nightly", "clippy", "--workspace", "--", "--deny", "clippy::all", "--deny", "warnings"]
33 changes: 33 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "miden-client"
version = "0.1.0"
authors = ["miden contributors"]
readme = "README.md"
license = "MIT"
repository = "https://github.com/0xPolygonMiden/miden-client"
keywords = ["miden", "client"]
edition = "2021"
rust-version = "1.67"

[features]
default = ["std"]
std = ["crypto/std", "objects/std"]
testing = ["objects/testing", "mock"]

[dependencies]
clap = { version = "4.3" , features = ["derive"] }
crypto = { package = "miden-crypto", git = "https://github.com/0xPolygonMiden/crypto", branch = "next", default-features = false }
lazy_static = "1.4.0"
objects = { package = "miden-objects", git = "https://github.com/0xPolygonMiden/miden-base", branch = "main", features = ["serde"] }
miden_lib = { package = "miden-lib", git = "https://github.com/0xPolygonMiden/miden-base", branch = "main", default-features = false }
mock = { package = "miden-mock", git = "https://github.com/0xPolygonMiden/miden-base", branch = "main", default-features = false, optional = true }
rusqlite = { version = "0.29.0", features = ["bundled"] }
rusqlite_migration = { version = "1.0" }
rand = { version="0.8.5" }
serde = {version="1.0", features = ["derive"]}
serde_json = { version = "1.0", features = ["raw_value"] }
comfy-table = "7.1.0"

[dev-dependencies]
uuid = { version = "1.6.1", features = ["serde", "v4"] }
mock = { package = "miden-mock", git = "https://github.com/0xPolygonMiden/miden-base", branch = "main", default-features = false }
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Polygon Miden

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# miden-client
183 changes: 183 additions & 0 deletions src/cli/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
use clap::Parser;
use comfy_table::{presets, Attribute, Cell, ContentArrangement, Table};
use crypto::{dsa::rpo_falcon512::KeyPair, Felt};
use miden_client::Client;
use miden_lib::{faucets, AuthScheme};
use objects::{accounts::AccountType, assets::TokenSymbol};
use rand::Rng;

// ACCOUNT COMMAND
// ================================================================================================

#[derive(Debug, Clone, Parser)]
#[clap(about = "View accounts and account details")]
pub enum AccountCmd {
/// List all accounts monitored by this client
#[clap(short_flag = 'l')]
List,

/// View details of the account for the specified ID
#[clap(short_flag = 'v')]
View {
#[clap()]
id: Option<String>,
},

/// Create new account and store it locally
#[clap(short_flag = 'n')]
New {
#[clap(subcommand)]
template: Option<AccountTemplate>,

/// Executes a transaction that records the account on-chain
#[clap(short, long, default_value_t = false)]
deploy: bool,
},
}

#[derive(Debug, Parser, Clone)]
#[clap()]
pub enum AccountTemplate {
/// Creates a basic account (Regular account with immutable code)
BasicImmutable,
/// Creates a basic account (Regular account with mutable code)
BasicMutable,
/// Creates a faucet for fungible tokens
FungibleFaucet {
#[clap(short, long)]
token_symbol: String,
#[clap(short, long)]
decimals: u8,
#[clap(short, long)]
max_supply: u64,
},
/// Creates a faucet for non-fungible tokens
NonFungibleFaucet,
}

impl AccountCmd {
pub fn execute(&self, client: Client) -> Result<(), String> {
match self {
AccountCmd::List => {
list_accounts(client)?;
}
AccountCmd::New { template, deploy } => {
new_account(client, template, *deploy)?;
}
AccountCmd::View { id: _ } => todo!(),
}
Ok(())
}
}

// LIST ACCOUNTS
// ================================================================================================

fn list_accounts(client: Client) -> Result<(), String> {
println!("{}", "-".repeat(240));
println!(
"{0: <18} | {1: <66} | {2: <66} | {3: <66} | {4: <15}",
"account id", "code root", "vault root", "storage root", "nonce",
);
println!("{}", "-".repeat(240));

let accounts = client.get_accounts().map_err(|err| err.to_string())?;

let mut table = Table::new();
table
.load_preset(presets::UTF8_FULL)
.set_content_arrangement(ContentArrangement::Dynamic)
.set_header(vec![
Cell::new("account id").add_attribute(Attribute::Bold),
Cell::new("code root").add_attribute(Attribute::Bold),
Cell::new("vault root").add_attribute(Attribute::Bold),
Cell::new("storage root").add_attribute(Attribute::Bold),
Cell::new("nonce").add_attribute(Attribute::Bold),
]);

accounts.iter().for_each(|acc| {
table.add_row(vec![
acc.id().to_string(),
acc.code_root().to_string(),
acc.vault_root().to_string(),
acc.storage_root().to_string(),
acc.nonce().to_string(),
]);
});

println!("{table}");
Ok(())
}

// ACCOUNT NEW
// ================================================================================================

fn new_account(
client: Client,
template: &Option<AccountTemplate>,
deploy: bool,
) -> Result<(), String> {
if deploy {
todo!("Recording the account on chain is not supported yet");
}

let key_pair: KeyPair =
KeyPair::new().map_err(|err| format!("Error generating KeyPair: {}", err))?;
let auth_scheme: AuthScheme = AuthScheme::RpoFalcon512 {
pub_key: key_pair.public_key(),
};

let mut rng = rand::thread_rng();
// we need to use an initial seed to create the wallet account
let init_seed: [u8; 32] = rng.gen();

// TODO: as the client takes form, make errors more structured
let (account, _) = match template {
None => todo!("Generic account creation is not supported yet"),
Some(AccountTemplate::BasicImmutable) => miden_lib::wallets::create_basic_wallet(
init_seed,
auth_scheme,
AccountType::RegularAccountImmutableCode,
),
Some(AccountTemplate::FungibleFaucet {
token_symbol,
decimals,
max_supply,
}) => {
let max_supply = max_supply.to_le_bytes();
faucets::create_basic_fungible_faucet(
init_seed,
TokenSymbol::new(token_symbol)
.expect("Hardcoded test token symbol creation should not panic"),
*decimals,
Felt::try_from(max_supply.as_slice())
.map_err(|_| "Maximum supply must fit into a field element")?,
auth_scheme,
)
}
Some(AccountTemplate::BasicMutable) => miden_lib::wallets::create_basic_wallet(
init_seed,
auth_scheme,
AccountType::RegularAccountUpdatableCode,
),
_ => todo!("Template not supported yet"),
}
.map_err(|err| err.to_string())?;

// TODO: Make these inserts atomic through a single transaction
client
.store()
.insert_account_code(account.code())
.and_then(|_| client.store().insert_account_storage(account.storage()))
.and_then(|_| client.store().insert_account_vault(account.vault()))
.and_then(|_| client.store().insert_account(&account))
.map(|_| {
println!(
"Succesfully created and stored Account ID: {}",
account.id()
)
})
.map_err(|x| x.to_string())?;

Ok(())
}
Loading

0 comments on commit 86b39cb

Please sign in to comment.