Skip to content

Commit 8a50572

Browse files
committed
fix: small fixes
1 parent dd79025 commit 8a50572

17 files changed

+231
-59
lines changed

.github/workflows/deploy.yml

Whitespace-only changes.

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,4 @@ _ide_helper_models.php
2828
phpunit.xml
2929
phpstan.neon
3030
testbench.yaml
31-
/docs
3231
/coverage

composer.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"@composer run prepare"
5757
],
5858
"prepare": "@php vendor/bin/testbench package:discover --ansi",
59-
"analyse": "vendor/bin/phpstan analyse",
59+
"analyse": "vendor/bin/phpstan analyse --memory-limit 2G",
6060
"test": "vendor/bin/pest",
6161
"test-coverage": "vendor/bin/pest --coverage",
6262
"format": "vendor/bin/pint",
@@ -85,7 +85,12 @@
8585
"Farbcode\\LaravelEvm\\LaravelEvmServiceProvider"
8686
],
8787
"aliases": {
88-
"LaravelEvm": "Farbcode\\LaravelEvm\\Facades\\LaravelEvm"
88+
"LaravelEvm": "Farbcode\\LaravelEvm\\Facades\\LaravelEvm",
89+
"EvmContract": "Farbcode\\LaravelEvm\\Facades\\EvmContract",
90+
"EvmRpc": "Farbcode\\LaravelEvm\\Facades\\EvmRpc",
91+
"EvmSigner": "Farbcode\\LaravelEvm\\Facades\\EvmSigner",
92+
"EvmFees": "Farbcode\\LaravelEvm\\Facades\\EvmFees",
93+
"EvmNonce": "Farbcode\\LaravelEvm\\Facades\\EvmNonce"
8994
}
9095
}
9196
},

src/Clients/ContractClientGeneric.php

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,13 @@
88
use Farbcode\LaravelEvm\Contracts\NonceManager;
99
use Farbcode\LaravelEvm\Contracts\RpcClient;
1010
use Farbcode\LaravelEvm\Contracts\Signer;
11-
use Farbcode\LaravelEvm\Contracts\TxBuilder;
1211
use Farbcode\LaravelEvm\Jobs\SendTransaction;
1312

1413
class ContractClientGeneric implements ContractClient
1514
{
1615
public function __construct(
1716
private RpcClient $rpc,
1817
private Signer $signer,
19-
private NonceManager $nonces,
20-
private FeePolicy $fees,
21-
private TxBuilder $builder,
2218
private AbiCodec $abi,
2319
private int $chainId,
2420
private array $txCfg
@@ -67,15 +63,16 @@ public function sendAsync(string $function, array $args = [], array $opts = []):
6763
$data = $this->abi->encodeFunction($this->abiJson, $function, $args);
6864
$queue = (string) ($this->txCfg['queue'] ?? 'evm-send');
6965

70-
return dispatch(
71-
new SendTransaction(
72-
address: $this->address,
73-
data: $data,
74-
opts: $opts,
75-
chainId: $this->chainId,
76-
txCfg: $this->txCfg
77-
)
78-
)->onQueue($queue)->getJobId();
66+
// Generate a pseudo job identifier (not the queue internal ID) for tracking
67+
$requestId = \Illuminate\Support\Str::uuid()->toString();
68+
dispatch(new SendTransaction(
69+
address: $this->address,
70+
data: $data,
71+
opts: array_merge($opts, ['request_id' => $requestId]),
72+
chainId: $this->chainId,
73+
txCfg: $this->txCfg
74+
))->onQueue($queue);
75+
return $requestId;
7976
}
8077

8178
public function wait(string $txHash, int $timeoutSec = 120, int $pollMs = 800): ?array

src/Codec/AbiCodecWeb3p.php

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,71 @@
66

77
use Farbcode\LaravelEvm\Contracts\AbiCodec;
88
use Web3\Contract;
9+
use kornrunner\Keccak; // keccak256 helper
910

1011
class AbiCodecWeb3p implements AbiCodec
1112
{
1213
public function encodeFunction(array|string $abi, string $fn, array $args): string
1314
{
14-
$c = new Contract('', is_array($abi) ? json_encode($abi) : $abi);
15+
// web3p Contract::getData() returns void and fills internal state. To avoid dynamic property reliance
16+
// implement a lightweight encoder for common static call patterns.
17+
$abiArray = is_string($abi) ? json_decode($abi, true) : $abi;
18+
if (!is_array($abiArray)) {
19+
throw new \InvalidArgumentException('ABI must decode to array');
20+
}
21+
$item = null;
22+
foreach ($abiArray as $entry) {
23+
if (($entry['type'] ?? '') === 'function' && ($entry['name'] ?? '') === $fn) {
24+
$item = $entry; break;
25+
}
26+
}
27+
if (!$item) {
28+
throw new \RuntimeException('Function '.$fn.' not found in ABI');
29+
}
30+
$inputs = $item['inputs'] ?? [];
31+
// Build function selector
32+
$typesSig = implode(',', array_map(fn($i) => $i['type'], $inputs));
33+
$signature = $fn.'('.$typesSig.')';
34+
$hash = Keccak::hash($signature, 256);
35+
$selector = '0x'.substr($hash, 0, 8);
36+
// Encode arguments (very simplified: handles address, uint256, bytes32, bool, string)
37+
$encodedArgs = '';
38+
foreach ($inputs as $idx => $in) {
39+
$type = $in['type'];
40+
$val = $args[$idx] ?? null;
41+
$encodedArgs .= $this->encodeValue($type, $val);
42+
}
43+
return $selector.$encodedArgs;
44+
}
1545

16-
return $c->getData($fn, ...$args);
46+
private function encodeValue(string $type, mixed $val): string
47+
{
48+
// Simplified static encoding (no dynamic types except string truncated)
49+
if (str_starts_with($type, 'uint')) {
50+
return str_pad(dechex((int) $val), 64, '0', STR_PAD_LEFT);
51+
}
52+
if ($type === 'address') {
53+
$clean = strtolower(preg_replace('/^0x/', '', (string) $val));
54+
return str_pad($clean, 64, '0', STR_PAD_LEFT);
55+
}
56+
if ($type === 'bytes32') {
57+
$clean = strtolower(preg_replace('/^0x/', '', (string) $val));
58+
return str_pad(substr($clean, 0, 64), 64, '0', STR_PAD_RIGHT);
59+
}
60+
if ($type === 'bool') {
61+
return str_pad($val ? '1' : '0', 64, '0', STR_PAD_LEFT);
62+
}
63+
if ($type === 'string') {
64+
// naive: hex of string truncated to 32 bytes
65+
$hex = bin2hex((string) $val);
66+
return str_pad(substr($hex, 0, 64), 64, '0', STR_PAD_RIGHT);
67+
}
68+
throw new \RuntimeException('Unsupported ABI type '.$type);
1769
}
1870

1971
public function callStatic(array|string $abi, string $fn, array $args, callable $ethCall): mixed
2072
{
2173
$data = $this->encodeFunction($abi, $fn, $args);
22-
2374
return $ethCall($data);
2475
}
2576
}

src/Commands/EvmCallCommand.php

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

55
namespace Farbcode\LaravelEvm\Commands;
66

7-
use Farbcode\LaravelEvm\LaravelEvm;
7+
use Farbcode\LaravelEvm\Facades\LaravelEvm as LaravelEvmFacade;
88
use Illuminate\Console\Command;
99

1010
// Facade Alias
@@ -22,7 +22,7 @@ public function handle(): int
2222
$fn = $this->argument('function');
2323
$args = $this->argument('args');
2424

25-
$res = LaravelEvm::at($addr, $abi)->call($fn, $args);
25+
$res = LaravelEvmFacade::at($addr, $abi)->call($fn, $args);
2626
$this->line(json_encode($res, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
2727

2828
return self::SUCCESS;

src/Commands/EvmSendCommand.php

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

55
namespace Farbcode\LaravelEvm\Commands;
66

7-
use Farbcode\LaravelEvm\LaravelEvm;
7+
use Farbcode\LaravelEvm\Facades\LaravelEvm as LaravelEvmFacade;
88
use Illuminate\Console\Command;
99

1010
// Facade Alias
@@ -23,7 +23,7 @@ public function handle(): int
2323
$args = $this->argument('args');
2424
$timeout = (int) $this->option('timeout');
2525

26-
$jobId = LaravelEvm::at($addr, $abi)->sendAsync($fn, $args, ['timeout' => $timeout]);
26+
$jobId = LaravelEvmFacade::at($addr, $abi)->sendAsync($fn, $args, ['timeout' => $timeout]);
2727
$this->info('Queued job id '.$jobId);
2828
$this->info('Queue '.config('evm.tx.queue'));
2929

src/Crypto/TxBuilderEip1559.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@ class TxBuilderEip1559 implements TxBuilder
1414
public function build(array $fields): string
1515
{
1616
$tx = new EIP1559Transaction($fields);
17-
18-
return $tx->serialize(); // unsigned RLP
17+
$serialized = $tx->serialize();
18+
// Library returns Buffer implementing __toString(); cast directly without redundant is_object() check.
19+
if (method_exists($serialized, '__toString')) {
20+
$serialized = (string) $serialized;
21+
}
22+
if (!is_string($serialized)) {
23+
throw new \RuntimeException('Unexpected serialized type for transaction');
24+
}
25+
return $serialized; // unsigned RLP hex
1926
}
2027

2128
/**
@@ -26,7 +33,8 @@ public function hashUnsigned(array $fields): string
2633
{
2734
$tx = new EIP1559Transaction($fields);
2835
if (method_exists($tx, 'hash')) {
29-
return $tx->hash(false);
36+
// Only call hash() without arguments; do not force unsupported signatures.
37+
return $tx->hash();
3038
}
3139
throw new \BadMethodCallException('Unsigned hash not supported by this EIP1559Transaction version');
3240
}

src/Facades/EvmContract.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Farbcode\LaravelEvm\Facades;
4+
5+
use Illuminate\Support\Facades\Facade;
6+
use Farbcode\LaravelEvm\Contracts\ContractClient;
7+
8+
class EvmContract extends Facade
9+
{
10+
protected static function getFacadeAccessor(): string
11+
{
12+
return ContractClient::class;
13+
}
14+
}

src/Facades/EvmFees.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Farbcode\LaravelEvm\Facades;
4+
5+
use Illuminate\Support\Facades\Facade;
6+
use Farbcode\LaravelEvm\Contracts\FeePolicy;
7+
8+
class EvmFees extends Facade
9+
{
10+
protected static function getFacadeAccessor(): string
11+
{
12+
return FeePolicy::class;
13+
}
14+
}

0 commit comments

Comments
 (0)