Skip to content

ADN-752: add Cosmos SIGN_MODE_DIRECT signing pipeline (Phase 4)#822

Open
HeesungB wants to merge 4 commits intofeature/ADN-751from
feature/ADN-752
Open

ADN-752: add Cosmos SIGN_MODE_DIRECT signing pipeline (Phase 4)#822
HeesungB wants to merge 4 commits intofeature/ADN-751from
feature/ADN-752

Conversation

@HeesungB
Copy link
Copy Markdown

Summary

Phase 4 of AtomOne multichain support. Adds SIGN_MODE_DIRECT
(proto-based) Cosmos signing alongside the Phase 3 AMINO pipeline (#821).
A dispatcher chooses the pipeline per chain based on
chain.signing.preferred; AtomOne is switched to prefer DIRECT, and
byte/signature parity with @cosmjs/proto-signing is enforced by tests.
The AMINO pipeline and Gno signing are untouched on the hot path.

adena-module

  • cosmos/direct/: new subtree — make-sign-doc.ts produces proto-encoded
    SignDoc with a compressed pubkey embedded in AuthInfo;
    sign-cosmos-direct.ts wires resolveAccount → makeDirectSignDoc → keyring.signRaw → TxRaw.encode using shared bodyBytes / authInfoBytes
    (byte-equal guarantee between signed SignDoc and broadcast payload)
  • cosmos/sign-cosmos.ts: new dispatcher — exhaustive switch on
    CosmosSignMode with a never compile-time guard for future modes
  • cosmos/signer-helpers.ts: resolveAccount (empty-string safe) and
    resolvePublicKey (HD / PrivateKey / Web3Auth / Ledger→Phase 7 /
    Multisig→permanent) extracted out of the AMINO pipeline and shared
  • cosmos/proto/make-tx-raw.ts: signMode: SignMode is now a required
    param with no default, so the mode written into modeInfo.single.mode
    always matches what was actually signed
  • cosmos/types.ts: SignedCosmosTx.signDoc widened to
    StdSignDoc | SignDoc; adds isAminoSignDoc / isDirectSignDoc
    type guards
  • chain-registry: CosmosChain.signing now { modes, preferred };
    AtomOne declares preferred: 'SIGN_MODE_DIRECT'; new
    ChainRegistry.getChainByChainId() lookup
  • wallet.ts: signCosmosByAccountId(accountId, document, provider, signMode)
    signMode is now required, delegates to the signCosmos dispatcher

adena-extension

  • TransactionService.signCosmos: resolves chain.signing.preferred via
    ChainRegistry.getChainByChainId(chainId) and threads it into
    wallet.signCosmosByAccountId

Tests

  • sign-cosmos-direct.spec.ts (new): SignDoc round-trip through cosmjs
    DirectSecp256k1Wallet, bit-equal signature parity with
    DirectSecp256k1Wallet.signDirect, GOLDEN vector (fixed mnemonic →
    known base64 TxRaw), provider fallback for missing
    accountNumber/sequence, Ledger / Multisig / AirGap error shapes
  • registry.spec.ts: getChainByChainId coverage for gno and atomone
  • make-tx-raw.spec.ts: updated for the explicit signMode param

Test plan

  • `cd packages/adena-module && npx jest` pass
  • `cd packages/adena-extension && npm test` pass
  • `npx tsc --noEmit` clean, `yarn build` green
  • Manual: send `PHOTON` / `ATONE` on AtomOne — tx appears on Mintscan
    (DIRECT is now the live path)
  • Manual: Gno GNOT / GRC20 transfer unchanged
  • Manual: Multisig × Cosmos — rejected with permanent-unsupport message
  • Manual: Ledger × Cosmos — rejected with Phase 7 message (both AMINO
    and DIRECT paths now surface the same error via signer-helpers)

Related

- makeTxRaw takes an explicit signMode: SignMode param so AMINO and the
  upcoming DIRECT pipeline share the same TxRaw builder. No default value —
  a wrong mode on the AuthInfo side silently invalidates the signature, so
  the choice is forced at every call site.
- Extract resolveAccount + resolvePublicKey from sign-cosmos-amino into a
  new signer-helpers module; DIRECT reuses the same account/pubkey logic
- Standardize the Ledger guard message to mention "(Phase 7)" so both
  signer-helpers and LedgerKeyring.signRaw agree on the forward-looking label
- AMINO GOLDEN unchanged — bit-for-bit identical txBytes
- SignedCosmosTx.signDoc becomes StdSignDoc | SignDoc so the DIRECT pipeline
  can return its proto SignDoc as-is for audit/reference without a separate
  result type
- Add isAminoSignDoc / isDirectSignDoc type guards — tests and any future
  dApp-injection consumer narrow via discriminator fields instead of
  instanceof
- No runtime change; only production consumers of .signDoc are specs,
  verified by grep across both packages
- makeDirectSignDoc builds TxBody/AuthInfo proto bytes with SIGN_MODE_DIRECT
  + pubkey, wraps into SignDoc, returns raw signBytes; the same
  bodyBytes/authInfoBytes are reused for the final TxRaw so the signed
  document matches the broadcast payload byte-for-byte
- signCosmosDirect mirrors the AMINO entry structure via the shared
  signer-helpers; Ledger keyrings are rejected in resolvePublicKey with
  the Phase 7 message
- signCosmos dispatcher switch-routes on CosmosSignMode; exhaustive check
  keeps any future mode addition compile-time visible
- sign-cosmos-direct.spec verifies SignDoc encoding round-trip, bit-equal
  against @cosmjs/proto-signing DirectSecp256k1Wallet signature, and a
  GOLDEN txBytes base64 vector
- Promote cosmjs-types (0.10.1) to a direct dependency now that SignDoc is
  imported from two sites; matches the version @cosmjs/proto-signing@0.36.0
  already pulls in transitively
- Export CosmosSignMode from chain-registry/types for cross-package use
- AdenaWallet.signCosmosByAccountId takes CosmosSignMode explicitly and
  delegates to the new cosmos/sign-cosmos dispatcher. The wallet layer
  stays free of chain-registry knowledge — the sign-mode decision lives
  one layer up in TransactionService
- TransactionService.signCosmos reads chain.signing.preferred via
  ChainRegistry.getChainByChainId and forwards it to the wallet. Missing
  or non-cosmos chain throws a clear error instead of silently falling
  back to AMINO
- wallet-sign.spec pins the Phase 3 AMINO GOLDEN by passing the mode
  explicitly, proving the new param is a pure additive signature change
- With ATOMONE_CHAIN.signing.preferred = 'SIGN_MODE_DIRECT', internal
  Cosmos send on AtomOne now signs with SIGN_MODE_DIRECT end-to-end.
  Ledger keyrings hit the Phase 7 guard inside signCosmosDirect until
  Phase 7 adds the AMINO-override path
@HeesungB HeesungB requested a review from a team as a code owner April 22, 2026 02:56
@HeesungB HeesungB requested review from dongwon8247 and jinoosss and removed request for a team April 22, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant