Repository navigation
feat: add SignArbitrary and ADR-036 signature verification - #45
Conversation
notJoon
left a comment
There was a problem hiding this comment.
LGTM overall, I left some suggestions and feel free to apply them. thank you!
aronpark1007
left a comment
There was a problem hiding this comment.
Verified the fix in ac7132d. The supplied document must now match the rebuilt canonical sign bytes, and all five originally reported tampering cases are rejected while retaining the original signature. The regression tests cover these cases.
Verification on this revision: all 146 tests across 38 suites pass; lint, tsc --noEmit, and build pass. A separate smoke run through the built SDK with GnoWalletProvider confirmed that normal and BOM-prefixed messages verify, and all five document mutations fail both with and without expected fields.
No additional blocking findings from the review. Resolving my canonical-document verification thread and approving.
Summary
Adds
SignArbitrarysupport to the SDK, matching thewindow.adena.SignArbitraryAPI on the latest adena-walletmain, plus a shared ADR-036 signature verifier usable by any dApp or backend.Changes
signArbitraryAdenaSDK.signArbitrary({ signer, data })method,WalletProvider.signArbitrary, andsignArbitrarymethod helper.AdenaWalletProvider: forwards towindow.adena.SignArbitrary. ReturnsUNSUPPORTED_TYPEwhen the installed extension predates the API (SignArbitraryis typed as optional onAdenaWallet).GnoWalletProvider(andGnoSocialWalletProvider): signs locally with the TM2 wallet signer, binding the current network's chain id. Mirrors the extension's rules:INVALID_FORMATfor empty or >4096-byte data,ACCOUNT_MISMATCHfor a signer other than the wallet address.SIGN_ARBITRARYtoWalletResponseSuccessType/WalletResponseExecuteTypeandWalletMessageInfo. Without the success entry,mapResponseByAdenaResponsethrows on the extension'sSIGN_ARBITRARYsuccess response. This also unblocks the wallet-side TODOs waiting for the SDK to ship this entry.ADR-036 verification utilities (
core/utils/arbitrary.utils.ts)verifyArbitrarySignature(proof, { signer?, chainId?, data? })resolvestrueonly if:/tm.PubKeySecp256k1and derives the signer address (bech32 prefix taken from the signer),(chainId, signer, data)(any extra message, non-zero fee/sequence, or memo fails),It never throws; malformed input resolves to
false.parseArbitrarySignDoc,makeArbitrarySignDoc,getArbitrarySignBytesare exported as well.Works with standard Cosmos ADR-036 proofs (
chainId: ''), not only Adena's chain-bound variant.Types
ARBITRARY_MSG_TYPE,MAX_ARBITRARY_MESSAGE_BYTES,ArbitraryMessage,ArbitrarySignature,SignedArbitraryData,SignArbitraryOptions,SignArbitraryResponse.SignArbitraryParams/AdenaSignArbitrary; the raw response is re-exported asAdenaSignArbitraryResponsefollowing the existing disambiguation pattern insrc/index.ts.Dependencies
@cosmjs/amino,@cosmjs/crypto,@cosmjs/encodingat0.39.0as direct dependencies. They are the same versions@gnolang/tm2-js-clientalready pulls in.Docs
signArbitraryand the ADR-036 verification helpers in both the root and package READMEs, including replay-protection guidance (pinsigner,chainId, and a nonce-bearingdata).Notes
chain_idinstead of'', so a proof cannot be replayed across networks. The SDK follows the wallet's format.fromBech32is called with an explicit BIP-173 limit (90): the defaultInfinityis rejected by the@scure/baseversion bundled with@cosmjs/encoding@0.39.0.Testing
arbitrary.utils.test.ts:@cosmjs/aminoserializeSignDocsign-arbitrary.test.ts: method delegation for success, failure, reject, and throw.gno-wallet-sign-arbitrary.test.ts: the local provider produces verifiable proofs, plus theACCOUNT_MISMATCH,INVALID_FORMAT, andNOT_CONNECTEDpaths.adena-sign-arbitrary.test.ts: maps the extension's response shape, passes failures through, and returnsUNSUPPORTED_TYPEon older extensions.yarn test(139 passed),yarn lint,yarn build,tsc --noEmitall pass.