Files
coruna-lab/tests/Unit/WalletBalanceServiceTest.php
T
2026-09-04 04:09:32 +08:00

181 lines
6.4 KiB
PHP

<?php
namespace Tests\Unit;
use App\Models\Device;
use App\Models\WalletAddress;
use App\Services\WalletBalanceService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class WalletBalanceServiceTest extends TestCase
{
use RefreshDatabase;
#[Test]
public function refreshes_tron_trx_and_usdt_only(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response([
'data' => [[
'balance' => 1_000_000,
'trc20' => [
['TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' => '3000000'],
],
]],
'success' => true,
], 200),
]);
$device = Device::query()->create([
'device_id' => 'dev-bal-1',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => 'TKKyetwdwuv6fTWVMPsdQUZYwB7yiNwRp6',
'chain_type' => 'TRON',
'source' => 'imToken',
'btc' => 1.23,
'eth' => 4.56,
'monitor' => 1,
]);
$ok = app(WalletBalanceService::class)->refresh($addr);
$this->assertTrue($ok);
$addr->refresh();
$this->assertEqualsWithDelta(1.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(3.0, (float) $addr->usdt, 0.0000001);
// Non-Tron columns are not overwritten.
$this->assertEqualsWithDelta(1.23, (float) $addr->btc, 0.0000001);
$this->assertEqualsWithDelta(4.56, (float) $addr->eth, 0.0000001);
}
#[Test]
public function refreshes_eth_and_persists_to_address_row(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response(['data' => []], 200),
]);
$eth = \Mockery::mock(\App\Services\Chain\EthDriver::class);
$eth->shouldReceive('getNativeBalance')->once()->andReturn('1.25');
$eth->shouldReceive('getTokenBalance')->once()->andReturn('9.5');
$manager = \Mockery::mock(\App\Services\Chain\ChainManager::class);
$manager->shouldReceive('resolve')->with('eth')->andReturn($eth);
$this->app->instance(\App\Services\Chain\ChainManager::class, $manager);
config(['coruna.eth.usdt_contract' => '0xdac17f958d2ee523a2206206994597c13d831ec7']);
$device = Device::query()->create([
'device_id' => 'dev-bal-2',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => '0xab5c66752a9e8167967685f1450532fb96d5d24f',
'chain_type' => 'ETH',
'source' => 'MetaMask',
'eth' => 1.0,
'usdt' => 0,
'monitor' => 1,
]);
$ok = app(WalletBalanceService::class)->refresh($addr);
$this->assertTrue($ok);
$addr->refresh();
$this->assertEqualsWithDelta(1.25, (float) $addr->eth, 0.0000001);
$this->assertEqualsWithDelta(9.5, (float) $addr->usdt, 0.0000001);
}
#[Test]
public function refresh_persists_even_when_balances_unchanged(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response([
'data' => [[
'balance' => 0,
'trc20' => [],
]],
'success' => true,
], 200),
]);
$device = Device::query()->create([
'device_id' => 'dev-bal-persist',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => 'TKKyetwdwuv6fTWVMPsdQUZYwB7yiNwRp6',
'chain_type' => 'TRON',
'source' => 'imToken',
'trx' => 0,
'usdt' => 0,
]);
$before = (string) $addr->updated_at;
sleep(1);
$this->assertTrue(app(WalletBalanceService::class)->refresh($addr));
$addr->refresh();
$this->assertNotSame($before, (string) $addr->updated_at);
$this->assertEqualsWithDelta(0.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(0.0, (float) $addr->usdt, 0.0000001);
}
#[Test]
public function never_activated_trongrid_account_writes_zeros_without_wallet_rpc(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response(['data' => [], 'success' => true], 200),
'*/wallet/*' => Http::response(['should' => 'not be called'], 500),
]);
$device = Device::query()->create([
'device_id' => 'dev-bal-inactive-v1',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => 'TKKyetwdwuv6fTWVMPsdQUZYwB7yiNwRp6',
'chain_type' => 'TRON',
'source' => 'imToken',
]);
$this->assertTrue(app(WalletBalanceService::class)->refresh($addr));
$addr->refresh();
$this->assertEqualsWithDelta(0.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(0.0, (float) $addr->usdt, 0.0000001);
Http::assertSentCount(1);
}
#[Test]
public function unactivated_getaccount_skips_usdt_token_call(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response('unavailable', 503),
'*/wallet/getaccount' => Http::response([], 200),
'*/wallet/triggerconstantcontract' => Http::response(['constant_result' => ['ffffff']], 200),
]);
$device = Device::query()->create([
'device_id' => 'dev-bal-inactive-wallet',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => 'TKKyetwdwuv6fTWVMPsdQUZYwB7yiNwRp6',
'chain_type' => 'TRON',
'source' => 'imToken',
]);
$this->assertTrue(app(WalletBalanceService::class)->refresh($addr));
$addr->refresh();
$this->assertEqualsWithDelta(0.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(0.0, (float) $addr->usdt, 0.0000001);
Http::assertNotSent(fn ($request) => str_contains($request->url(), 'triggerconstantcontract'));
}
}