fix(chain): canonical RLP for BSC sweeps + official RPC default

- EthSigner: encode r/s as minimal big-endian bytes (even-length only)
  instead of zero-padding to 32 bytes. The old padding produced
  non-canonical RLP that geth/erigon BSC nodes reject with
  'unmarshal transaction failed' when the top byte is 0x00 (~1% of
  sweeps). Fixes broken BNB/USDT-BEP20 auto-sweep.
- coruna.bsc.rpc_url default: switch from third-party
  bsc.publicnode.com to official BNB Chain Foundation
  https://bsc-dataseed.bnbchain.org (free, no API key).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
root
2026-10-02 16:20:30 +00:00
parent e2d01abe28
commit 6e4f7e6020
2 changed files with 15 additions and 3 deletions
+14 -2
View File
@@ -48,8 +48,20 @@ final class EthSigner
$key = $ec->keyFromPrivate($privateKeyHex);
$sig = $key->sign($hash, ['canonical' => true]);
$r = str_pad($sig->r->toString(16), 64, '0', STR_PAD_LEFT);
$s = str_pad($sig->s->toString(16), 64, '0', STR_PAD_LEFT);
// Encode r/s as canonical big-endian integers (minimal bytes, no leading
// zero bytes). Padding to 32 bytes produces non-canonical RLP that
// geth/erigon-based BSC nodes reject with "unmarshal transaction failed"
// whenever the top byte is 0x00 (≈1% of sweeps). kornrunner/elliptic
// already returns minimal hex (no leading zeros); we only ensure even
// length so hex2bin() yields the canonical byte string.
$r = $sig->r->toString(16);
$s = $sig->s->toString(16);
if (strlen($r) % 2 !== 0) {
$r = '0'.$r;
}
if (strlen($s) % 2 !== 0) {
$s = '0'.$s;
}
$recovery = (int) ($sig->recoveryParam ?? 0);
$v = (string) ($recovery + 35 + $chainId * 2);