diff --git a/.eslintrc.js b/.eslintrc.js index e1d8effd..bf57df18 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,13 +6,21 @@ module.exports = { extends: [ '@vue/airbnb', 'plugin:vue/recommended', - 'plugin:@typescript-eslint/recommended', 'plugin:import/typescript', + // 'prettier/@typescript-eslint', + 'plugin:@typescript-eslint/recommended', // "plugin:prettier/recommended", - // "prettier/@typescript-eslint" ], + parser: 'vue-eslint-parser', parserOptions: { - parser: '@babel/eslint-parser', + parser: '@typescript-eslint/parser', + ecmaVersion: 6, + sourceType: 'module', + ecmaFeatures: { + jsx: false, + modules: true, + experimentalObjectRestSpread: true, + }, }, rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', @@ -23,10 +31,12 @@ module.exports = { 'linebreak-style': 'off', // camelcase: ['error', { properties: 'never', ignoreDestructuring: true, ignoreImports: true }], 'arrow-parens': ['error', 'as-needed'], - 'vue/multiline-html-element-content-newline': 'off', + 'vue/new-line-between-multi-line-property': 0, + 'vue/multiline-html-element-content-newline': 0, 'vue/multi-word-component-names': 0, 'vue/no-mutating-props': 0, 'vue/v-slot-style': 0, + '@typescript-eslint/no-empty-function': 1, camelcase: 0, 'vuejs-accessibility/click-events-have-key-events': 'off', 'vuejs-accessibility/mouse-events-have-key-events': 'off', diff --git a/src/libs/client/PingWalletClient.ts b/src/libs/client/SigningEthermintClient.ts similarity index 67% rename from src/libs/client/PingWalletClient.ts rename to src/libs/client/SigningEthermintClient.ts index 49e74808..6fec4d8d 100644 --- a/src/libs/client/PingWalletClient.ts +++ b/src/libs/client/SigningEthermintClient.ts @@ -11,37 +11,22 @@ import { createIbcAminoConverters, createStakingAminoConverters, } from '@cosmjs/stargate' -import { - EncodeObject, TxBodyEncodeObject, makeAuthInfoBytes, -} from '@cosmjs/proto-signing' +import { EncodeObject } from '@cosmjs/proto-signing' import { LedgerSigner } from '@cosmjs/ledger-amino' import TransportWebUSB from '@ledgerhq/hw-transport-webusb' import TransportWebBLE from '@ledgerhq/hw-transport-web-ble' import { StdFee, } from '@cosmjs/amino' -import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx' import { generateMessageWithMultipleTransactions, generateTypes, generateFee, createEIP712, } from '@tharsis/eip712' -import { - createTxRawEIP712, signatureToWeb3Extension, Chain, -} from '@tharsis/transactions' -import { - createTransactionWithMultipleMessages, -} from '@tharsis/proto' -import { - fromBase64, fromBech32, fromHex, toBase64, -} from '@cosmjs/encoding' -// import { generateEndpointBroadcast, generatePostBodyBroadcast } from '@tharsis/provider' -import { SignMode } from 'cosmjs-types/cosmos/tx/signing/v1beta1/signing' -import * as eth from '@tharsis/proto/dist/proto/ethermint/crypto/v1/ethsecp256k1/keys' // /ethermint/crypto/v1/ethsecp256k1/keys' -import { PubKey } from 'cosmjs-types/cosmos/crypto/secp256k1/keys' -import { Int53 } from '@cosmjs/math' -import { Any } from 'cosmjs-types/google/protobuf/any' +import { createTxRawEIP712, signatureToWeb3Extension, Chain } from '@tharsis/transactions' +import { createTransactionWithMultipleMessages } from '@tharsis/proto' +import { fromBech32, toBase64 } from '@cosmjs/encoding' import EthereumLedgerSigner from './EthereumLedgerSigner' import { defaultMessageAdapter } from './MessageAdapter' @@ -152,52 +137,6 @@ export class SigningEthermintClient { return Promise.resolve(rawTx) } } -export function encodePubkey(pubkey: string): Any { -// const value = new eth.ethermint.crypto.v1.ethsecp256k1.PubKey({ key: fromBase64(pubkey) }) -// return Any.fromPartial({ -// typeUrl: '/ethermint.crypto.v1.ethsecp256k1.PubKey', -// value: value.serializeBinary(), -// }) - return Any.fromPartial({ - typeUrl: '/ethermint.crypto.v1.ethsecp256k1.PubKey', - value: PubKey.encode({ - key: fromBase64(pubkey), - }).finish(), - }) -} - -function makeRawTx(sender, messages, memo, fee, signature, registry): TxRaw { - const pubkey = encodePubkey(sender.pubkey) - - const signedTxBody = { - messages, - memo, - } - const signedTxBodyEncodeObject: TxBodyEncodeObject = { - typeUrl: '/cosmos.tx.v1beta1.TxBody', - value: signedTxBody, - } - const signedTxBodyBytes = registry.encode(signedTxBodyEncodeObject) - const signedGasLimit = Int53.fromString(fee.gas).toNumber() - // const signedSequence = sender.sequence - const signedAuthInfoBytes = makeAuthInfoBytes( - [{ pubkey, sequence: sender.sequence }], - fee.amount, - signedGasLimit, - SignMode.SIGN_MODE_LEGACY_AMINO_JSON, - ) - const rawTx = TxRaw.fromPartial({ - bodyBytes: signedTxBodyBytes, - authInfoBytes: signedAuthInfoBytes, - signatures: [fromHex(signature)], - }) - - return rawTx -} - -// export function createAnyMessage(messages: readonly EncodeObject[]) { -// return messages.map(x => x.) -// } export declare type SigningClient = SigningStargateClient | SigningEthermintClient; diff --git a/src/libs/client/SigningKeplrEthermintClient.ts b/src/libs/client/SigningKeplrEthermintClient.ts new file mode 100644 index 00000000..6c0682df --- /dev/null +++ b/src/libs/client/SigningKeplrEthermintClient.ts @@ -0,0 +1,59 @@ +import { fromBase64 } from '@cosmjs/encoding' +import { Int53 } from '@cosmjs/math' +import { + EncodeObject, makeAuthInfoBytes, makeSignDoc, OfflineSigner, +} from '@cosmjs/proto-signing' +import { + SignerData, SigningStargateClient, SigningStargateClientOptions, StdFee, +} from '@cosmjs/stargate' +import { PubKey } from 'cosmjs-types/cosmos/crypto/secp256k1/keys' +import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx' +import { Any } from 'cosmjs-types/google/protobuf/any' + +export default class SigningKeplerEthermintClient { + private signer + + private client + + static async offline(signer: OfflineSigner, options?: SigningStargateClientOptions): Promise { + const instance = new SigningKeplerEthermintClient() + instance.client = await SigningStargateClient.offline(signer, options) + instance.signer = signer + return Promise.resolve(instance) + } + + async sign(signerAddress: string, messages: readonly EncodeObject[], fee: StdFee, memo: string, explicitSignerData?: SignerData): Promise { + const account = await this.signer.getAccounts() + const acc = account.find(x => x.address === signerAddress) + if (!acc) { + throw new Error('The signer address dose not exsits in Ledger!') + } + // Custom typeUrl for EVMOS + const pubk = Any.fromPartial({ + typeUrl: '/ethermint.crypto.v1.ethsecp256k1.PubKey', + value: PubKey.encode({ + key: acc.pubkey, + }).finish(), + }) + + const txBodyEncodeObject = { + typeUrl: '/cosmos.tx.v1beta1.TxBody', + value: { + messages, + memo, + }, + } + const txBodyBytes = this.client.registry.encode(txBodyEncodeObject) + const gasLimit = Int53.fromString(fee.gas).toNumber() + const authInfoBytes = makeAuthInfoBytes([{ pubkey: pubk, sequence: explicitSignerData.sequence }], fee.amount, gasLimit) + const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, explicitSignerData.chainId, explicitSignerData.accountNumber) + const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc) + + // returns txBytes for broadcast + return Promise.resolve(TxRaw.encode({ + bodyBytes: signed.bodyBytes, + authInfoBytes: signed.authInfoBytes, + signatures: [fromBase64(signature.signature)], + }).finish()) + } +} diff --git a/src/libs/utils.js b/src/libs/utils.js index e8240e93..27c5bf96 100644 --- a/src/libs/utils.js +++ b/src/libs/utils.js @@ -20,8 +20,9 @@ import { $themeColors } from '@themeConfig' // import { SigningStargateClient } from '@cosmjs/stargate' // import PingWalletClient from './data/signing' import { SigningStargateClient } from '@cosmjs/stargate' -import { getSigningClient } from './client/PingWalletClient.ts' -import { EthereumLedgerSigner } from './client/EthereumLedgerSigner.ts' +import { getSigningClient } from './client/SigningEthermintClient.ts' +import EthereumLedgerSigner from './client/EthereumLedgerSigner.ts' +import SigningKeplerEthermintClient from './client/SigningKeplrEthermintClient' dayjs.extend(localeData) dayjs.extend(duration) @@ -231,6 +232,34 @@ function getHdPath(address) { return stringToPath(hdPath) } +function isEvmosBasedChain(chainId) { + const re = /[_]{1}[\d]{4}[\\-]{1}[\d]+$/g + return re.test(chainId) +} + +export async function sign(device, chainId, signerAddress, messages, fee, memo, signerData) { + const hdpath = getHdPath(signerAddress) + let client + if (device.startsWith('ledger')) { + client = await getSigningClient(device, hdpath) + } else { + if (!window.getOfflineSigner || !window.keplr) { + throw new Error('Please install keplr extension') + } + await window.keplr.enable(chainId) + const signer = window.getOfflineSigner(chainId) + if (isEvmosBasedChain(chainId)) { + client = await SigningKeplerEthermintClient.offline(signer) + } else { + client = await SigningStargateClient.offline(signer) + } + } + const coinType = Number(hdpath[1]) + const addr = device.startsWith('ledger') && coinType !== 60 ? toSignAddress(signerAddress) : signerAddress + return client.sign(addr, messages, fee, memo, signerData) +} + +// import address from ledger async function getLedgerAppName(coinType, device, hdpath) { let ledgerAppName = 'Cosmos' switch (coinType) { @@ -252,27 +281,6 @@ async function getLedgerAppName(coinType, device, hdpath) { return new LedgerSigner(transport, { hdPaths: [hdpath], ledgerAppName }) } -export async function sign(device, chainId, signerAddress, messages, fee, memo, signerData) { - const hdpath = getHdPath(signerAddress) - let client - if (device.startsWith('ledger')) { - client = await getSigningClient(device, hdpath) - } else { - if (!window.getOfflineSigner || !window.keplr) { - throw new Error('Please install keplr extension') - } - await window.keplr.enable(chainId) - const signer = window.getOfflineSignerOnlyAmino(chainId) - client = await SigningStargateClient.offline(signer) - } - // let transport - // let signer - // const hdpath = getHdPath(signerAddress) - const coinType = Number(hdpath[1]) - const addr = device.startsWith('ledger') && coinType !== 60 ? toSignAddress(signerAddress) : signerAddress - return client.sign(addr, messages, fee, memo, signerData) -} - export async function getLedgerAddress(transport = 'blu', hdPath = "m/44'/118/0'/0/0") { const protocol = transport === 'usb' ? await TransportWebUSB.create() : await TransportWebBLE.create() // extract Cointype from from HDPath @@ -280,6 +288,7 @@ export async function getLedgerAddress(transport = 'blu', hdPath = "m/44'/118/0' const signer = await getLedgerAppName(coinType, protocol, stringToPath(hdPath)) return signer.getAccounts() } +/// end import address from ledger export function toDuration(value) { return dayjs.duration(value).humanize() diff --git a/src/views/WalletAccountDetail.vue b/src/views/WalletAccountDetail.vue index 599fbbda..1a230a75 100644 --- a/src/views/WalletAccountDetail.vue +++ b/src/views/WalletAccountDetail.vue @@ -651,7 +651,7 @@ export default { }, created() { this.$http.getAuthAccount(this.address).then(acc => { - this.account = acc + this.account = acc.account this.initial() this.$http.getTxsBySender(this.address).then(res => { this.transactions = res