16 Commits
Author SHA1 Message Date
zeekay 1f84c0617f Pin past the versions the proxy can no longer serve
The bulk retag moved published tags. go.sum and sum.golang.org hold the
original bytes, proxy.golang.org answers not-found, and the direct fetch
disagrees, so builds stopped at a checksum before reaching a compiler.
Pin forward to versions the proxy still serves.
2026-09-01 12:20:56 -07:00
zeekayandHanzo Dev 4fa22a74c6 deps: zip v1.8.3 -> v1.18.22
The estate was spread across ten zip versions while the zipdoc/graft refactor
landed at v1.18.22. Measured before bumping: the API is additive across that
range -- 57 exported symbols at v1.17.2, 83 at v1.18.22, with exactly one
removal (`PluginStatus`), and no repo that pins zip references it.

Verified by building this module against the new version, not by assuming.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-01 20:25:27 -07:00
zeekay d807895a25 refactor(deps): use the canonical zip at github.com/zap-proto/zip
zap-proto/zip is the one zip. The hanzoai/zip fork is behind it and has no
unique surface left: canonical supersedes its closers with a context-aware
OnShutdown, keeps ZAPRegistry in the zaprpc subpackage, and exports the
primitives its App.Mount wrapped.
2026-07-26 11:34:26 -07:00
zeekay 844506b5bd go: 1.26.3 → 1.26.4 (security: crypto/x509, mime, net/textproto) 2026-06-06 22:04:27 -07:00
zeekay 0b5eff46fc merge: integrate TON broadcaster (#393)
Consolidates origin/z/bridgev2-ton-broadcast — final of the five chain
broadcaster branches. With TON wired, all six families (EVM, BTC, SOL,
DOT, XRP, TON) are now implemented end-to-end.

Conflicts resolved:
- internal/broadcast/client.go: TON case added alongside the existing
  five; ErrFamilyNotImplemented is now reserved for future families
- cmd/bridge/release_pool.go: dropped TON agent's separate Wallet field
  shape (ECDSAPubKey string + EDDSAPubKey string) in favor of the
  merged shape from earlier chains:
  * Wallet.ECDSAPubKey stays []byte (BTC's choice — XRP/DOT decode hex)
  * Wallet.EDDSAPubKeyHex added as hex string (TON's choice — uniform
    with the ed25519-only wallet families)
  ReleasePoolEntry now carries both ECDSAPubKey (hex) and EDDSAPubKey
  (hex), plus AddressType (mchain type — distinct from Family string)
- cmd/bridge/signing_driver.go: TON dispatch added to the family
  switch in signOne after the SOL+XRP branches but before the DOT/EVM
  assembler arm; threaded tonAssembler + tonUnsigned through the
  PreSign/MPC-sign/Finalize flow with TON-specific gas pre-check;
  lookupPoolEntry helper added for fetching the EDDSAPubKey alongside
  the address; tonAmountToNano + isTONNativeAsset utilities
- cmd/bridge/main.go: TON assembler wired through signer.SetTONAssembler
  alongside EVM/SOL/DOT; balance probe TON endpoints + API keys wired
  via networks.yaml + balanceProbe.TONBalanceURLs/TONAPIKeys
- cmd/bridge/balance_probe.go: TON branch added to BalanceAt switch
  (calls balanceAtTON via GET getAddressBalance); SOL kept in the
  dedicated branch; isLikelyNonEVMNetwork docstring updated to
  acknowledge SOL+TON are routed elsewhere
- internal/mchain/client.go: Wallet.ECDSAPubKey stays []byte; new
  EDDSAPubKeyHex string field for Ed25519 wallets (TON); pickAddress
  TON case derives v4r2 raw address from EDDSAPubKey when present,
  falls back to SOLAddress slot for legacy mpcd
- go.mod: added xssnick/tonutils-go + ed25519 dependency chain; took
  golang.org/x/crypto v0.51.0 + golang.org/x/sys v0.44.0 (TON's
  newer minimums)
- internal/broadcast/client_test.go: TestBroadcast_FamilyNotImplemented
  retired — every address type now has a concrete broadcaster
- Test refactors: ReleasePool tests use NewReleasePoolForFamily +
  PutEntry(family, idx, entry); FamilyTON constant added
2026-05-28 00:42:58 -07:00
zeekay da12749209 merge: integrate XRP broadcaster (#393)
Consolidates origin/z/bridgev2-xrp-broadcast. Conflicts resolved:
- internal/broadcast/client.go: XRP case added alongside EVM/BTC/SOL/DOT;
  ErrFamilyNotImplemented now lists only TON as pending
- cmd/bridge/release_pool.go: dropped XRP agent's PubKeyHex field +
  AcquireForFamily/SizeByFamily/Reload accessors that re-implemented
  family routing inside ReleasePool. Kept BTC's family-keyed store
  approach (LoadEntries(ctx, family)) as the single source of truth.
  XRP pubkey persistence rides on ReleasePoolEntry.ECDSAPubKey (hex
  string field added by DOT merge — XRP signing driver reads the same
  field for its SigningPubKey embedding). Added FamilyXRP constant.
- cmd/bridge/release_pool_set.go: added XRP slot to ReleasePoolSet +
  Size/FamilySizes/PoolFor/poolFor coverage
- cmd/bridge/signing_driver.go: XRP dispatch added before EVM/DOT
  assembler path; threaded poolEntry through both poolSet acquire and
  legacy fallback acquire so signOneXRP can read poolEntry.ECDSAPubKey
- cmd/bridge/main.go: XRP release pool wired through releasePoolSet.XRP
  via the same NewReleasePoolForFamily(store, FamilyXRP, …) shape as
  BTC/SOL/DOT — no more shared-store-with-different-indices hack
- internal/mchain/client.go: Wallet.ECDSAPubKey stays []byte (BTC's
  choice) — XRP consumers hex-encode when persisting. XRP r-address
  derivation runs in pickAddress when ECDSAPubKey present, falls back
  to ETHAddress otherwise (matches the merged-state shape-only tests)
- cmd/bridge/broadcast_driver.go: humanizeBroadcastErr merges BTC's
  txn-* rejections with XRP's tecINSUFFICIENT_FUNDS / tecUNFUNDED
- go.mod: added rubblelabs/ripple + bits-and-blooms/bitset to
  union of all branches' deps
- Test refactors: ECDSAPubKeyHex → ECDSAPubKey ([]byte); PutEntry takes
  family arg; XRP-specific tests using AcquireForFamily/SizeByFamily
  replaced with TestReleasePool_XRPFamily_BootstrapAndAcquire matching
  the BTC family-pool shape
2026-05-28 00:30:53 -07:00
zeekay 6aa0491351 merge: integrate SOL broadcaster (#393)
Consolidates origin/z/bridgev2-sol-broadcast. Conflicts resolved:
- internal/broadcast/client.go: keep BTC + SOL cases in family switch
- cmd/bridge/signing_driver.go: BTC dispatch first, then SOL branch
- cmd/bridge/main.go: BTC pool block + SOL pool block + multi-family
  router (releasePoolSet) that BOTH families register into
- go.mod/go.sum: union of dependencies, tidy applied
- Replaced SOL agent's NewInMemoryStoreFamily wrappers with BTC agent's
  family-scoped ReleasePoolStore (LoadEntries(ctx, family)) — single
  source of truth, no parallel wrappers
- release_pool_family_store.go: deleted (redundant with BTC design)
- FamilySOL constant added alongside FamilyEVM + FamilyBTC
2026-05-28 00:03:34 -07:00
zeekay 0e1ad73ace feat(mchain): BTC P2WPKH derivation from keygen ECDSAPubKey
Extend the MPC keygen client to surface the compressed secp256k1
public key alongside the chain-appropriate address, and derive a
bech32 P2WPKH locally for BITCOIN_* networks instead of relying on
mpcd's legacy P2PKH "1..." output.

Why: bridge release on BTC needs P2WPKH (witness-discount fees,
direct btcsuite/txscript compatibility, broader wallet support).
mpcd's pubKeyToBtcAddress emits Base58Check P2PKH; rather than
round-tripping a fix through mpcd, the bridge re-derives locally
from the same ECDSAPubKey the keygen already returns.

Changes:
- Wallet gains ECDSAPubKey []byte; 33-byte compressed form preferred,
  uncompressed (65/64) and x-only (32) inputs all compress canonically
- keygenResult parses both eth_address and evm_address (mpcd renamed)
- pickAddress() takes the network internal_name so BITCOIN_MAINNET vs
  BITCOIN_TESTNET selects the right bech32 hrp (bc / tb)
- new btc_address.go: deriveBTCBech32Address + compressSecp256k1Pubkey
  + bitcoinChainParams; uses btcd/btcutil for canonical HASH160 +
  segwit-v0 encoding
- 11 new tests covering mainnet/testnet hrp selection, 32/33/64/65
  byte pubkey shapes, empty/malformed input, keygen integration
2026-05-27 18:07:03 -07:00
zeekay 5c4ae63411 feat(xrpl): Payment codec + address derivation + DER low-s signature
Introduces internal/xrpl, the bridge's XRP Ledger primitives package:

- AddressFromPubKey / AccountIDFromPubKey: derive the canonical r-address
  from a 33-byte compressed-secp256k1 public key. Hash chain is
  RIPEMD160(SHA256(pubkey)), base58check-encoded with the XRPL alphabet
  + 0x00 version byte. Round-trips through the rubblelabs codec.
- PreSign(PaymentUnsigned) → (32-byte digest, *SignCtx): builds a native
  XRP Payment, embeds the signing pubkey on the wire, returns the
  SHA-512Half of (0x53545800 || serialized_body) — exactly the message
  the MPC quorum must sign.
- Finalize(DER, *SignCtx) → (signedBlob, txHash): attaches the DER
  signature to TxnSignature, returns the full wire-format binary blob
  (suitable for submit's tx_blob param as hex) and the canonical XRPL
  tx hash (SHA-512Half of 0x54584E00 || blob).
- EncodeDERSignature(r, s): ASN.1 DER encode (r, s) with low-s
  normalization (rejects high-s as XRPL's tfFullyCanonicalSig requires)
  and the 0x00 leading-byte rule for INTEGERs with the MSB set.
- CanonicalizeS / SHA512Half exposed for tests + future TrustSet path.

Uses github.com/rubblelabs/ripple for the deep binary codec — every
field-id, type-byte, and length-prefix detail is the library's
responsibility. The bridge owns only the signing flow on top, so MPC
ECDSA can stand in for the library's local-key Sign helper.

Tests cover: canonical pubkey → r-address round-trip, rejection of
bad pubkey lengths/prefixes, DER encoding of standard and high-bit
cases, low-s flip for s > N/2, validation that high-s gets canonicalized
in EncodeDERSignature, PreSign digest matching independent SHA512Half
recomputation, full PreSign → Finalize round-trip via the parser.
2026-05-27 17:54:07 -07:00
zeekay 73aaa949fb feat(bridge): TON broadcast + v4r2 wallet tx assembler
Add the wire-correct TON destination handler so the bridge can release
into TON_MAINNET / TON_TESTNET via TON Center.

internal/broadcast/ton.go:

- broadcastTON pushes a signed external-message BOC to TON Center's
  sendBoc endpoint (mainnet: toncenter.com/api/v2/sendBoc; testnet:
  testnet.toncenter.com/api/v2/sendBoc).
- X-API-Key header sourced per-network from Client.TONAPIKeys (set via
  SetTONAPIKey or populated by main.go from networks.yaml). Required
  at production rates — public gateway throttles to ~1 req/s.
- normalizeTONPayload accepts the hex shape the txassembler emits (to
  match the EVM raw-tx convention) and converts to base64 for the
  toncenter wire. Pre-base64 payloads pass through.
- parseTONResponse classifies error responses: 429 / "rate" →
  ErrTONRateLimited, "account not initialized" / "state_init" →
  ErrTONAccountNotInitialized, "invalid boc" / "wrong signature" →
  ErrTONMalformedBOC (fatal — signer must re-build), other 5xx /
  transport → TONError{Retryable: true}.
- Returns the in-message hash as BroadcastResult.TxHash. Callers
  resolve the on-chain tx hash later via getTransactions polling.

internal/txassembler/ton.go:

- Two-phase PreSign / Finalize parallel to the EVM path. PreSignTON
  builds the wallet-v4r2 unsigned body cell (subwallet || valid_until
  || seqno || op=0 || message_mode || ref_to_internal_msg) and
  surfaces its representation hash for the MPC Ed25519 quorum to
  sign. FinalizeTON / FinalizeTONHex re-assemble with the 64-byte
  signature, wrap in an external-in message (with state_init when
  SourceInitialized=false so first sends self-deploy), and emit BOC
  bytes (or base64) for the broadcast layer.
- Native TON transfer + jetton transfer (TRC-3 op=0x0f8a7ea5) under
  one spec. Jetton path resolves the source's jetton-wallet address
  off the master either via TONJettonWalletAddressProvider (live
  runMethod) or operator-supplied TONSpec.JettonSourceWallet. Forward
  TON convention 0.05 TON (50_000_000 nanoton) for gas — same
  amount the body itself carries to the master.
- Wallet v4r2 (= tonwallet.V4R2) + sub-wallet 698983191 (=
  tonwallet.DefaultSubwallet). messages_ttl=180s matches upstream.
- Address helpers: TONAddressFromPubKey (UQ), …Bounceable… (EQ),
  TONRawAddress ("<workchain>:<hex>"), ParseTONAddress (accepts any
  form). Exported so mchain.pickAddress can derive a real TON
  address from EDDSAPubKey once mpcd surfaces it, and so the
  deposit-watcher can match incoming-deposit addresses.

internal/broadcast/client.go:

- Add TONAPIKeys map on Client + AddressTypeTON dispatch case
  routing to broadcastTON. ErrFamilyNotImplemented message updated
  (BTC/SOL/XRP/DOT remain not implemented; EVM + TON are in).
2026-05-27 17:52:24 -07:00
zeekay 4dfb24878c feat(txassembler): SOL message build + signature finalize
Adds SOLAssembler — companion to the EVM Assembler — that constructs
Solana transactions for the bridge's destination-release flow:

  - PreSign: fetch a recent blockhash via JSON-RPC getLatestBlockhash,
    build a v0 message (one signer = the MPC release wallet as fee
    payer, one recipient, lamport amount), serialize the bytes to be
    signed. SPL token mode (when SourceMint is set) derives source +
    destination ATAs via solana.FindAssociatedTokenAddress and probes
    the destination ATA via getAccountInfo — if absent, the assembler
    prepends a CreateAssociatedTokenAccount instruction so the release
    wallet pays the ~2_039_280 lamport rent + creates the account.
  - Finalize: slot the 64-byte Ed25519 signature into Transaction
    .Signatures[0], serialize the full wire tx with MarshalBinary, and
    base64-encode for JSON-RPC sendTransaction (encoding:base64). The
    signature itself doubles as the canonical Solana "tx hash" — return
    it base58-encoded for SDK consumption.

Dependency: github.com/gagliardetto/solana-go v1.20.0 — the de facto
standard Go client. The assembler stays decoupled from the broader
*rpc.Client beyond GetLatestBlockhash + GetAccountInfo, so the
broadcast layer can use its own JSON-RPC endpoint.

Helpers:
  - LamportsFromFloat(amount, decimals): safe float → uint64 conversion
    with overflow protection. 9dp for native SOL; varies for SPL.
  - ParseSOLSignatureHex(s): decodes a 128-char hex string to a fixed
    [64]byte buffer — used by the signing driver when the dashboard
    returns the Ed25519 sig in hex form.
  - SOLDefaultBlockhashURL(network): canonical RPC URL per network.

Tests (sol_test.go) cover:
  - Native transfer happy path: instruction is system.Transfer at
    Account[0] = payer; round-trip of MessageBytes through
    Message.Unmarshal yields an identical message.
  - SPL transfer with destination ATA missing: 2 instructions
    (ata.Create, then token.Transfer), destination ATA correctly
    derived and probed.
  - SPL transfer with destination ATA present: only 1 instruction.
  - Finalize round-trip: rawTx parses back through solana-go's
    Transaction decoder with matching signature + payer + blockhash.
  - Error paths: unknown network, zero amount, malformed payer addr.
  - ParseSOLSignatureHex + LamportsFromFloat: corner cases.

Total: 12 SOL tests, all green.
2026-05-27 17:45:02 -07:00
zeekay 83f854f160 feat(mchain): per-curve keygen + sign — Ed25519 hint for SOL/TON/DOT
The lux-mpc cluster supports both ECDSA/secp256k1 and EdDSA/Ed25519
(FROST) keygens. The bridge previously hardcoded secp256k1 because
every active swap path was EVM/BTC. To wire Solana end-to-end we need
the cluster to mint an Ed25519 wallet and sign over raw Solana message
bytes — neither of which work under secp256k1.

Add a Curve type with two members (secp256k1, ed25519) and a
CurveFor(AddressType) mapping. Forward the curve hint on both the
keygen and dashboard /v1/mpc/sign request bodies; older daemons that
don't recognize the field fall back to their compile-time default
(secp256k1) — which produces an ECDSA-shaped signature the SOL
finalizer will reject with a clear error, so a deployment mismatch
fails fast instead of silently producing bad release txs.

SignForWallet and SignForWalletWithOrg stay on secp256k1 (default
behaviour preserved). The new SignForWalletOnCurve/OnCurveWithOrg
entry points let the signing driver pass an Ed25519 hint per swap.

Tests:
  - TestKeygen_SOL_SendsEd25519Curve: SOL keygen body has curve=ed25519
  - TestKeygen_ETH_SendsSecp256k1Curve: ETH stays on secp256k1
  - TestCurveFor: coverage across all six AddressTypes
2026-05-27 17:41:04 -07:00
venuswhispers b1241c9fda feat: added mpc sign option 2026-05-27 14:49:55 +02:00
venuswhispers 9a551a554a feat: base bridge functions like swap function has been set almost 2026-05-25 23:08:12 +02:00
zeekay 23083ff3a1 go.mod: bump go directive to 1.26.3 (security advisory) 2026-05-12 20:54:59 -07:00
zeekay da713de7c4 feat(bridge): unified Go binary — embedded SPA + native networks/tokens/limits, proxied swap/quote/rate
Mirrors the luxfi/explorer pattern: cmd/bridge/main.go embeds the SPA
build via go:embed and exposes /v1/bridge/* on a single port. Read paths
(networks, tokens, exchanges, limits) are answered natively from a YAML
config — no Postgres. MPC-heavy paths (quote, rate, swaps, explorer)
reverse-proxy to the legacy Node backend until the native port lands.

Image: cmd/bridge/Dockerfile produces ~25 MB distroless.
Config: cmd/bridge/networks.example.yaml.
Migration target: Hanzo Base (SQLite) + luxfi/mpc direct calls.
2026-05-05 21:24:03 -07:00