|
| 1 | +<?php |
| 2 | + |
| 3 | +use Illuminate\Support\Facades\Artisan; |
| 4 | +use Farbcode\LaravelEvm\Contracts\RpcClient; |
| 5 | +use Farbcode\LaravelEvm\Contracts\Signer; |
| 6 | +use Farbcode\LaravelEvm\Contracts\FeePolicy; |
| 7 | +use Farbcode\LaravelEvm\Contracts\NonceManager; |
| 8 | +use Illuminate\Support\Facades\Event; |
| 9 | + |
| 10 | +class BumpSigner implements Signer { |
| 11 | + public function getAddress(): string { return '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'; } |
| 12 | + public function privateKey(): string { return '0x'.str_repeat('11',32); } |
| 13 | +} |
| 14 | +class BumpRpc implements RpcClient { |
| 15 | + public array $sent = []; |
| 16 | + public function call(string $m, array $p = []): mixed { |
| 17 | + return match($m) { |
| 18 | + 'eth_getTransactionCount' => '0x5', // latest and pending both 0x5 -> no pending |
| 19 | + 'eth_gasPrice' => '0x3b9aca00', |
| 20 | + 'eth_chainId' => '0x89', // 137 |
| 21 | + 'eth_sendRawTransaction' => ($this->sent[] = $p[0]) && '0xhash123', |
| 22 | + default => '0x1' |
| 23 | + }; |
| 24 | + } |
| 25 | + public function callRaw(string $m, array $p = []): array { return ['result' => '0x1']; } |
| 26 | + public function health(): array { return ['chainId' => 137, 'block' => 1]; } |
| 27 | + public function getLogs(array $filter): array { return []; } |
| 28 | +} |
| 29 | +class BumpFees implements FeePolicy { public function suggest(callable $f): array { return [1_000_000_000, 50_000_000_000]; } public function replace(int $a,int $b): array { return [$a*2,$b*2]; } } |
| 30 | +class BumpNonce implements NonceManager { public function getPendingNonce(string $a, callable $b): int { return 5; } public function markUsed(string $a,int $n): void {} } |
| 31 | + |
| 32 | +it('fails gracefully when no pending nonce', function() { |
| 33 | + app()->bind(Signer::class, fn() => new BumpSigner); |
| 34 | + app()->bind(RpcClient::class, fn() => new BumpRpc); |
| 35 | + app()->bind(FeePolicy::class, fn() => new BumpFees); |
| 36 | + app()->bind(NonceManager::class, fn() => new BumpNonce); |
| 37 | + $code = Artisan::call('evm:bump'); |
| 38 | + expect($code)->toBe(1); // FAILURE |
| 39 | +}); |
| 40 | + |
| 41 | +it('broadcasts when explicit nonce provided', function() { |
| 42 | + app()->bind(Signer::class, fn() => new BumpSigner); |
| 43 | + app()->bind(RpcClient::class, fn() => new BumpRpc); |
| 44 | + app()->bind(FeePolicy::class, fn() => new BumpFees); |
| 45 | + app()->bind(NonceManager::class, fn() => new BumpNonce); |
| 46 | + $code = Artisan::call('evm:bump', ['--nonce' => 4, '--dry-run' => true]); |
| 47 | + expect($code)->toBe(0); |
| 48 | +}); |
0 commit comments