diff --git a/src/wallet/walletconnect/WalletConnectV2.ts b/src/wallet/walletconnect/WalletConnectV2.ts index bdcdb636..4b5ead14 100644 --- a/src/wallet/walletconnect/WalletConnectV2.ts +++ b/src/wallet/walletconnect/WalletConnectV2.ts @@ -183,7 +183,7 @@ export class WalletConnectV2 { public async signAmino( chainId: string, signerAddress: string, - stdSignDoc: StdSignDoc + stdSignDoc: StdSignDoc, ): Promise { const { signature, signed } = await this.request( chainId, @@ -202,7 +202,7 @@ export class WalletConnectV2 { public async signDirect( chainId: string, signerAddress: string, - signDoc: SignDoc + signDoc: SignDoc, ): Promise { const { signature, signed } = await this.request( chainId, @@ -264,7 +264,7 @@ export class WalletConnectV2 { } } - private async request(chainId: string, method: Method, params: unknown) { + protected async request(chainId: string, method: Method, params: unknown) { const session = localStorage.getItem(this.sessionStorageKey); if (!session || !this.signClient) { throw new Error("Session not found for " + chainId); diff --git a/src/wallet/walletconnect/WalletConnectV2Keplr.ts b/src/wallet/walletconnect/WalletConnectV2Keplr.ts new file mode 100644 index 00000000..6be0c9af --- /dev/null +++ b/src/wallet/walletconnect/WalletConnectV2Keplr.ts @@ -0,0 +1,96 @@ +import { SignDoc, StdSignDoc } from "cosmes/registry"; + +import { MobileAppDetails } from "./QRCodeModal"; +import { WalletConnectV2 } from "./WalletConnectV2"; + +/** + * The data returned by the `cosmos_signAmino` method. `signed` is optional + * because some wallets (like Cosmostation) may not return it. + */ +type WcSignAminoResponse = { + signature: { + signature: string; + }; + signed?: StdSignDoc | undefined; +}; +type SignAminoResponse = Required; + +/** + * The data returned by the `cosmos_signDirect` method. `signed` is optional + * because some wallets (like Cosmostation) may not return it. + */ +type WcSignDirectResponse = { + signature: { + signature: string; + }; + signed?: SignDoc | undefined; +}; +type SignDirectResponse = Required; + +const Method = { + GET_ACCOUNTS: "cosmos_getAccounts", + SIGN_AMINO: "cosmos_signAmino", + SIGN_DIRECT: "cosmos_signDirect", +} as const; +type Method = (typeof Method)[keyof typeof Method]; + +export interface SignOptions { + readonly preferNoSetFee?: boolean; + readonly preferNoSetMemo?: boolean; + readonly disableBalanceCheck?: boolean; +} + +export class WalletConnectV2Keplr extends WalletConnectV2 { + defaultOptions: { + sign: { preferNoSetFee: boolean; preferNoSetMemo: boolean }; + }; + + constructor(projectId: string, mobileAppDetails: MobileAppDetails) { + super(projectId, mobileAppDetails); + this.defaultOptions = { + sign: { preferNoSetFee: true, preferNoSetMemo: true }, + }; + } + + public async signAminoKeplr( + chainId: string, + signerAddress: string, + stdSignDoc: StdSignDoc, + signOptions: SignOptions, + ): Promise { + const { signature, signed } = await this.request( + chainId, + Method.SIGN_AMINO, + { + signerAddress, + signDoc: stdSignDoc, + signOptions: signOptions, + } + ); + return { + signature: signature, + signed: signed ?? stdSignDoc, // simply return the original sign doc if `signed` is not returned + }; + } + + public async signDirectKeplr( + chainId: string, + signerAddress: string, + signDoc: SignDoc, + signOptions: SignOptions, + ): Promise { + const { signature, signed } = await this.request( + chainId, + Method.SIGN_DIRECT, + { + signerAddress, + signDoc, + signOptions:signOptions + } + ); + return { + signature: signature, + signed: signed ?? signDoc, // simply return the original sign doc if `signed` is not returned + }; + } +} diff --git a/src/wallet/wallets/cosmostation/CosmostationController.ts b/src/wallet/wallets/cosmostation/CosmostationController.ts index 8c2ab6c9..d7ad99a6 100644 --- a/src/wallet/wallets/cosmostation/CosmostationController.ts +++ b/src/wallet/wallets/cosmostation/CosmostationController.ts @@ -4,19 +4,19 @@ import { base64 } from "cosmes/codec"; import { WalletName } from "../../constants/WalletName"; import { WalletType } from "../../constants/WalletType"; import { onWindowEvent } from "../../utils/window"; -import { WalletConnectV2 } from "../../walletconnect/WalletConnectV2"; import { ConnectedWallet } from "../ConnectedWallet"; import { ChainInfo, WalletController } from "../WalletController"; import { WalletError } from "../WalletError"; import { CosmostationExtension } from "./CosmostationExtension"; import { CosmostationWalletConnectV2 } from "./CosmostationWalletConnectV2"; +import { WalletConnectV2Keplr } from "../../walletconnect/WalletConnectV2Keplr"; export class CosmostationController extends WalletController { - private readonly wc: WalletConnectV2; + private readonly wc: WalletConnectV2Keplr; constructor(wcProjectId: string) { super(WalletName.COSMOSTATION); - this.wc = new WalletConnectV2(wcProjectId, { + this.wc = new WalletConnectV2Keplr(wcProjectId, { // https://github.com/cosmostation/cosmostation-wc-modal/blob/main/src/modal.tsx#L22-L34 name: "Cosmostation", android: diff --git a/src/wallet/wallets/keplr/KeplrController.ts b/src/wallet/wallets/keplr/KeplrController.ts index 7d80b021..c8948a64 100644 --- a/src/wallet/wallets/keplr/KeplrController.ts +++ b/src/wallet/wallets/keplr/KeplrController.ts @@ -4,19 +4,19 @@ import { base64 } from "cosmes/codec"; import { WalletName } from "../../constants/WalletName"; import { WalletType } from "../../constants/WalletType"; import { onWindowEvent } from "../../utils/window"; -import { WalletConnectV2 } from "../../walletconnect/WalletConnectV2"; import { ConnectedWallet } from "../ConnectedWallet"; import { ChainInfo, WalletController } from "../WalletController"; import { WalletError } from "../WalletError"; import { KeplrExtension } from "./KeplrExtension"; import { KeplrWalletConnectV2 } from "./KeplrWalletConnectV2"; +import { WalletConnectV2Keplr } from "cosmes/wallet/walletconnect/WalletConnectV2Keplr"; export class KeplrController extends WalletController { - private readonly wc: WalletConnectV2; + private readonly wc: WalletConnectV2Keplr; constructor(wcProjectId: string) { super(WalletName.KEPLR); - this.wc = new WalletConnectV2(wcProjectId, { + this.wc = new WalletConnectV2Keplr(wcProjectId, { // https://github.com/chainapsis/keplr-wallet/blob/master/packages/wc-qrcode-modal/src/modal.tsx#L61-L75 name: "Keplr", android: diff --git a/src/wallet/wallets/keplr/KeplrWalletConnectV2.ts b/src/wallet/wallets/keplr/KeplrWalletConnectV2.ts index a8fc564d..8fbf4531 100644 --- a/src/wallet/wallets/keplr/KeplrWalletConnectV2.ts +++ b/src/wallet/wallets/keplr/KeplrWalletConnectV2.ts @@ -13,20 +13,20 @@ import { } from "cosmes/protobufs"; import { WalletError, WalletName, WalletType } from "cosmes/wallet"; -import { WalletConnectV2 } from "../../walletconnect/WalletConnectV2"; import { ConnectedWallet, SignArbitraryResponse, UnsignedTx, } from "../ConnectedWallet"; +import { WalletConnectV2Keplr } from "../../walletconnect/WalletConnectV2Keplr"; export class KeplrWalletConnectV2 extends ConnectedWallet { - private readonly wc: WalletConnectV2; + private readonly wc: WalletConnectV2Keplr; private readonly useAmino: boolean; constructor( walletName: WalletName, - wc: WalletConnectV2, + wc: WalletConnectV2Keplr, chainId: string, pubKey: Secp256k1PubKey, address: string, @@ -72,15 +72,20 @@ export class KeplrWalletConnectV2 extends ConnectedWallet { memo, timeoutHeight, }; + const signOptions = { + preferNoSetFee: true, + preferNoSetMemo: true, + }; + let txRaw: TxRaw; if (this.useAmino) { const { signed, signature } = await WalletError.wrap( - this.wc.signAmino(this.chainId, this.address, tx.toStdSignDoc(params)) + this.wc.signAminoKeplr(this.chainId, this.address, tx.toStdSignDoc(params), signOptions) ); txRaw = tx.toSignedAmino(signed, signature.signature); } else { const { signed, signature } = await WalletError.wrap( - this.wc.signDirect(this.chainId, this.address, tx.toSignDoc(params)) + this.wc.signDirectKeplr(this.chainId, this.address, tx.toSignDoc(params), signOptions) ); txRaw = tx.toSignedDirect(signed, signature.signature); } diff --git a/src/wallet/wallets/leap/LeapController.ts b/src/wallet/wallets/leap/LeapController.ts index 855855a2..b2e2e894 100644 --- a/src/wallet/wallets/leap/LeapController.ts +++ b/src/wallet/wallets/leap/LeapController.ts @@ -4,19 +4,19 @@ import { base64 } from "cosmes/codec"; import { WalletName } from "../../constants/WalletName"; import { WalletType } from "../../constants/WalletType"; import { onWindowEvent } from "../../utils/window"; -import { WalletConnectV2 } from "../../walletconnect/WalletConnectV2"; import { ConnectedWallet } from "../ConnectedWallet"; import { ChainInfo, WalletController } from "../WalletController"; import { WalletError } from "../WalletError"; import { LeapExtension } from "./LeapExtension"; import { LeapWalletConnectV2 } from "./LeapWalletConnectV2"; +import { WalletConnectV2Keplr } from "../../walletconnect/WalletConnectV2Keplr"; export class LeapController extends WalletController { - private readonly wc: WalletConnectV2; + private readonly wc: WalletConnectV2Keplr; constructor(wcProjectId: string) { super(WalletName.LEAP); - this.wc = new WalletConnectV2(wcProjectId, { + this.wc = new WalletConnectV2Keplr(wcProjectId, { name: "Leap", android: "leapcosmos://wcV2#Intent;package=io.leapwallet.cosmos;scheme=leapwallet;end;",