wallet tron transactions

This commit is contained in:
cano
2024-03-25 06:15:36 +08:00
parent 4b8f205e86
commit 489090382f
83 changed files with 5424 additions and 1343 deletions

View File

@ -0,0 +1,57 @@
<?php
namespace Sdk\Wallet\Tools;
/**
* 数据签名
* Class Formatter
* @package Ethereum
*/
class Formatter
{
/**
* 对于方法名和参数类型做签名
* @param $method
* @return string
*/
public static function toMethodFormat($method)
{
return Utils::stripZero(substr(Utils::sha3($method), 0, 10));
}
/**
* 地址签名
* @param $address
* @return string
*/
public static function toAddressFormat($address)
{
if (Utils::isAddress($address)) {
$address = strtolower($address);
if (Utils::isZeroPrefixed($address)) {
$address = Utils::stripZero($address);
}
}
return implode('', array_fill(0, 64 - strlen($address), 0)) . $address;
}
/**
* 数字签名
* @param $value
* @param int $digit
* @return string
*/
public static function toIntegerFormat($value, $digit = 64)
{
$bn = Utils::toBn($value);
$bnHex = $bn->toHex(true);
$padded = mb_substr($bnHex, 0, 1);
if ($padded !== 'f') {
$padded = '0';
}
return implode('', array_fill(0, $digit - mb_strlen($bnHex), $padded)) . $bnHex;
}
}

82
sdk/Wallet/Tools/Key.php Normal file
View File

@ -0,0 +1,82 @@
<?php
namespace Sdk\Wallet\Tools;
use Elliptic\EC;
use IEXBase\TronAPI\Support\Base58;
use IEXBase\TronAPI\Support\Crypto;
use IEXBase\TronAPI\Support\Hash;
use InvalidArgumentException;
class Key
{
/**
* Generate the Address of the provided Public key
*
* @param string $publicKey
*
* @return string
*/
public static function publicKeyToAddress(string $publicKey)
{
if (Utils::isHex($publicKey) === false) {
throw new InvalidArgumentException('Invalid public key format.');
}
$publicKey = Utils::stripZero($publicKey);
if (strlen($publicKey) !== 130) {
throw new InvalidArgumentException('Invalid public key length.');
}
return substr(Utils::sha3(substr(hex2bin($publicKey), 1)), 24);
}
/**
* Generate the Address of the provided Private key
*
* @param string $privateKey
*
* @return string
*/
public static function privateKeyToAddress(string $privateKey)
{
return self::publicKeyToAddress(
self::privateKeyToPublicKey($privateKey)
);
}
/**
* Generate the Public key for provided Private key
*
* @param string $privateKey Private Key
*
* @return string
*/
public static function privateKeyToPublicKey(string $privateKey)
{
if (Utils::isHex($privateKey) === false) {
throw new InvalidArgumentException('Invalid private key format.');
}
$privateKey = Utils::stripZero($privateKey);
if (strlen($privateKey) !== 64) {
throw new InvalidArgumentException('Invalid private key length.');
}
$secp256k1 = new EC('secp256k1');
$privateKey = $secp256k1->keyFromPrivate($privateKey, 'hex');
$publicKey = $privateKey->getPublic(false, 'hex');
return $publicKey;
}
public static function getBase58CheckAddress(string $addressHex): string
{
$addressBin = hex2bin($addressHex);
$hash0 = Hash::SHA256($addressBin);
$hash1 = Hash::SHA256($hash0);
$checksum = substr($hash1, 0, 4);
$checksum = $addressBin . $checksum;
return Base58::encode(Crypto::bin2bc($checksum));
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Sdk\Wallet\Tools;
class Tools
{
}

330
sdk/Wallet/Tools/Utils.php Normal file
View File

@ -0,0 +1,330 @@
<?php
namespace Sdk\Wallet\Tools;
use InvalidArgumentException;
use kornrunner\Keccak;
use phpseclib\Math\BigInteger;
use Psr\Http\Message\StreamInterface;
class Utils
{
/**
* SHA3_NULL_HASH
*
* @const string
*/
const SHA3_NULL_HASH = 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
/**
* NEGATIVE1
* Cannot work, see: http://php.net/manual/en/language.constants.syntax.php
*
* @const
*/
// const NEGATIVE1 = new BigInteger(-1);
/**
* construct
*
* @return void
*/
// public function __construct() {}
/**
* toHex
* Encoding string or integer or numeric string(is not zero prefixed) or big number to hex.
*
* @param string|int|BigInteger $value
* @param bool $isPrefix
* @return string
*/
public static function toHex($value, $isPrefix = false)
{
if (is_numeric($value)) {
// turn to hex number
$bn = self::toBn($value);
$hex = $bn->toHex(true);
$hex = preg_replace('/^0+(?!$)/', '', $hex);
} elseif (is_string($value)) {
$value = self::stripZero($value);
$hex = implode('', unpack('H*', $value));
} elseif ($value instanceof BigInteger) {
$hex = $value->toHex(true);
$hex = preg_replace('/^0+(?!$)/', '', $hex);
} else {
throw new InvalidArgumentException('The value to toHex function is not support.');
}
if ($isPrefix) {
return '0x' . $hex;
}
return $hex;
}
/**
* hexToBin
*
* @param string
* @return string
*/
public static function hexToBin($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to hexToBin function must be string.');
}
if (self::isZeroPrefixed($value)) {
$count = 1;
$value = str_replace('0x', '', $value, $count);
}
return pack('H*', $value);
}
/**
* isZeroPrefixed
*
* @param string
* @return bool
*/
public static function isZeroPrefixed($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to isZeroPrefixed function must be string.');
}
return (strpos($value, '0x') === 0);
}
/**
* stripZero
*
* @param string $value
* @return string
*/
public static function stripZero($value)
{
if (self::isZeroPrefixed($value)) {
$count = 1;
return str_replace('0x', '', $value, $count);
}
return $value;
}
/**
* isNegative
*
* @param string
* @return bool
*/
public static function isNegative($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to isNegative function must be string.');
}
return (strpos($value, '-') === 0);
}
/**
* isAddress
*
* @param string $value
* @return bool
*/
public static function isAddress($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to isAddress function must be string.');
}
if (preg_match('/^(0x|0X)?[a-f0-9A-F]{40}$/', $value) !== 1) {
return false;
} elseif (preg_match('/^(0x|0X)?[a-f0-9]{40}$/', $value) === 1 || preg_match('/^(0x|0X)?[A-F0-9]{40}$/', $value) === 1) {
return true;
}
return self::isAddressChecksum($value);
}
/**
* isAddressChecksum
*
* @param string $value
* @return bool
*/
public static function isAddressChecksum($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to isAddressChecksum function must be string.');
}
$value = self::stripZero($value);
$hash = self::stripZero(self::sha3(mb_strtolower($value)));
for ($i = 0; $i < 40; $i++) {
if (
(intval($hash[$i], 16) > 7 && mb_strtoupper($value[$i]) !== $value[$i]) ||
(intval($hash[$i], 16) <= 7 && mb_strtolower($value[$i]) !== $value[$i])
) {
return false;
}
}
return true;
}
/**
* isHex
*
* @param string $value
* @return bool
*/
public static function isHex($value)
{
return (is_string($value) && preg_match('/^(0x)?[a-f0-9A-F]*$/', $value) === 1);
}
/**
* sha3
* keccak256
*
* @param string $value
* @return string
*/
public static function sha3($value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to sha3 function must be string.');
}
if (strpos($value, '0x') === 0) {
$value = self::hexToBin($value);
}
$hash = Keccak::hash($value, 256);
if ($hash === self::SHA3_NULL_HASH) {
return null;
}
return $hash;
}
/**
* toBn
* Change number or number string to BigInteger.
*
* @param BigInteger|string|int $number
* @return array|BigInteger
*/
public static function toBn($number)
{
if ($number instanceof BigInteger) {
$bn = $number;
} elseif (is_int($number)) {
$bn = new BigInteger($number);
} elseif (is_numeric($number)) {
$number = (string) $number;
if (self::isNegative($number)) {
$count = 1;
$number = str_replace('-', '', $number, $count);
$negative1 = new BigInteger(-1);
}
if (strpos($number, '.') > 0) {
$comps = explode('.', $number);
if (count($comps) > 2) {
throw new InvalidArgumentException('toBn number must be a valid number.');
}
$whole = $comps[0];
$fraction = $comps[1];
return [
new BigInteger($whole),
new BigInteger($fraction),
strlen($comps[1]),
isset($negative1) ? $negative1 : false
];
} else {
$bn = new BigInteger($number);
}
if (isset($negative1)) {
$bn = $bn->multiply($negative1);
}
} elseif (is_string($number)) {
$number = mb_strtolower($number);
if (self::isNegative($number)) {
$count = 1;
$number = str_replace('-', '', $number, $count);
$negative1 = new BigInteger(-1);
}
if (self::isZeroPrefixed($number) || preg_match('/[a-f]+/', $number) === 1) {
$number = self::stripZero($number);
$bn = new BigInteger($number, 16);
} elseif (empty($number)) {
$bn = new BigInteger(0);
} else {
throw new InvalidArgumentException('toBn number must be valid hex string.');
}
if (isset($negative1)) {
$bn = $bn->multiply($negative1);
}
} else {
throw new InvalidArgumentException('toBn number must be BigInteger, string or int.');
}
return $bn;
}
/**
* 根据精度展示资产
* @param $number
* @param int $decimals
* @return string
*/
public static function toDisplayAmount($number, int $decimals)
{
$number = number_format($number,0,'.','');//格式化
$bn = self::toBn($number);
$bnt = self::toBn(pow(10, $decimals));
return self::divideDisplay($bn->divide($bnt), $decimals);
}
public static function divideDisplay(array $divResult, int $decimals)
{
list($bnq, $bnr) = $divResult;
$ret = "$bnq->value";
if ($bnr->value > 0) {
$ret .= '.' . rtrim(sprintf("%0{$decimals}d", $bnr->value), '0');
}
return $ret;
}
public static function toMinUnitByDecimals($number, int $decimals)
{
$bn = self::toBn($number);
$bnt = self::toBn(pow(10, $decimals));
if (is_array($bn)) {
// fraction number
list($whole, $fraction, $fractionLength, $negative1) = $bn;
$whole = $whole->multiply($bnt);
switch (MATH_BIGINTEGER_MODE) {
case $whole::MODE_GMP:
static $two;
$powerBase = gmp_pow(gmp_init(10), (int) $fractionLength);
break;
case $whole::MODE_BCMATH:
$powerBase = bcpow('10', (string) $fractionLength, 0);
break;
default:
$powerBase = pow(10, (int) $fractionLength);
break;
}
$base = new BigInteger($powerBase);
$fraction = $fraction->multiply($bnt)->divide($base)[0];
if ($negative1 !== false) {
return $whole->add($fraction)->multiply($negative1);
}
return $whole->add($fraction);
}
return $bn->multiply($bnt);
}
}