feat: new chain
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Chain;
|
||||
|
||||
use Elliptic\EC;
|
||||
use kornrunner\Keccak;
|
||||
use RuntimeException;
|
||||
|
||||
final class EthSigner
|
||||
{
|
||||
/**
|
||||
* Sign a legacy EIP-155 transaction.
|
||||
*
|
||||
* @param array{nonce: string, gasPrice: string, gas: string, to: string, value: string, data: string} $tx
|
||||
* @return string 0x-prefixed raw tx hex
|
||||
*/
|
||||
public static function signLegacy(string $privateKeyHex, array $tx, int $chainId): string
|
||||
{
|
||||
$privateKeyHex = strtolower($privateKeyHex);
|
||||
if (str_starts_with($privateKeyHex, '0x')) {
|
||||
$privateKeyHex = substr($privateKeyHex, 2);
|
||||
}
|
||||
$to = strtolower($tx['to']);
|
||||
if (str_starts_with($to, '0x')) {
|
||||
$to = substr($to, 2);
|
||||
}
|
||||
$data = strtolower($tx['data'] ?? '');
|
||||
if (str_starts_with($data, '0x')) {
|
||||
$data = substr($data, 2);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
EthRlp::intToBin($tx['nonce']),
|
||||
EthRlp::intToBin($tx['gasPrice']),
|
||||
EthRlp::intToBin($tx['gas']),
|
||||
hex2bin($to) ?: '',
|
||||
EthRlp::intToBin($tx['value']),
|
||||
$data === '' ? '' : (hex2bin($data) ?: ''),
|
||||
EthRlp::intToBin((string) $chainId),
|
||||
'',
|
||||
'',
|
||||
];
|
||||
|
||||
$unsigned = EthRlp::encodeList($fields);
|
||||
$hash = Keccak::hash($unsigned, 256);
|
||||
|
||||
$ec = new EC('secp256k1');
|
||||
$key = $ec->keyFromPrivate($privateKeyHex);
|
||||
$sig = $key->sign($hash, ['canonical' => true]);
|
||||
|
||||
$r = str_pad($sig->r->toString(16), 64, '0', STR_PAD_LEFT);
|
||||
$s = str_pad($sig->s->toString(16), 64, '0', STR_PAD_LEFT);
|
||||
$recovery = (int) ($sig->recoveryParam ?? 0);
|
||||
$v = (string) ($recovery + 35 + $chainId * 2);
|
||||
|
||||
$signed = EthRlp::encodeList([
|
||||
EthRlp::intToBin($tx['nonce']),
|
||||
EthRlp::intToBin($tx['gasPrice']),
|
||||
EthRlp::intToBin($tx['gas']),
|
||||
hex2bin($to) ?: '',
|
||||
EthRlp::intToBin($tx['value']),
|
||||
$data === '' ? '' : (hex2bin($data) ?: ''),
|
||||
EthRlp::intToBin($v),
|
||||
hex2bin($r) ?: '',
|
||||
hex2bin($s) ?: '',
|
||||
]);
|
||||
|
||||
return '0x'.bin2hex($signed);
|
||||
}
|
||||
|
||||
public static function publicAddress(string $privateKeyHex): string
|
||||
{
|
||||
$privateKeyHex = strtolower($privateKeyHex);
|
||||
if (str_starts_with($privateKeyHex, '0x')) {
|
||||
$privateKeyHex = substr($privateKeyHex, 2);
|
||||
}
|
||||
$ec = new EC('secp256k1');
|
||||
$pub = $ec->keyFromPrivate($privateKeyHex)->getPublic(false, 'hex');
|
||||
|
||||
return EthAddress::fromUncompressedPublicKey($pub);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user