Skip to content

Commit 7e445e8

Browse files
committed
vanity move address
1 parent a537dc0 commit 7e445e8

9 files changed

Lines changed: 203 additions & 8 deletions

File tree

.cargo/config.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ rustflags = [
2929
rustflags = [
3030
"--cfg",
3131
"tokio_unstable",
32-
"-C",
33-
"link-arg=-fuse-ld=lld",
32+
# "-C",
33+
# "link-arg=-fuse-ld=lld",
3434
"-C",
3535
"force-frame-pointers=yes",
3636
"-C",
@@ -43,8 +43,8 @@ rustflags = [
4343
rustflags = [
4444
"--cfg",
4545
"tokio_unstable",
46-
"-C",
47-
"link-arg=-fuse-ld=lld",
46+
# "-C",
47+
# "link-arg=-fuse-ld=lld",
4848
"-C",
4949
"force-frame-pointers=yes",
5050
"-C",
@@ -70,8 +70,8 @@ rustflags = [
7070
rustflags = [
7171
"--cfg",
7272
"tokio_unstable",
73-
"-C",
74-
"link-arg=-fuse-ld=lld",
73+
# "-C",
74+
# "link-arg=-fuse-ld=lld",
7575
"-C",
7676
"force-frame-pointers=yes",
7777
"-C",
@@ -85,8 +85,8 @@ rustflags = [
8585
rustflags = [
8686
"--cfg",
8787
"tokio_unstable",
88-
"-C",
89-
"link-arg=-fuse-ld=lld",
88+
# "-C",
89+
# "link-arg=-fuse-ld=lld",
9090
"-C",
9191
"force-frame-pointers=yes",
9292
"-C",

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ members = [
3838
"util/signing/providers/aws-kms",
3939
"util/signing/providers/hashicorp-vault",
4040
"util/signing/testing",
41+
"util/vanity",
4142
"demo/hsm",
4243
"protocol-units/execution/maptos/framework/releases/*",
4344
"protocol-units/execution/maptos/framework/migrations/*",

util/vanity/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

util/vanity/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "vanity"
3+
version = "0.2.1"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aptos-sdk = { workspace = true }
8+
rand = { workspace = true }
9+
rayon = "1.7"
10+
hex = "0.4"
11+
clap = { version = "4.5", features = ["derive"] }
12+
thiserror = "1.0"
13+
num_cpus = "1.13"

util/vanity/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Vanity 🧂⛏️
2+
3+
Vanity is a CLI for mining vanity move addresses.
4+
5+
Vanity is heavely inspired by [Create2Crunch](https://github.com/0age/create2crunch).
6+
7+
## Installation
8+
9+
```bash
10+
git clone https://github.com/movementlabsxyz/movement.git
11+
cd movement
12+
# Run it directly
13+
cargo run -p vanity --release -- move --starts-pattern <STARTS_PATTERN> --ends-pattern <ENDS_PATTERN>
14+
15+
cd util/vanity
16+
# Add it to your path
17+
cargo install --path .
18+
```

util/vanity/src/cli.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::{ops::Deref, str::FromStr};
2+
3+
/// Pattern.
4+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
5+
pub(super) struct Pattern(Box<str>);
6+
7+
impl Deref for Pattern {
8+
type Target = str;
9+
10+
fn deref(&self) -> &Self::Target {
11+
&self.0
12+
}
13+
}
14+
15+
impl Pattern {
16+
pub(super) fn into_bytes(self) -> Result<Vec<u8>, hex::FromHexError> {
17+
let mut string = self.to_string();
18+
19+
if self.len() % 2 != 0 {
20+
string += "0"
21+
};
22+
23+
hex::decode(string)
24+
}
25+
}
26+
27+
/// Pattern errors.
28+
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
29+
pub(super) enum PatternError {
30+
#[error("the pattern's length exceeds 39 characters or the pattern is empty")]
31+
InvalidPatternLength,
32+
#[error("the pattern is not in hexadecimal format")]
33+
NonHexPattern,
34+
}
35+
36+
impl FromStr for Pattern {
37+
type Err = PatternError;
38+
39+
fn from_str(s: &str) -> Result<Self, Self::Err> {
40+
if s.len() >= 40 || s.is_empty() {
41+
return Err(PatternError::InvalidPatternLength);
42+
}
43+
44+
if s.chars().any(|c| !c.is_ascii_hexdigit()) {
45+
return Err(PatternError::NonHexPattern);
46+
}
47+
48+
Ok(Self(s.into()))
49+
}
50+
}
51+
52+
#[derive(Clone, Debug, clap::Parser)]
53+
#[command(name = "vanity", about = "Vanity is a fast vanity address miner.")]
54+
pub(super) enum Vanity {
55+
Move {
56+
#[clap(long)]
57+
starts_pattern: Option<String>,
58+
#[clap(long)]
59+
ends_pattern: Option<String>,
60+
},
61+
}

util/vanity/src/main.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
mod cli;
2+
mod miner;
3+
4+
use std::str::FromStr;
5+
use clap::Parser;
6+
use cli::{Pattern, Vanity};
7+
use miner::mine_move_address;
8+
use num_cpus;
9+
10+
fn main() -> Result<(), Box<dyn std::error::Error>> {
11+
match Vanity::parse() {
12+
Vanity::Move { starts_pattern, ends_pattern } => {
13+
let starts_pattern_bytes = match starts_pattern {
14+
Some(p) => Pattern::from_str(&p)?.into_bytes()?,
15+
None => vec![],
16+
};
17+
let ends_pattern_bytes = match ends_pattern {
18+
Some(p) => Pattern::from_str(&p)?.into_bytes()?,
19+
None => vec![],
20+
};
21+
22+
let account = mine_move_address(
23+
&starts_pattern_bytes,
24+
&ends_pattern_bytes,
25+
num_cpus::get(),
26+
);
27+
28+
println!("Found Move address: {}", account.address());
29+
println!("Private key (hex): {}", hex::encode(account.private_key().to_bytes()));
30+
return Ok(());
31+
}
32+
}
33+
}

util/vanity/src/miner.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use aptos_sdk::types::{account_address::AccountAddress, LocalAccount};
2+
use rand::thread_rng;
3+
use rayon::prelude::*;
4+
use rayon::ThreadPoolBuilder;
5+
use std::sync::{
6+
atomic::{AtomicBool, Ordering},
7+
Arc, Mutex,
8+
};
9+
use std::time::Instant;
10+
11+
fn matches_pattern(addr: &AccountAddress, start: &[u8], end: &[u8]) -> bool {
12+
let addr_bytes = addr.to_vec();
13+
(start.is_empty() || addr_bytes.starts_with(start)) &&
14+
(end.is_empty() || addr_bytes.ends_with(end))
15+
}
16+
17+
pub fn mine_move_address(
18+
starts_pattern: &[u8],
19+
ends_pattern: &[u8],
20+
threads: usize,
21+
) -> LocalAccount {
22+
let found = Arc::new(AtomicBool::new(false));
23+
let result = Arc::new(Mutex::new(None));
24+
let start_time = Instant::now();
25+
26+
let pool = ThreadPoolBuilder::new()
27+
.num_threads(threads)
28+
.build()
29+
.expect("Failed to build thread pool");
30+
31+
pool.install(|| {
32+
(0u64..=u64::MAX)
33+
.into_par_iter()
34+
.find_any(|_| {
35+
if found.load(Ordering::Relaxed) {
36+
return false;
37+
}
38+
let mut rng = thread_rng();
39+
let account = LocalAccount::generate(&mut rng);
40+
if matches_pattern(&account.address(), starts_pattern, ends_pattern) {
41+
let mut lock = result.lock().unwrap();
42+
*lock = Some(account);
43+
found.store(true, Ordering::Relaxed);
44+
true
45+
} else {
46+
false
47+
}
48+
});
49+
});
50+
51+
println!("✅ Mining completed in {:?}", start_time.elapsed());
52+
53+
let final_result = std::mem::take(&mut *result.lock().unwrap());
54+
final_result.expect("No matching account found")
55+
}

0 commit comments

Comments
 (0)