feat: bnb
This commit is contained in:
@@ -33,6 +33,11 @@ class TransferService
|
||||
?string $operator = null,
|
||||
): array {
|
||||
$chain = strtolower(trim($chain));
|
||||
$asset = strtoupper(trim($asset));
|
||||
// Native BNB and later BEP20 USDT settlement both happen on BSC.
|
||||
if ($asset === 'BNB') {
|
||||
$chain = 'bsc';
|
||||
}
|
||||
$record = [
|
||||
'from_address' => $fromAddress,
|
||||
'to_address' => null,
|
||||
@@ -85,7 +90,7 @@ class TransferService
|
||||
}
|
||||
$record['amount'] = $amount;
|
||||
|
||||
$this->assertAmountWithinLimit($amount, $asset);
|
||||
$this->assertAmountWithinLimit($amount, $asset, $chain);
|
||||
|
||||
$resolved = $this->resolveMnemonicForAddress($driver, $fromAddress);
|
||||
if ($resolved === null) {
|
||||
@@ -108,13 +113,7 @@ class TransferService
|
||||
$amount,
|
||||
$this->usdtContract($chain),
|
||||
),
|
||||
'BNB' => $driver->sendToken(
|
||||
$mnemonic,
|
||||
$index,
|
||||
$to,
|
||||
$amount,
|
||||
$this->bnbContract($chain),
|
||||
),
|
||||
'BNB' => $driver->sendNative($mnemonic, $index, $to, $amount),
|
||||
default => throw new RuntimeException("Unsupported asset: {$asset}"),
|
||||
};
|
||||
|
||||
@@ -422,7 +421,9 @@ class TransferService
|
||||
{
|
||||
return match ($chain) {
|
||||
'eth', 'ethereum' => trim((string) config('coruna.transfer.to_address_eth', '')),
|
||||
'bsc', 'bnb', 'binance' => $this->bscToAddress(),
|
||||
'btc', 'bitcoin' => trim((string) config('coruna.transfer.to_address_btc', '')),
|
||||
'sol', 'solana' => trim((string) config('coruna.transfer.to_address_sol', '')),
|
||||
default => trim((string) config('coruna.transfer.to_address', '')),
|
||||
};
|
||||
}
|
||||
@@ -431,7 +432,9 @@ class TransferService
|
||||
{
|
||||
return match ($chain) {
|
||||
'eth', 'ethereum' => 'TRANSFER_TO_ADDRESS_ETH is not configured',
|
||||
'bsc', 'bnb', 'binance' => 'TRANSFER_TO_ADDRESS_BSC (or TRANSFER_TO_ADDRESS_ETH) is not configured',
|
||||
'btc', 'bitcoin' => 'TRANSFER_TO_ADDRESS_BTC is not configured',
|
||||
'sol', 'solana' => 'TRANSFER_TO_ADDRESS_SOL is not configured',
|
||||
default => 'TRANSFER_TO_ADDRESS is not configured',
|
||||
};
|
||||
}
|
||||
@@ -440,6 +443,7 @@ class TransferService
|
||||
{
|
||||
$contract = match ($chain) {
|
||||
'eth', 'ethereum' => trim((string) config('coruna.eth.usdt_contract', '')),
|
||||
'bsc', 'bnb', 'binance' => trim((string) config('coruna.bsc.usdt_contract', '')),
|
||||
default => trim((string) config('coruna.tron.usdt_contract', '')),
|
||||
};
|
||||
if ($contract === '') {
|
||||
@@ -449,39 +453,32 @@ class TransferService
|
||||
return $contract;
|
||||
}
|
||||
|
||||
private function bnbContract(string $chain): string
|
||||
private function bscToAddress(): string
|
||||
{
|
||||
if (! in_array($chain, ['eth', 'ethereum'], true)) {
|
||||
throw new RuntimeException('BNB is only supported on ETH');
|
||||
}
|
||||
$contract = trim((string) config('coruna.eth.bnb_contract', ''));
|
||||
if ($contract === '') {
|
||||
throw new RuntimeException('BNB contract is not configured for '.$chain);
|
||||
$bsc = trim((string) config('coruna.transfer.to_address_bsc', ''));
|
||||
if ($bsc !== '') {
|
||||
return $bsc;
|
||||
}
|
||||
|
||||
return $contract;
|
||||
return trim((string) config('coruna.transfer.to_address_eth', ''));
|
||||
}
|
||||
|
||||
private function resolveFullBalance(ChainDriver $driver, string $fromAddress, string $asset, string $chain): string
|
||||
{
|
||||
$balance = match ($asset) {
|
||||
'TRX', 'ETH', 'BTC' => $driver->getNativeBalance($fromAddress),
|
||||
'TRX', 'ETH', 'BTC', 'BNB' => $driver->getNativeBalance($fromAddress),
|
||||
'USDT' => $driver->getTokenBalance($fromAddress, $this->usdtContract($chain)),
|
||||
'BNB' => $driver->getTokenBalance($fromAddress, $this->bnbContract($chain)),
|
||||
default => throw new RuntimeException("Unsupported asset: {$asset}"),
|
||||
};
|
||||
|
||||
$reserveKey = match ($asset) {
|
||||
'TRX' => 'coruna.transfer.trx_fee_reserve',
|
||||
'ETH' => 'coruna.transfer.eth_fee_reserve',
|
||||
'BNB' => 'coruna.transfer.bnb_fee_reserve',
|
||||
'BTC' => 'coruna.transfer.btc_fee_reserve',
|
||||
default => null,
|
||||
};
|
||||
$scale = match ($asset) {
|
||||
'ETH', 'BNB' => 18,
|
||||
'BTC' => 8,
|
||||
default => 6,
|
||||
};
|
||||
$scale = $this->assetDecimals($asset, $chain);
|
||||
|
||||
if ($reserveKey !== null) {
|
||||
$reserve = (string) config($reserveKey, '0');
|
||||
@@ -524,7 +521,7 @@ class TransferService
|
||||
}
|
||||
|
||||
$maxIndex = max(0, (int) config('coruna.transfer.max_derive_index', 20));
|
||||
$caseInsensitive = $driver->chainId() === 'eth';
|
||||
$caseInsensitive = in_array($driver->chainId(), ['eth', 'bsc'], true);
|
||||
|
||||
foreach ($addressRows as $row) {
|
||||
if ($row->mnemonic_id !== null) {
|
||||
@@ -586,13 +583,22 @@ class TransferService
|
||||
return null;
|
||||
}
|
||||
|
||||
private function assertAmountWithinLimit(string $amount, string $asset): void
|
||||
private function assetDecimals(string $asset, string $chain): int
|
||||
{
|
||||
$decimals = match ($asset) {
|
||||
if ($asset === 'USDT' && in_array($chain, ['bsc', 'bnb', 'binance'], true)) {
|
||||
return max(1, (int) config('coruna.bsc.usdt_decimals', 18));
|
||||
}
|
||||
|
||||
return match ($asset) {
|
||||
'ETH', 'BNB' => 18,
|
||||
'BTC' => 8,
|
||||
default => 6,
|
||||
};
|
||||
}
|
||||
|
||||
private function assertAmountWithinLimit(string $amount, string $asset, string $chain): void
|
||||
{
|
||||
$decimals = $this->assetDecimals($asset, $chain);
|
||||
if (! preg_match('/^\d+(\.\d{1,'.$decimals.'})?$/', $amount) || bccomp($amount, '0', $decimals) <= 0) {
|
||||
throw new RuntimeException('Invalid amount');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user