-module(gleeth@crypto@wallet). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/crypto/wallet.gleam"). -export([from_private_key_hex/1, from_private_key_bytes/1, generate/0, get_address/1, get_private_key_hex/1, get_public_key_hex/1, get_private_key_bytes/1, get_public_key_bytes/1, is_valid/1, sign_hash/2, sign_message/2, sign_personal_message/2, to_string/1, to_summary/1, equals/2, error_to_string/1, is_recoverable_error/1]). -export_type([wallet/0, wallet_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type wallet() :: {wallet, gleeth@crypto@secp256k1:private_key(), gleeth@crypto@secp256k1:public_key(), gleeth@crypto@secp256k1:ethereum_address()}. -type wallet_error() :: {invalid_private_key, binary()} | {invalid_hex, binary()} | {key_generation_failed, binary()} | {signing_failed, binary()}. -file("src/gleeth/crypto/wallet.gleam", 28). ?DOC( " Create a wallet from a private key hex string\n" " Supports both with and without 0x prefix\n" ). -spec from_private_key_hex(binary()) -> {ok, wallet()} | {error, wallet_error()}. from_private_key_hex(Hex_string) -> gleam@result:'try'( begin _pipe = gleeth@crypto@secp256k1:private_key_from_hex(Hex_string), gleam@result:map_error( _pipe, fun(Field@0) -> {invalid_private_key, Field@0} end ) end, fun(Private_key) -> gleam@result:'try'( begin _pipe@1 = gleeth@crypto@secp256k1:create_public_key( Private_key ), gleam@result:map_error( _pipe@1, fun(Field@0) -> {key_generation_failed, Field@0} end ) end, fun(Public_key) -> gleam@result:'try'( begin _pipe@2 = gleeth@crypto@secp256k1:public_key_to_address( Public_key ), gleam@result:map_error( _pipe@2, fun(Field@0) -> {key_generation_failed, Field@0} end ) end, fun(Address) -> {ok, {wallet, Private_key, Public_key, Address}} end ) end ) end ). -file("src/gleeth/crypto/wallet.gleam", 48). ?DOC(" Create a wallet from raw private key bytes\n"). -spec from_private_key_bytes(bitstring()) -> {ok, wallet()} | {error, wallet_error()}. from_private_key_bytes(Bytes) -> gleam@result:'try'( begin _pipe = gleeth@crypto@secp256k1:private_key_from_bytes(Bytes), gleam@result:map_error( _pipe, fun(Field@0) -> {invalid_private_key, Field@0} end ) end, fun(Private_key) -> gleam@result:'try'( begin _pipe@1 = gleeth@crypto@secp256k1:create_public_key( Private_key ), gleam@result:map_error( _pipe@1, fun(Field@0) -> {key_generation_failed, Field@0} end ) end, fun(Public_key) -> gleam@result:'try'( begin _pipe@2 = gleeth@crypto@secp256k1:public_key_to_address( Public_key ), gleam@result:map_error( _pipe@2, fun(Field@0) -> {key_generation_failed, Field@0} end ) end, fun(Address) -> {ok, {wallet, Private_key, Public_key, Address}} end ) end ) end ). -file("src/gleeth/crypto/wallet.gleam", 68). ?DOC(" Generate a new random wallet using cryptographically secure randomness\n"). -spec generate() -> {ok, wallet()} | {error, wallet_error()}. generate() -> gleam@result:'try'( begin _pipe = gleeth@crypto@random:generate_private_key(), gleam@result:map_error( _pipe, fun(Err) -> {key_generation_failed, <<"Failed to generate secure private key: "/utf8, (gleeth@crypto@random:error_to_string(Err))/binary>>} end ) end, fun(Private_key) -> gleam@result:'try'( begin _pipe@1 = gleeth@crypto@secp256k1:create_public_key( Private_key ), gleam@result:map_error( _pipe@1, fun(Field@0) -> {key_generation_failed, Field@0} end ) end, fun(Public_key) -> gleam@result:'try'( begin _pipe@2 = gleeth@crypto@secp256k1:public_key_to_address( Public_key ), gleam@result:map_error( _pipe@2, fun(Field@0) -> {key_generation_failed, Field@0} end ) end, fun(Address) -> {ok, {wallet, Private_key, Public_key, Address}} end ) end ) end ). -file("src/gleeth/crypto/wallet.gleam", 96). ?DOC(" Get the wallet's Ethereum address as a string\n"). -spec get_address(wallet()) -> binary(). get_address(Wallet) -> gleeth@crypto@secp256k1:address_to_string(erlang:element(4, Wallet)). -file("src/gleeth/crypto/wallet.gleam", 101). ?DOC(" Get the wallet's private key as a hex string\n"). -spec get_private_key_hex(wallet()) -> binary(). get_private_key_hex(Wallet) -> gleeth@crypto@secp256k1:private_key_to_hex(erlang:element(2, Wallet)). -file("src/gleeth/crypto/wallet.gleam", 106). ?DOC(" Get the wallet's public key as a hex string\n"). -spec get_public_key_hex(wallet()) -> binary(). get_public_key_hex(Wallet) -> gleeth@crypto@secp256k1:public_key_to_hex(erlang:element(3, Wallet)). -file("src/gleeth/crypto/wallet.gleam", 111). ?DOC(" Get the wallet's private key as raw bytes\n"). -spec get_private_key_bytes(wallet()) -> bitstring(). get_private_key_bytes(Wallet) -> gleeth@crypto@secp256k1:private_key_to_bytes(erlang:element(2, Wallet)). -file("src/gleeth/crypto/wallet.gleam", 116). ?DOC(" Get the wallet's public key as raw bytes\n"). -spec get_public_key_bytes(wallet()) -> bitstring(). get_public_key_bytes(Wallet) -> gleeth@crypto@secp256k1:public_key_to_bytes(erlang:element(3, Wallet)). -file("src/gleeth/crypto/wallet.gleam", 121). ?DOC(" Check if the wallet has a valid private key\n"). -spec is_valid(wallet()) -> boolean(). is_valid(Wallet) -> gleeth@crypto@secp256k1:is_valid_private_key(erlang:element(2, Wallet)). -file("src/gleeth/crypto/wallet.gleam", 130). ?DOC(" Sign a message hash with the wallet's private key\n"). -spec sign_hash(wallet(), bitstring()) -> {ok, gleeth@crypto@secp256k1:signature()} | {error, wallet_error()}. sign_hash(Wallet, Message_hash) -> _pipe = gleeth@crypto@secp256k1:sign_message_hash( Message_hash, erlang:element(2, Wallet) ), gleam@result:map_error(_pipe, fun(Field@0) -> {signing_failed, Field@0} end). -file("src/gleeth/crypto/wallet.gleam", 139). ?DOC(" Sign raw message bytes (will be hashed with keccak256)\n"). -spec sign_message(wallet(), bitstring()) -> {ok, gleeth@crypto@secp256k1:signature()} | {error, wallet_error()}. sign_message(Wallet, Message) -> _pipe = gleeth@crypto@secp256k1:sign_message( Message, erlang:element(2, Wallet) ), gleam@result:map_error(_pipe, fun(Field@0) -> {signing_failed, Field@0} end). -file("src/gleeth/crypto/wallet.gleam", 148). ?DOC(" Sign an Ethereum personal message\n"). -spec sign_personal_message(wallet(), binary()) -> {ok, gleeth@crypto@secp256k1:signature()} | {error, wallet_error()}. sign_personal_message(Wallet, Message) -> _pipe = gleeth@crypto@secp256k1:sign_personal_message( Message, erlang:element(2, Wallet) ), gleam@result:map_error(_pipe, fun(Field@0) -> {signing_failed, Field@0} end). -file("src/gleeth/crypto/wallet.gleam", 161). ?DOC(" Convert a wallet to a summary string for display\n"). -spec to_string(wallet()) -> binary(). to_string(Wallet) -> Address = get_address(Wallet), Private_key = get_private_key_hex(Wallet), <<<<<<<<<<<<<<"Wallet {\n"/utf8, " address: "/utf8>>/binary, Address/binary>>/binary, "\n"/utf8>>/binary, " private_key: "/utf8>>/binary, Private_key/binary>>/binary, "\n"/utf8>>/binary, "}"/utf8>>. -file("src/gleeth/crypto/wallet.gleam", 176). ?DOC(" Convert a wallet to a compact summary for logging\n"). -spec to_summary(wallet()) -> binary(). to_summary(Wallet) -> Address = get_address(Wallet), <<<<"Wallet("/utf8, Address/binary>>/binary, ")"/utf8>>. -file("src/gleeth/crypto/wallet.gleam", 182). ?DOC(" Check if two wallets are the same (have same private key)\n"). -spec equals(wallet(), wallet()) -> boolean(). equals(Wallet1, Wallet2) -> get_private_key_hex(Wallet1) =:= get_private_key_hex(Wallet2). -file("src/gleeth/crypto/wallet.gleam", 191). ?DOC(" Convert WalletError to string for display\n"). -spec error_to_string(wallet_error()) -> binary(). error_to_string(Error) -> case Error of {invalid_private_key, Msg} -> <<"Invalid private key: "/utf8, Msg/binary>>; {invalid_hex, Msg@1} -> <<"Invalid hex format: "/utf8, Msg@1/binary>>; {key_generation_failed, Msg@2} -> <<"Key generation failed: "/utf8, Msg@2/binary>>; {signing_failed, Msg@3} -> <<"Signing failed: "/utf8, Msg@3/binary>> end. -file("src/gleeth/crypto/wallet.gleam", 201). ?DOC(" Check if an error is recoverable\n"). -spec is_recoverable_error(wallet_error()) -> boolean(). is_recoverable_error(Error) -> case Error of {invalid_private_key, _} -> false; {invalid_hex, _} -> false; {key_generation_failed, _} -> true; {signing_failed, _} -> true end.