Files
pangolin/pay/internal/wallet/address.go
wangjia 7cf87a764f feat(pay): Phase D 归集 —— 气隙签名 sweep(#34/34A)
动钱代码,按"联网建/广播 + 离线签"气隙流程,离线签名独立验签防篡改:
- wallet: DecodeTronAddress/TronAddressBodyHex(base58check 解码校验)、AddressFromMnemonic(离线校验用)。
- tron/sign: TxID(sha256 raw_data)、SignRawData(secp256k1 → R||S||recid 65B)、RecoverAddressBody。
- tron/abi: ABIEncodeTransferParams(transfer(address,uint256) 参数)、keccak 地址体。
- tron/tx(联网): BuildTransfer(triggersmartcontract 建未签名)、TRC20Balance、Broadcast。
- cmd/sweep: plan/build/sign/broadcast 四段;sign 对每笔独立验:①重算 txid 防篡改 ②收款人+额 ABI
  内嵌 ③USDT 合约内嵌 ④派生地址==owner,任一不符拒签;助记词只经 PAY_SWEEP_MNEMONIC(离线机,不入 arg)。
- 测试:签名可恢复到正确地址、ABI 编码、地址解码 roundtrip 全绿。
- 联网上链部分标注需 Phase E 真链验证;README 补 sweep 用法 + 验签说明 + gas 提醒。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 04:12:04 +08:00

40 lines
1.2 KiB
Go

package wallet
import (
"bytes"
"crypto/sha256"
"fmt"
"github.com/btcsuite/btcd/btcutil/base58"
)
// DecodeTronAddress decodes a base58check TRON address ("T...") to its 21-byte
// payload (0x41 || 20-byte body), validating the checksum. The 20-byte body
// (payload[1:]) is what TRON ABI parameters use (left-padded to 32 bytes).
func DecodeTronAddress(addr string) ([]byte, error) {
raw := base58.Decode(addr)
if len(raw) != 25 { // 21 payload + 4 checksum
return nil, fmt.Errorf("wallet: bad TRON address length %d", len(raw))
}
payload, sum := raw[:21], raw[21:]
h1 := sha256.Sum256(payload)
h2 := sha256.Sum256(h1[:])
if !bytes.Equal(h2[:4], sum) {
return nil, fmt.Errorf("wallet: bad TRON address checksum")
}
if payload[0] != tronAddrPrefix {
return nil, fmt.Errorf("wallet: bad TRON address prefix 0x%02x", payload[0])
}
return payload, nil
}
// TronAddressBodyHex returns the 20-byte address body as hex (no 0x41 prefix) —
// used to build/verify ABI-encoded transfer recipients.
func TronAddressBodyHex(addr string) (string, error) {
payload, err := DecodeTronAddress(addr)
if err != nil {
return "", err
}
return fmt.Sprintf("%x", payload[1:]), nil
}