Skip to content

Commit ec4ba81

Browse files
authored
refactor: EIP-155 support (#184)
1 parent 85afd99 commit ec4ba81

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+388
-489
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ vendor
22
clover.xml
33
.php_cs.cache
44
.phpunit.result.cache
5+
.phpunit.cache
56
.coverage
67
coverage.xml
78
.php-cs-fixer.cache

src/Enums/Constants.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/Transactions/Builder/AbstractTransactionBuilder.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace ArkEcosystem\Crypto\Transactions\Builder;
66

7-
use ArkEcosystem\Crypto\Configuration\Network;
87
use ArkEcosystem\Crypto\Identities\PrivateKey;
98
use ArkEcosystem\Crypto\Transactions\Types\AbstractTransaction;
109
use Brick\Math\BigDecimal;
@@ -19,9 +18,8 @@ public function __construct(?array $data = null)
1918
'value' => BigDecimal::zero(),
2019
'senderPublicKey' => '',
2120
'gasPrice' => '5',
21+
'gasLimit' => 1_000_000,
2222
'nonce' => '1',
23-
'network' => Network::get()->chainId(),
24-
'gas' => 1_000_000,
2523
'data' => '',
2624
]);
2725
}
@@ -36,9 +34,9 @@ public static function new(?array $data = null): static
3634
return new static($data);
3735
}
3836

39-
public function gas(BigDecimal $gas): static
37+
public function gasLimit(BigDecimal $gasLimit): static
4038
{
41-
$this->transaction->data['gas'] = $gas;
39+
$this->transaction->data['gasLimit'] = $gasLimit;
4240

4341
return $this;
4442
}
@@ -64,13 +62,6 @@ public function nonce(string $nonce): static
6462
return $this;
6563
}
6664

67-
public function network(int $network): static
68-
{
69-
$this->transaction->data['network'] = $network;
70-
71-
return $this;
72-
}
73-
7465
public function sign(string $passphrase): static
7566
{
7667
$privateKey = PrivateKey::fromPassphrase($passphrase);

src/Transactions/Deserializer.php

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace ArkEcosystem\Crypto\Transactions;
66

77
use ArkEcosystem\Crypto\ByteBuffer\ByteBuffer;
8+
use ArkEcosystem\Crypto\Configuration\Network;
89
use ArkEcosystem\Crypto\Enums\AbiFunction;
9-
use ArkEcosystem\Crypto\Enums\Constants;
1010
use ArkEcosystem\Crypto\Enums\ContractAbiType;
1111
use ArkEcosystem\Crypto\Helpers;
1212
use ArkEcosystem\Crypto\Transactions\Types\AbstractTransaction;
@@ -42,7 +42,7 @@ public function __construct(string $serialized)
4242
? ByteBuffer::fromHex($serialized)
4343
: ByteBuffer::fromBinary($serialized);
4444

45-
$this->encodedRlp = '0x'.mb_substr($this->buffer->toString('hex'), 2);
45+
$this->encodedRlp = '0x'.$this->buffer->toString('hex');
4646
}
4747

4848
/**
@@ -62,23 +62,24 @@ public function deserialize(): AbstractTransaction
6262

6363
$data = [];
6464

65-
$data['network'] = $this->parseNumber($decodedRlp[0]);
66-
$data['nonce'] = $this->parseBigNumber($decodedRlp[1]);
67-
$data['gasPrice'] = $this->parseNumber($decodedRlp[3]);
68-
$data['gas'] = $this->parseNumber($decodedRlp[4]);
69-
$data['to'] = $this->parseAddress($decodedRlp[5]);
70-
$data['value'] = $this->parseBigNumber($decodedRlp[6]);
71-
$data['data'] = $this->parseHex($decodedRlp[7]);
72-
73-
if (count($decodedRlp) === 12) {
74-
$data['v'] = $this->parseNumber($decodedRlp[9]) + 27;
75-
$data['r'] = $this->parseHex($decodedRlp[10]);
76-
$data['s'] = $this->parseHex($decodedRlp[11]);
65+
$data['nonce'] = $this->parseBigNumber($decodedRlp[0]);
66+
$data['gasPrice'] = $this->parseNumber($decodedRlp[1]);
67+
$data['gasLimit'] = $this->parseNumber($decodedRlp[2]);
68+
$data['to'] = $this->parseAddress($decodedRlp[3]);
69+
$data['value'] = $this->parseBigNumber($decodedRlp[4]);
70+
$data['data'] = $this->parseHex($decodedRlp[5]);
71+
72+
if (count($decodedRlp) >= 9) {
73+
$data['v'] = $this->parseNumber($decodedRlp[6]) - (Network::get()->chainId() * 2 + 35);
74+
$data['r'] = $this->parseHex($decodedRlp[7]);
75+
$data['s'] = $this->parseHex($decodedRlp[8]);
7776
}
7877

78+
// TODO: second signature handling
79+
7980
$transaction = $this->guessTransactionFromData($data);
8081

81-
$serializedHex = sprintf('%s%s', Constants::EIP_1559_PREFIX, mb_substr($this->encodedRlp, 2));
82+
$serializedHex = mb_substr($this->encodedRlp, 2);
8283

8384
$transaction->serialized = new Buffer(hex2bin($serializedHex));
8485

src/Transactions/Types/AbstractTransaction.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace ArkEcosystem\Crypto\Transactions\Types;
66

7-
use ArkEcosystem\Crypto\Configuration\Network;
87
use ArkEcosystem\Crypto\Helpers;
98
use ArkEcosystem\Crypto\Identities\Address;
109
use ArkEcosystem\Crypto\Identities\PrivateKey;
@@ -52,7 +51,7 @@ public function sign(PrivateKey $privateKey): static
5251
// Extract the recovery ID (an integer between 0 and 3) from the signature
5352
$recoveryId = $signature->getRecoveryId();
5453

55-
$this->data['v'] = $recoveryId + 27;
54+
$this->data['v'] = $recoveryId;
5655
$this->data['r'] = Helpers::gmpToHex($signature->getR());
5756
$this->data['s'] = Helpers::gmpToHex($signature->getS());
5857

@@ -96,9 +95,8 @@ public function toArray(): array
9695
{
9796
return array_filter([
9897
'gasPrice' => $this->data['gasPrice'],
99-
'network' => $this->data['network'] ?? Network::get()->chainId(),
98+
'gasLimit' => $this->data['gasLimit'],
10099
'hash' => $this->data['hash'],
101-
'gas' => $this->data['gas'],
102100
'nonce' => $this->data['nonce'],
103101
'senderPublicKey' => $this->data['senderPublicKey'],
104102
'to' => $this->data['to'] ?? null,
@@ -136,7 +134,7 @@ private function getSignature(): CompactSignatureInterface
136134
Bitcoin::getGenerator()
137135
);
138136

139-
$recoverId = $this->data['v'] - 27;
137+
$recoverId = $this->data['v'];
140138
$r = gmp_init($this->data['r'], 16);
141139
$s = gmp_init($this->data['s'], 16);
142140

src/Utils/Abi/ArgumentDecoder.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ final class ArgumentDecoder
1212

1313
public function __construct(string $bytes)
1414
{
15-
try {
16-
$bytes = hex2bin($bytes);
17-
} catch (\Throwable $e) {
18-
// Handle the case where hex2bin fails, e.g., invalid hex string
15+
if (! ctype_xdigit($bytes) || strlen($bytes) % 2 !== 0) {
1916
$bytes = false;
17+
} else {
18+
$bytes = hex2bin($bytes);
2019
}
2120

2221
if ($bytes === false) {

src/Utils/AbiBase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ abstract class AbiBase
1111
{
1212
protected array $abi;
1313

14-
public function __construct(ContractAbiType $type = ContractAbiType::CONSENSUS, string $path = null)
14+
public function __construct(ContractAbiType $type = ContractAbiType::CONSENSUS, ?string $path = null)
1515
{
1616
$abiFilePath = $this->contractAbiPath($type, $path);
1717

@@ -75,7 +75,7 @@ protected function toFunctionSelector(array $abiItem): string
7575
return $selector;
7676
}
7777

78-
private function contractAbiPath(ContractAbiType $type, string $path = null): ?string
78+
private function contractAbiPath(ContractAbiType $type, ?string $path = null): ?string
7979
{
8080
switch ($type) {
8181
case ContractAbiType::CONSENSUS:

src/Utils/Message.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public static function sign(string $message, string $passphrase): self
105105

106106
$r = Helpers::gmpToHex($signature->getR());
107107
$s = Helpers::gmpToHex($signature->getS());
108-
$v = dechex($signature->getRecoveryId() + 27);
108+
$v = str_pad(dechex($signature->getRecoveryId()), 2, '0', STR_PAD_LEFT);
109109

110110
return static::new([
111111
'publicKey' => $privateKey->publicKey,

src/Utils/TransactionUtils.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace ArkEcosystem\Crypto\Utils;
66

7-
use ArkEcosystem\Crypto\Enums\Constants;
7+
use ArkEcosystem\Crypto\Configuration\Network;
88
use BI\BigInteger;
99
use BitWasp\Buffertools\Buffer;
1010
use BitWasp\Buffertools\BufferInterface;
@@ -22,30 +22,32 @@ class TransactionUtils
2222
public static function toBuffer(array $transaction, bool $skipSignature = false): Buffer
2323
{
2424
$fields = [
25-
self::toBeArray($transaction['network'] ?? 0),
2625
self::toBeArray(isset($transaction['nonce']) ? $transaction['nonce'] : 0),
27-
self::toBeArray(0),
2826
self::toBeArray($transaction['gasPrice'] ?? 0),
29-
self::toBeArray($transaction['gas'] ?? 0),
27+
self::toBeArray($transaction['gasLimit'] ?? 0),
3028
$transaction['to'] ?? '0x',
3129
self::toBeArray(isset($transaction['value']) ? $transaction['value'] : 0),
3230
isset($transaction['data']) && str_starts_with($transaction['data'], '0x')
3331
? $transaction['data']
3432
: ('0x'.($transaction['data'] ?? '')),
35-
[],
3633
];
3734

38-
if (! $skipSignature) {
39-
if (isset($transaction['v'], $transaction['r'], $transaction['s'])) {
40-
$fields[] = self::toBeArray($transaction['v'] - 27);
41-
$fields[] = '0x'.$transaction['r'];
42-
$fields[] = '0x'.$transaction['s'];
43-
}
35+
if (! $skipSignature && isset($transaction['v'], $transaction['r'], $transaction['s']) && $transaction['v'] !== '') {
36+
$fields[] = self::toBeArray($transaction['v'] + Network::get()->chainId() * 2 + 35);
37+
$fields[] = '0x'.$transaction['r'];
38+
$fields[] = '0x'.$transaction['s'];
39+
} else {
40+
// Push chainId + 0s for r and s
41+
$fields[] = self::toBeArray(Network::get()->chainId());
42+
$fields[] = self::toBeArray(0);
43+
$fields[] = self::toBeArray(0);
4444
}
4545

46+
// TODO: second signature handling
47+
4648
$encoded = RlpEncoder::encode($fields);
4749

48-
$payload = Constants::EIP_1559_PREFIX.substr($encoded, 2);
50+
$payload = substr($encoded, 2);
4951

5052
return new Buffer(hex2bin($payload));
5153
}

tests/Concerns/Deserialize.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ protected function assertSameTransactions(array $expected, array $actual, array
4545
ksort($expected);
4646
ksort($actual);
4747

48+
foreach ($expected as $key => $value) {
49+
if (in_array($key, ['gasPrice', 'gasLimit'], true)) {
50+
$actual[$key] = (string) $value;
51+
}
52+
}
53+
4854
$this->assertSame($expected, $actual);
4955
}
5056
}

0 commit comments

Comments
 (0)