view release on metacpan or search on metacpan
examples/address_creation.pl view on Meta::CPAN
use Blockchain::Ethereum::Key;
use Blockchain::Ethereum::Seed;
# generating a new address
my $key = Blockchain::Ethereum::Key->new();
printf "%s\n", $key->address;
# importing private key
$key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
printf "%s\n", $key->address;
# hdwallet
my $wallet = Blockchain::Ethereum::Seed->new();
$key = $wallet->derive_key(0);
printf "%s\n", $key->address;
$key = $wallet->derive_key(1);
printf "%s\n", $key->address;
examples/eip1559_tx_signing.pl view on Meta::CPAN
nonce => '0x0',
max_fee_per_gas => '0x1127A5278',
max_priority_fee_per_gas => '0x79000000',
gas_limit => '0x1DE2B9',
value => '0x0',
data => $encoded,
chain_id => '0x1'
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
printf("0x%s", unpack "H*", $raw_transaction);
lib/Blockchain/Ethereum/Key.pm view on Meta::CPAN
use Crypt::PRNG qw(random_bytes);
use Scalar::Util qw(blessed);
use Bitcoin::Secp256k1;
use Blockchain::Ethereum::Address;
sub new {
my ($class, %params) = @_;
my $self = bless {}, $class;
if (exists $params{private_key}) {
$self->{private_key} = $params{private_key};
} else {
$self->{private_key} = random_bytes(32);
}
return $self;
}
sub private_key {
return shift->{private_key};
}
sub _ecc_handler {
return shift->{ecc_handler} //= Bitcoin::Secp256k1->new;
}
sub sign_transaction {
my ($self, $transaction) = @_;
croak "transaction must be a reference of Blockchain::Ethereum::Transaction"
unless blessed $transaction && $transaction->isa('Blockchain::Ethereum::Transaction');
my $result = $self->_ecc_handler->sign_digest_recoverable($self->private_key, $transaction->hash);
my $r = substr($result->{signature}, 0, 32);
my $s = substr($result->{signature}, 32, 32);
my $recovery_id = $result->{recovery_id};
$transaction->set_r(unpack "H*", $r);
$transaction->set_s(unpack "H*", $s);
$transaction->generate_v($recovery_id);
return $transaction;
}
sub address {
my $self = shift;
my $pubkey = $self->_ecc_handler->create_public_key($self->private_key);
my $compressed_pubkey = $self->_ecc_handler->compress_public_key($pubkey, 0);
my $pubkey_64 = substr($compressed_pubkey, 1); # remove 0x04 prefix
my $address = substr(keccak256($pubkey_64), -20);
my $hex_address = unpack("H*", $address);
return Blockchain::Ethereum::Address->new(address => "0x$hex_address");
}
sub export {
return shift->private_key;
}
1;
__END__
=pod
=encoding UTF-8
lib/Blockchain/Ethereum/Key.pm view on Meta::CPAN
=head1 SYNOPSIS
Generate a new key:
my $key = Blockchain::Ethereum::Key->new;
my $address = $key->address; # Blockchain::Ethereum::Address
$key->sign_transaction($transaction); # Blockchain::Ethereum::Transaction
Import existent key:
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key); # private key bytes
$key->sign_transaction($transaction); # Blockchain::Ethereum::Transaction
=head1 OVERVIEW
This is a private key abstraction
If instantiated without a private key, this module uses L<Crypt::PRNG> for the random key generation
=head1 METHODS
lib/Blockchain/Ethereum/Key.pm view on Meta::CPAN
Export the L<Blockchain::Ethereum::Address> from the imported/generated private key
=over 4
=back
L<Blockchain::Ethereum::Address>
=head2 export
Use `private_key` instead this method is deprecated and will be removed.
=over 4
=back
Private key bytes
=head1 AUTHOR
REFECO <refeco@cpan.org>
lib/Blockchain/Ethereum/Keystore.pm view on Meta::CPAN
$keyfile->write_to_file("...");
Signing a transaction:
my $transaction = Blockchain::Ethereum::Transaction::EIP1559->new(
...
);
my $keyfile = Blockchain::Ethereum::Keyfile->new;
$keyfile->import_file("...");
$keyfile->private_key->sign_transaction($transaction);
Export private key:
my $keyfile = Blockchain::Ethereum::Keyfile->new;
$keyfile->import_file("...");
# private key bytes
print $keyfile->private_key->export;
=head1 OVERVIEW
This module provides a collection of Ethereum wallet management utilities.
Core functionalities:
=over 4
=item * Manage Ethereum keyfiles, facilitating import, export, and password change.
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
pretty => 1,
canonical => 1
);
sub from_key {
my ($class, $key) = @_;
croak 'key must be a Blockchain::Ethereum::Key instance'
unless blessed $key && $key->isa('Blockchain::Ethereum::Key');
my $self = bless {private_key => $key}, $class;
return $self;
}
sub from_file {
my ($class, $file_path, $password) = @_;
my $self = bless {}, $class;
my $content;
{
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
sub kdf {
my $self = shift;
$self->{kdf} //= $self->_generate_kdf;
}
sub id {
my $self = shift;
$self->{id} //= $self->_generate_id;
}
sub private_key {
shift->{private_key};
}
sub password {
shift->{password};
}
sub _from_v3 {
my ($self, $object) = @_;
my $crypto = $object->{crypto};
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
$self->{kdf} = Blockchain::Ethereum::Keystore::KDF->new(
algorithm => $crypto->{kdf}, #
dklen => $header->{dklen},
n => $header->{n},
p => $header->{p},
r => $header->{r},
c => $header->{c},
prf => $header->{prf},
salt => $header->{salt});
$self->{private_key} = $self->_generate_private_key unless $self->private_key;
$self->_verify_mac;
return $self;
}
sub _verify_mac {
my ($self) = @_;
my $computed_mac = $self->_generate_mac;
my $expected_mac = $self->mac;
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
sub _generate_mac {
my ($self) = @_;
my $derived_key = $self->kdf->decode($self->password);
my $mac_key = substr($derived_key, 16, 16);
return unpack "H*", keccak256($mac_key . pack("H*", $self->ciphertext));
}
sub _generate_private_key {
my ($self) = @_;
my $derived_key = $self->kdf->decode($self->password);
my $cipher_key = substr($derived_key, 0, 16);
my $key = $self->cipher->decrypt(pack("H*", $self->ciphertext), $cipher_key, pack("H*", $self->iv));
return Blockchain::Ethereum::Key->new(private_key => $key);
}
sub _generate_random_iv {
my $iv = Crypt::PRNG::random_bytes(16);
return unpack "H*", $iv;
}
sub _generate_kdf {
my ($self) = @_;
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
$salt
);
}
sub _generate_ciphertext {
my ($self) = @_;
my $derived_key = $self->kdf->decode($self->password);
my $cipher_key = substr($derived_key, 0, 16);
my $encrypted = $self->cipher->encrypt($self->private_key->export, $cipher_key, pack("H*", $self->iv));
return unpack "H*", $encrypted;
}
sub _generate_id {
my $uuid = Data::UUID->new->create_str();
$uuid =~ s/-//g; # Remove hyphens for Ethereum format
return lc($uuid);
}
sub write_to_file {
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
=head1 VERSION
version 0.021
=head1 SYNOPSIS
use Blockchain::Ethereum::Keystore::File;
use Blockchain::Ethereum::Key;
# Create a new keystore from a private key
my $private_key = Blockchain::Ethereum::Key->new(
private_key => $key_bytes
);
my $keystore = Blockchain::Ethereum::Keystore::File->new(
private_key => $private_key,
password => 'my_secure_password'
);
# Save to file
$keystore->write_to_file('/path/to/keystore.json');
# Load from existing keystore file
my $loaded = Blockchain::Ethereum::Keystore::File->from_file(
'/path/to/keystore.json',
'my_secure_password'
);
# Change password and save
$loaded->write_to_file('/path/to/new_keystore.json', 'new_password');
# Access keystore properties
my $private_key = $loaded->private_key;
my $address = $private_key->address;
=head1 OVERVIEW
This module provides a way to create, read, and write Ethereum keystore files (version 3).
Ethereum keystores are encrypted JSON files that securely store private keys using
password-based encryption with scrypt key derivation and AES-128-CTR cipher.
The module supports:
=over 4
lib/Blockchain/Ethereum/Keystore/File.pm view on Meta::CPAN
=back
=head1 METHODS
=head2 from_key
Load a keystore from an existing private key.
my $key = Blockchain::Ethereum::Key->new(
private_key => $key_bytes
);
my $keystore = Blockchain::Ethereum::Keystore::File->from_key($key);
=over 4
=item * C<key> - A Blockchain::Ethereum::Key instance (required)
=back
Returns a keystore object with the loaded private key and parameters.
lib/Blockchain/Ethereum/Seed.pm view on Meta::CPAN
$change = 0 unless $change;
my $path = Bitcoin::Crypto::BIP44->new(
index => $index,
purpose => $purpose,
coin_type => $coin_type,
account => $account,
change => $change,
);
return Blockchain::Ethereum::Key->new(private_key => $self->_hdw_handler->derive_key($path)->get_basic_key->to_serialized);
}
1;
__END__
=pod
=encoding UTF-8
lib/Blockchain/Ethereum/Transaction/EIP1559.pm view on Meta::CPAN
address => '0x1234567890123456789012345678901234567890',
storage_keys => [
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000000000000000000000000000002'
]
}
]
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
=head1 METHODS
=head2 serialize
lib/Blockchain/Ethereum/Transaction/EIP2930.pm view on Meta::CPAN
address => '0x1234567890123456789012345678901234567890',
storage_keys => [
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000000000000000000000000000002'
]
}
]
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
=head1 METHODS
=head2 serialize
lib/Blockchain/Ethereum/Transaction/EIP4844.pm view on Meta::CPAN
]
}
],
blob_versioned_hashes => [
'0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014',
'0x01ac9710ba11d0d3cbea6d499ddc888c02f3374c2336331f3e11b33260054aeb'
]
);
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
=head1 AUTHOR
REFECO <refeco@cpan.org>
lib/Blockchain/Ethereum/Transaction/Legacy.pm view on Meta::CPAN
my $transaction = Blockchain::Ethereum::Transaction::Legacy->new(
nonce => '0x9',
gas_price => '0x4A817C800',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => '0xDE0B6B3A7640000',
chain_id => '0x1'
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
=head1 METHODS
=head2 serialize
t/Keystore/file.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use File::Temp qw(tempfile);
use JSON::MaybeXS qw(decode_json);
use Blockchain::Ethereum::Keystore::File;
use Blockchain::Ethereum::Key;
# Test data
my $private_key_hex = "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d";
my $private_key_bytes = pack "H*", $private_key_hex;
my $password = "testpassword";
subtest "from_file - v3 pbkdf2" => sub {
my $keyfile = Blockchain::Ethereum::Keystore::File->from_file("./t/Keystore/resources/pbkdf2_v3.json", $password);
isa_ok $keyfile, 'Blockchain::Ethereum::Keystore::File';
isa_ok $keyfile->private_key, 'Blockchain::Ethereum::Key';
is $keyfile->private_key->export, $private_key_bytes, 'private key matches';
is $keyfile->password, $password, 'password stored correctly';
# Test against actual file data
is $keyfile->version, 3, 'version is 3';
is $keyfile->id, '3198bc9c-6672-5ab3-d995-4942343ae5b6', 'ID matches file data';
is $keyfile->iv, '6087dab2f9fdbbfaddc31a909735c1e6', 'IV matches file data';
is $keyfile->ciphertext, '5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46', 'ciphertext matches file data';
is $keyfile->mac, '517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2', 'MAC matches file data';
# Test KDF parameters
t/Keystore/file.t view on Meta::CPAN
is $keyfile->kdf->dklen, 32, 'KDF dklen is correct';
is $keyfile->kdf->c, 262144, 'KDF iteration count is correct';
is $keyfile->kdf->prf, 'hmac-sha256', 'KDF PRF is correct';
is $keyfile->kdf->salt, 'ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd', 'KDF salt matches file data';
};
subtest "from_file - v3 scrypt" => sub {
my $keyfile = Blockchain::Ethereum::Keystore::File->from_file("./t/Keystore/resources/scrypt_v3.json", $password);
isa_ok $keyfile, 'Blockchain::Ethereum::Keystore::File';
isa_ok $keyfile->private_key, 'Blockchain::Ethereum::Key';
is $keyfile->private_key->export, $private_key_bytes, 'private key matches';
is $keyfile->password, $password, 'password stored correctly';
# Test against actual file data
is $keyfile->version, 3, 'version is 3';
is $keyfile->id, '3198bc9c-6672-5ab3-d995-4942343ae5b6', 'ID matches file data';
is $keyfile->iv, '83dbcc02d8ccb40e466191a123791e0e', 'IV matches file data';
is $keyfile->ciphertext, 'd172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c', 'ciphertext matches file data';
is $keyfile->mac, '2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097', 'MAC matches file data';
# Test KDF parameters
isa_ok $keyfile->kdf, 'Blockchain::Ethereum::Keystore::KDF';
is $keyfile->kdf->algorithm, 'scrypt', 'KDF algorithm is scrypt';
is $keyfile->kdf->dklen, 32, 'KDF dklen is correct';
is $keyfile->kdf->n, 262144, 'KDF n parameter is correct';
is $keyfile->kdf->p, 8, 'KDF p parameter is correct';
is $keyfile->kdf->r, 1, 'KDF r parameter is correct';
is $keyfile->kdf->salt, 'ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19', 'KDF salt matches file data';
};
subtest "write_to_file - basic" => sub {
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key_bytes);
my $keyfile = Blockchain::Ethereum::Keystore::File->from_key($key);
my ($fh, $filename) = tempfile();
close $fh;
eval { $keyfile->write_to_file($filename, $password) };
ok !$@, 'write_to_file succeeds';
ok -f $filename, 'file was created';
# Verify we can read it back
my $loaded = Blockchain::Ethereum::Keystore::File->from_file($filename, $password);
is $loaded->private_key->export, $private_key_bytes, 'round-trip preserves key';
unlink $filename;
};
subtest "error conditions - from_file" => sub {
eval { Blockchain::Ethereum::Keystore::File->from_file("nonexistent.json", $password) };
like $@, qr/No such file or directory/, 'from_file handles missing file';
eval { Blockchain::Ethereum::Keystore::File->from_file("./t/Keystore/resources/scrypt_v3.json", "wrongpassword") };
like $@, qr/Invalid password or corrupted keystore/, 'from_file validates password';
t/Keystore/file.t view on Meta::CPAN
# Load a valid keystore
my $keyfile = Blockchain::Ethereum::Keystore::File->from_file("./t/Keystore/resources/scrypt_v3.json", $password);
my $mac_original = $keyfile->mac;
my $mac_new = $keyfile->_generate_mac;
like $mac_original, qr/^[0-9a-f]+$/i, 'original MAC has hex format';
like $mac_new, qr/^[0-9a-f]+$/i, 'new MAC has hex format';
is $mac_new, $mac_original, 'MAC matches for valid keystore';
};
subtest "keystore format compliance" => sub {
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key_bytes);
my $keyfile = Blockchain::Ethereum::Keystore::File->from_key($key);
my ($fh, $filename) = tempfile;
close $fh;
$keyfile->write_to_file($filename, $password);
# Read the JSON directly to verify format
my $json_content = do {
open my $fh, '<', $filename or die $!;
t/Transaction/eip1559.t view on Meta::CPAN
nonce => '0x0',
max_fee_per_gas => '0x9',
max_priority_fee_per_gas => '0x0',
gas_limit => '0x1DE2B9',
value => '0x0',
data => $compiled_contract,
chain_id => '0x539'
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is(unpack("H*", $raw_transaction),
'02f901c3820539808009831de2b98080b90170608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b604...
);
t/Transaction/eip1559.t view on Meta::CPAN
nonce => '0x1',
max_fee_per_gas => '0x9',
max_priority_fee_per_gas => '0x0',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => parse_units('1', ETH),
chain_id => '0x539'
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is(unpack("H*", $raw_transaction),
'02f86c820539018009825208943535353535353535353535353535353535353535880de0b6b3a764000080c080a070816c3d026c13a53e98e5dc414398e9dcdf23e440e777114a3e04810e0dfb5da07d732e6b7f847b06d2baed033772d78407da8f4010fa9300df79f2209ba4c7a0'
);
t/Transaction/eip1559.t view on Meta::CPAN
'0x0000000000000000000000000000000000000000000000000000000000000002'
]
},
{
address => '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
storage_keys => ['0x0000000000000000000000000000000000000000000000000000000000000003']}
],
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is unpack("H*", $raw_transaction),
'02f9010d8205398084773594008504a817c80082c3509412345678901234567890123456789012345678908806f05b59d3b2000084deadbeeff893f859941234567890123456789012345678901234567890f842a00000000000000000000000000000000000000000000000000000000000000001a000000...
};
t/Transaction/eip2930.t view on Meta::CPAN
chain_id => '0x1',
nonce => '0x0',
gas_price => '0x4A817C800',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => parse_units('1', ETH),
data => '0x',
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is unpack("H*", $raw_transaction),
'01f86e01808504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080c001a00cbb47e86ca4f83d9675eccb8ea3c7f1f4718ab998baa4083c3627353c293103a064eba85277a343804e99ee028783fe90d05b3994202a0b77c8b04fb089fbc07a';
};
t/Transaction/eip2930.t view on Meta::CPAN
'0x0000000000000000000000000000000000000000000000000000000000000002'
]
},
{
address => '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
storage_keys => ['0x0000000000000000000000000000000000000000000000000000000000000003']}
],
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is unpack("H*", $raw_transaction),
'01f8fa01018504a817c80082c3509412345678901234567890123456789012345678908080f893f859941234567890123456789012345678901234567890f842a00000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000...
};
t/Transaction/eip4844.t view on Meta::CPAN
max_fee_per_gas => '0x4a817c800', # 20 gwei
max_fee_per_blob_gas => '0x3b9aca00', # 1 gwei
gas_limit => '0x186a0', # 100000
to => '0x1234567890123456789012345678901234567890',
value => '0x16345785d8a0000', # 0.1 ETH
data => '0xdeadbeef',
blob_versioned_hashes => ['0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014'],
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($tx);
my $raw_transaction = $tx->serialize;
is unpack("H*", $raw_transaction),
'03f89f018084773594008504a817c800830186a094123456789012345678901234567890123456789088016345785d8a000084deadbeefc0843b9aca00e1a0010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401401a0766af62f60f5aab78cf270654e9bd5c0cc323ddf06b9cd5...
'single blob transaction serialization matches';
t/Transaction/eip4844.t view on Meta::CPAN
storage_keys => ['0x0000000000000000000000000000000000000000000000000000000000000001']}
],
blob_versioned_hashes => [
'0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014',
'0x01ac9710ba11d0d3cbea6d499ddc888c02f3374c2336331f3e11b33260054aeb',
'0x0157374c17c7f992ec8fbcaaa1deffdb77914dad0bf6b9d7015dd7b86ccbd253'
],
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($tx);
my $raw_transaction = $tx->serialize;
is unpack("H*", $raw_transaction),
'03f901118205390184b2d05e008505d21dba00830249f094abcdefabcdefabcdefabcdefabcdefabcdefabcd8080f838f7941234567890123456789012345678901234567890e1a000000000000000000000000000000000000000000000000000000000000000018477359400f863a0010657f37554c7814...
'multiple blobs with access list transaction serialization matches';
t/Transaction/legacy.t view on Meta::CPAN
my $transaction = Blockchain::Ethereum::Transaction::Legacy->new(
nonce => '0x9',
gas_price => '0x4A817C800',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => parse_units('1', ETH),
chain_id => '0x1'
);
my $key = Blockchain::Ethereum::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is(unpack("H*", $raw_transaction),
'f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83'
);
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use Blockchain::Ethereum::Key;
subtest "0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b" => sub {
my $private_key = pack "H*", "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d";
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key);
is $key->address, '0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b';
};
subtest "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F" => sub {
my $private_key = pack "H*", "4646464646464646464646464646464646464646464646464646464646464646";
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key);
is $key->address, '0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F';
};
subtest "Fail to sign non-transaction object" => sub {
my $private_key = pack "H*", "4646464646464646464646464646464646464646464646464646464646464646";
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key);
eval { $key->sign_transaction("Not a transaction object"); };
like $@, qr/transaction must be a reference of Blockchain::Ethereum::Transaction/, 'die correctly for non-transaction object';
};
done_testing();