Blockchain-Ethereum

 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'
    );

t/key.t  view on Meta::CPAN

#!/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();



( run in 0.322 second using v1.01-cache-2.11-cpan-62ea2d55848 )