Initial commit

This commit is contained in:
Ryan Heywood 2024-11-20 13:16:19 -05:00
commit dc91b0bee8
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
7 changed files with 474 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

237
Cargo.lock generated Normal file
View File

@ -0,0 +1,237 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "icepick"
version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "proc-macro2"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[workspace]
resolver = "2"
members = [
"crates/icepick",
]
[workspace.dependencies]

74
README.md Normal file
View File

@ -0,0 +1,74 @@
## Bitcoin
Bitcoin is a native coin, and does not require any kind of custom token support
atop an existing blockchain.
Possible routes to enable BTC transfer:
* `bitcoin` Rust module should support creating and signing transactions, as
well as communicating with a Bitcoin node
## Ethereum
Ethereum is the native currency of the Ethereum blockchain. Ethereum supports
proof-of-stake, so staking needs to be enabled as well. The Ethereum blockchain
is also the host of many tokens, meaning Ethereum token transactions should
also be supported.
Possible routes to enable ETH and Ethereum Token transfer:
* Alloy, the Rust Ethereum project, should enable the necessary functionality
## Solana
Solana is a Rust-native coin and can be used to host tokens. Solana
incorporates proof-of-stake, so staking functionality is also required.
Possible routes to enable SOL and Solana Token transfer:
* Load Keyfork-derived key onto Ledger device
* Perform transaction using Solana SPL CLI to transfer tokens
* `spl-token transfer --sign-only`
* `solana-client` Rust crate should have necessary functionality
## Pyth
PYTH is a token that can be traded on the Solana network. The token is like an
NFT that can have multiple amounts, so to transfer PYTH, you're basically just
transferring that amount of an NFT.
Possible routes to enable PYTH transfer:
* Load Keyfork-derived key onto Ledger device
* Perform transaction using Solana SPL CLI to transfer tokens
* `spl-token transfer --sign-only`
## Stride (Token)
STRD is a coin using Inter-Blockchain Communication to interact with other
coins in the Cosmos ecosystem.
Possible routes to enable STRD transfer:
* Use `stride` to communicate with Stride
* Build CLI with `cosmrs` to communicate with Osmosis or Stride
## Ronin
Ronin uses the EVM on its own blockchain, meaning we can use the above
guidelines for Ethereum to connect.
Possible routes to enable Ronin transfer:
* `alloy`, in a similar manner to ETH
## Spacemesh
Spacemesh is a unique blockchain written in Go, but providing a Rust SDK. Proof
of stake doesn't seem to be supported, so staking would not be an option for
this blockchain.
Possible routes to enable Spacemesh transfer:
* Spacemesh Rust SDK crate
* Spacemesh Go SDK, ported to Rust

View File

@ -0,0 +1,7 @@
[package]
name = "icepick"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.20", features = ["cargo", "derive"] }

View File

@ -0,0 +1,139 @@
#![allow(clippy::upper_case_acronyms)]
use clap::{Arg, Command};
// TODO: extract as icepick_coin
mod icepick_coin {
use clap::Command;
pub trait Coin {
/// Return the name for the coin, in lowercase.
fn coin_name(&self) -> &'static str;
/// Return a description of the coin.
fn coin_description(&self) -> &'static str;
/// Given a Command, add any arguments relevant to the Transfer operation.
///
/// All commands by default have the following values:
/// * `amount`: The amount of the currency to transfer.
/// * `to`: The account to transfer the currency to.
/// * `from_account`: The non-default derivation account to send currency from.
fn build_transfer_command(&self, _command: Command) -> Result<Command, ()> {
Err(())
}
/// Given a Command, add any arguments relevant to the Stake operation.
fn build_stake_command(&self, _command: Command) -> Result<Command, ()> {
Err(())
}
}
}
// TODO: extract as icepick_eth
mod eth {
use super::icepick_coin::Coin;
use clap::arg;
pub struct ETH;
impl Coin for ETH {
fn coin_name(&self) -> &'static str {
"eth"
}
fn coin_description(&self) -> &'static str {
"The leading platform for innovative apps and blockchain networks."
}
fn build_transfer_command(&self, command: clap::Command) -> Result<clap::Command, ()> {
Ok(command
.arg(arg!(--gas <GAS> "Specify custom gas for the transaction."))
.arg(arg!(--"gas-payer" <ACCOUNT> "Use an alternative derivation account for paying gas.")))
}
fn build_stake_command(&self, _command: clap::Command) -> Result<clap::Command, ()> {
Err(())
}
}
}
use icepick_coin::Coin;
fn build_transfer_command() -> Command {
Command::new("transfer")
.about("Transfer coins from one wallet to another.")
}
fn build_stake_command() -> Command {
Command::new("stake")
.about("Stake coins.")
}
fn build_transfer_subcommand(coin: &dyn Coin) -> Command {
let name = coin.coin_name();
let description = coin.coin_description();
let uppercase_name = name.to_uppercase();
Command::new(name)
.about(description)
.arg(Arg::new("amount").help(format!("Amount of {uppercase_name} to transfer")))
.arg(Arg::new("to_address").help(format!("Account to send {uppercase_name} to")))
.arg(
Arg::new("from_account")
.help(format!(
"Specify a non-default derivation account to send {uppercase_name} from"
))
.required(false),
)
}
fn build_stake_subcommand(coin: &dyn Coin) -> Command {
let name = coin.coin_name();
let description = coin.coin_description();
let uppercase_name = name.to_uppercase();
Command::new(name)
.about(description)
.arg(Arg::new("amount").help(format!("Amount of {uppercase_name} to stake")))
.arg(
Arg::new("from_account")
.help(format!(
"Specify a non-default derivation account to send {uppercase_name} from"
))
.required(false),
)
}
pub fn build_command() -> Command {
let command = clap::command!();
let mut transfer_subcommand = build_transfer_command();
let mut stake_subcommand = build_stake_command();
// TODO: this will break. how do i support multiple types here?
#[allow(clippy::single_element_loop)]
for value in &[eth::ETH] {
let res = value.build_transfer_command(build_transfer_subcommand(value));
match res {
Ok(subcommand) => {
transfer_subcommand = transfer_subcommand.subcommand(subcommand);
}
Err(_) => {
// This coin does not support the given operation.
}
}
let res = value.build_stake_command(build_stake_subcommand(value));
match res {
Ok(subcommand) => {
stake_subcommand = stake_subcommand.subcommand(subcommand);
}
Err(_) => {
// This coin does not support the given operation.
}
}
}
command
.subcommand(transfer_subcommand)
.subcommand(stake_subcommand)
}
pub fn handle_matches(_matches: clap::ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

View File

@ -0,0 +1,8 @@
mod cli;
fn main() {
let command = cli::build_command();
let matches = command.get_matches();
cli::handle_matches(matches).unwrap();
println!("Hello, world!");
}