From 3db310b620cb534cee848cb4cdba92884bfdaa4b Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 2 Nov 2023 00:50:34 +0100 Subject: [PATCH 01/42] fix(react): :wrench: fix types export --- packages/react/package.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index a884006b..3525b24d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -20,11 +20,6 @@ "react": "18.2.0" }, "main": "./index.js", - "types": "./index.d.ts", - "exports": { - ".": { - "import": "./index.mjs", - "require": "./index.js" - } - } + "module": "./index.mjs", + "typings": "./index.d.ts" } From 0aa97349f82f576eb1b2eb8469e434c9e8c9c343 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 2 Nov 2023 12:35:34 +0100 Subject: [PATCH 02/42] feat(store): :sparkles: add getChain util --- packages/store/src/slices/config.ts | 3 +++ packages/store/src/types/config.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/packages/store/src/slices/config.ts b/packages/store/src/slices/config.ts index d7c5fd52..14bc5cc1 100644 --- a/packages/store/src/slices/config.ts +++ b/packages/store/src/slices/config.ts @@ -3,6 +3,7 @@ import type { StateCreator } from 'zustand/vanilla'; export const createConfigSlice: StateCreator = ( set, + get, ) => ({ wallets: [], chains: [], @@ -10,4 +11,6 @@ export const createConfigSlice: StateCreator = ( setChains: (chains) => set(() => ({ chains })), setAssetsLists: (assetsLists) => set(() => ({ assetsLists })), setWallets: (wallets) => set(() => ({ wallets })), + getChain: (chainName) => + get().chains.find((chain) => chain.chain_name === chainName), }); diff --git a/packages/store/src/types/config.ts b/packages/store/src/types/config.ts index eaf29ddb..5095096c 100644 --- a/packages/store/src/types/config.ts +++ b/packages/store/src/types/config.ts @@ -5,6 +5,7 @@ export interface ConfigState { wallets: Wallet[]; chains: Chain[]; assetsLists: AssetLists[]; + getChain: (chainName: string) => Chain | undefined; setChains: (chains: Chain[]) => void; setAssetsLists: (assetsLists: AssetLists[]) => void; setWallets: (wallets: Wallet[]) => void; From 75d4046928bc04ded29f2cc2add4964cdc827d33 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 2 Nov 2023 12:35:57 +0100 Subject: [PATCH 03/42] feat(react): :sparkles: add useChain hook --- packages/react/src/hooks/chain.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/react/src/hooks/chain.tsx b/packages/react/src/hooks/chain.tsx index 05a157e6..24e72865 100644 --- a/packages/react/src/hooks/chain.tsx +++ b/packages/react/src/hooks/chain.tsx @@ -1,3 +1,4 @@ +import { assertIsDefined } from '@quirks/core'; import { useQuirks } from '../providers'; export const useChains = () => { @@ -5,5 +6,23 @@ export const useChains = () => { return { accounts: store.use.accounts(), + accountName: store.use.accountName ? store.use.accountName() : undefined, + getAddresses: store.use.getAddresses(), + getAddress: store.use.getAddress(), + getChain: store.use.getChain(), + }; +}; + +export const useChain = (chainName: string) => { + const { getChain, getAddress, accountName } = useChains(); + + const chain = getChain(chainName); + + assertIsDefined(chain, `there is no chain named "${chainName}"`); + + return { + chain, + address: getAddress(chain.chain_id), + accountName, }; }; From 8997373a36154dda2fd7144b82a7544b9f45670d Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 2 Nov 2023 12:36:09 +0100 Subject: [PATCH 04/42] docs(examples-nextjs): :memo: update example --- examples/nextjs/app/page.tsx | 6 ++---- examples/nextjs/components/button.tsx | 5 ++--- examples/nextjs/components/test-chain.tsx | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 examples/nextjs/components/test-chain.tsx diff --git a/examples/nextjs/app/page.tsx b/examples/nextjs/app/page.tsx index 72a8b0b1..e448afbd 100644 --- a/examples/nextjs/app/page.tsx +++ b/examples/nextjs/app/page.tsx @@ -1,14 +1,12 @@ -import { osmosis, osmosisAssetList } from '@nabla-studio/chain-registry'; +import { TestChain } from '../components/test-chain'; import { Button } from '../components/button'; import { Test } from '../components/test'; export default async function Index() { return (
- {osmosis.chain_name} - {osmosisAssetList.chain_name} - +
); diff --git a/examples/nextjs/components/button.tsx b/examples/nextjs/components/button.tsx index 65365514..60b04dcd 100644 --- a/examples/nextjs/components/button.tsx +++ b/examples/nextjs/components/button.tsx @@ -20,9 +20,8 @@ export const Button = () => { {wallet.options.prettyName} diff --git a/examples/nextjs/components/test-chain.tsx b/examples/nextjs/components/test-chain.tsx new file mode 100644 index 00000000..f7c15eab --- /dev/null +++ b/examples/nextjs/components/test-chain.tsx @@ -0,0 +1,22 @@ +'use client'; + +import { useChain, useConnect } from '@quirks/react'; + +export const TestChain = () => { + const { connected } = useConnect(); + const { address, chain } = useChain('osmosis'); + + if (!connected) { + return false; + } + + return ( +
+
Chain ID: {chain.chain_id}
+ +
Chain Name: Osmosis
+ +
Address: {address}
+
+ ); +}; From 2886bc85e891042e42786aac80372f4ff6ce7987 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 2 Nov 2023 22:55:25 +0100 Subject: [PATCH 05/42] feat(store): :sparkles: add store reset on disconnect --- packages/store/src/slices/account.ts | 12 ++++++++---- packages/store/src/slices/config.ts | 14 +++++++++----- packages/store/src/slices/connect.ts | 22 ++++++++++++---------- packages/store/src/store.ts | 13 +++++++++++++ packages/store/src/types/account.ts | 5 +++++ packages/store/src/types/config.ts | 5 +++++ packages/store/src/types/connect.ts | 5 +++++ packages/store/src/types/store.ts | 12 ++++++++---- 8 files changed, 65 insertions(+), 23 deletions(-) diff --git a/packages/store/src/slices/account.ts b/packages/store/src/slices/account.ts index e80af2fa..36a17dab 100644 --- a/packages/store/src/slices/account.ts +++ b/packages/store/src/slices/account.ts @@ -1,14 +1,18 @@ -import type { AppState, AccountState } from '../types'; +import type { AppState, AccountSlice, AccountState } from '../types'; import type { StateCreator } from 'zustand/vanilla'; +export const accountInitialState: AccountState = { + accountName: undefined, + accounts: [], +}; + export const createAccountSlice: StateCreator< AppState, [], [], - AccountState + AccountSlice > = (_, get) => ({ - accountName: undefined, - accounts: [], + ...accountInitialState, getAddress: (chainId) => get().accounts.find((account) => account.chainId === chainId) ?.bech32Address, diff --git a/packages/store/src/slices/config.ts b/packages/store/src/slices/config.ts index 14bc5cc1..f8751d5e 100644 --- a/packages/store/src/slices/config.ts +++ b/packages/store/src/slices/config.ts @@ -1,13 +1,17 @@ -import type { ConfigState, AppState } from '../types'; +import type { ConfigSlice, AppState, ConfigState } from '../types'; import type { StateCreator } from 'zustand/vanilla'; -export const createConfigSlice: StateCreator = ( - set, - get, -) => ({ +export const configInitialState: ConfigState = { wallets: [], chains: [], assetsLists: [], +}; + +export const createConfigSlice: StateCreator = ( + set, + get, +) => ({ + ...configInitialState, setChains: (chains) => set(() => ({ chains })), setAssetsLists: (assetsLists) => set(() => ({ assetsLists })), setWallets: (wallets) => set(() => ({ wallets })), diff --git a/packages/store/src/slices/connect.ts b/packages/store/src/slices/connect.ts index 21dcb4e1..0b81904b 100644 --- a/packages/store/src/slices/connect.ts +++ b/packages/store/src/slices/connect.ts @@ -2,22 +2,27 @@ import { assertIsDefined, createInvalidWalletName } from '@quirks/core'; import { ConnectionStates, type AppState, - type ConnectState, + type ConnectSlice, AddressWithChain, ReconnectionStates, + type ConnectState, } from '../types'; import type { StateCreator } from 'zustand/vanilla'; +export const connectInitialState: ConnectState = { + walletName: undefined, + wallet: undefined, + status: ConnectionStates.DISCONNECTED, + reconnectionStatus: ReconnectionStates.IDLE, +}; + export const createConnectSlice: StateCreator< AppState, [], [], - ConnectState + ConnectSlice > = (set, get) => ({ - walletName: undefined, - wallet: undefined, - status: ConnectionStates.DISCONNECTED, - reconnectionStatus: ReconnectionStates.IDLE, + ...connectInitialState, setWallet: async (wallet) => { set(() => ({ wallet })); @@ -118,9 +123,6 @@ export const createConnectSlice: StateCreator< get().wallet?.removeListeners(); - set(() => ({ - walletName: undefined, - status: ConnectionStates.DISCONNECTED, - })); + get().reset(); }, }); diff --git a/packages/store/src/store.ts b/packages/store/src/store.ts index 1d12842c..967b567a 100644 --- a/packages/store/src/store.ts +++ b/packages/store/src/store.ts @@ -5,8 +5,11 @@ import { persist, } from 'zustand/middleware'; import { + configInitialState, createConfigSlice, + connectInitialState, createConnectSlice, + accountInitialState, createAccountSlice, } from './slices'; import { createSSRStorage } from './utils'; @@ -73,6 +76,16 @@ export const createConfig = (config: Config) => { assetsLists, ...createConnectSlice(...props), ...createAccountSlice(...props), + reset: () => { + props[0]({ + ...configInitialState, + ...connectInitialState, + ...accountInitialState, + wallets, + chains, + assetsLists, + }); + }, }), persistOptions, ), diff --git a/packages/store/src/types/account.ts b/packages/store/src/types/account.ts index 6fceb181..9f2112f3 100644 --- a/packages/store/src/types/account.ts +++ b/packages/store/src/types/account.ts @@ -8,6 +8,11 @@ export interface AddressWithChain extends Key { export interface AccountState { accountName?: string; accounts: AddressWithChain[]; +} + +export interface AccountActions { getAddress: (chainId: string) => string | undefined; getAddresses: (chainIds: string[]) => string[]; } + +export type AccountSlice = AccountState & AccountActions; diff --git a/packages/store/src/types/config.ts b/packages/store/src/types/config.ts index 5095096c..d828aa6d 100644 --- a/packages/store/src/types/config.ts +++ b/packages/store/src/types/config.ts @@ -5,8 +5,13 @@ export interface ConfigState { wallets: Wallet[]; chains: Chain[]; assetsLists: AssetLists[]; +} + +export interface ConfigActions { getChain: (chainName: string) => Chain | undefined; setChains: (chains: Chain[]) => void; setAssetsLists: (assetsLists: AssetLists[]) => void; setWallets: (wallets: Wallet[]) => void; } + +export type ConfigSlice = ConfigState & ConfigActions; diff --git a/packages/store/src/types/connect.ts b/packages/store/src/types/connect.ts index 8ee62773..81b2463c 100644 --- a/packages/store/src/types/connect.ts +++ b/packages/store/src/types/connect.ts @@ -25,9 +25,14 @@ export interface ConnectState { wallet?: Wallet; status: ConnectionState; reconnectionStatus: ReconnectionState; +} + +export interface ConnectActions { setWallet: (wallet?: Wallet) => void; getWalletData: () => void; connect: (walletName: string) => void; reconnect: (walletName: string) => void; disconnect: () => void; } + +export type ConnectSlice = ConnectState & ConnectActions; diff --git a/packages/store/src/types/store.ts b/packages/store/src/types/store.ts index ba51fbc9..efe4c2e0 100644 --- a/packages/store/src/types/store.ts +++ b/packages/store/src/types/store.ts @@ -1,5 +1,9 @@ -import { AccountState } from './account'; -import { ConfigState } from './config'; -import { ConnectState } from './connect'; +import { AccountSlice } from './account'; +import { ConfigSlice } from './config'; +import { ConnectSlice } from './connect'; -export type AppState = ConfigState & ConnectState & AccountState; +export interface AppActions { + reset: () => void; +} + +export type AppState = ConfigSlice & ConnectSlice & AccountSlice & AppActions; From 2ff2f6dd1f25c2b2c6bee24eec42239862b8b3f5 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 16:38:06 +0100 Subject: [PATCH 06/42] feat(store): :sparkles: add sign slice --- packages/store/src/slices/index.ts | 1 + packages/store/src/slices/sign.ts | 61 ++++++++++++++++++++++++++++++ packages/store/src/store.ts | 31 ++++++++++++++- packages/store/src/types/index.ts | 1 + packages/store/src/types/sign.ts | 35 +++++++++++++++++ packages/store/src/types/store.ts | 7 +++- 6 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 packages/store/src/slices/sign.ts create mode 100644 packages/store/src/types/sign.ts diff --git a/packages/store/src/slices/index.ts b/packages/store/src/slices/index.ts index 4e66bba8..c74f5177 100644 --- a/packages/store/src/slices/index.ts +++ b/packages/store/src/slices/index.ts @@ -1,3 +1,4 @@ export * from './connect'; export * from './config'; export * from './account'; +export * from './sign'; diff --git a/packages/store/src/slices/sign.ts b/packages/store/src/slices/sign.ts new file mode 100644 index 00000000..76ae4751 --- /dev/null +++ b/packages/store/src/slices/sign.ts @@ -0,0 +1,61 @@ +import { assertIsDefined } from '@quirks/core'; +import type { AppState, SignSlice, SignState } from '../types'; +import type { StateCreator } from 'zustand/vanilla'; + +export const signInitialState: SignState = { + signOptions: { + preferNoSetFee: false, + preferNoSetMemo: true, + disableBalanceCheck: true, + }, +}; + +export const createSignSlice: StateCreator = ( + _, + get, +) => ({ + ...signInitialState, + getOfflineSigner: (chainId) => { + assertIsDefined(get().wallet); + + return get().wallet!.getOfflineSigner(chainId, get().signOptions); + }, + getOfflineSignerOnlyAmino: (chainId) => { + assertIsDefined(get().wallet); + + return get().wallet!.getOfflineSignerOnlyAmino(chainId, get().signOptions); + }, + getOfflineSignerAuto: (chainId) => { + assertIsDefined(get().wallet); + + return get().wallet!.getOfflineSignerAuto(chainId, get().signOptions); + }, + signAmino: (chainId, signDoc) => { + assertIsDefined(get().wallet); + + const address = get().getAddress(chainId); + + assertIsDefined(address); + + return get().wallet!.signAmino( + chainId, + address, + signDoc, + get().signOptions, + ); + }, + signDirect: (chainId, signDoc) => { + assertIsDefined(get().wallet); + + const address = get().getAddress(chainId); + + assertIsDefined(address); + + return get().wallet!.signDirect( + chainId, + address, + signDoc, + get().signOptions, + ); + }, +}); diff --git a/packages/store/src/store.ts b/packages/store/src/store.ts index 967b567a..f48b2192 100644 --- a/packages/store/src/store.ts +++ b/packages/store/src/store.ts @@ -11,10 +11,12 @@ import { createConnectSlice, accountInitialState, createAccountSlice, + signInitialState, + createSignSlice, } from './slices'; import { createSSRStorage } from './utils'; import { createStore } from 'zustand/vanilla'; -import type { Wallet } from '@quirks/core'; +import type { SignOptions, Wallet } from '@quirks/core'; import type { AssetLists, Chain } from '@nabla-studio/chain-registry'; import type { AppState } from './types'; @@ -28,8 +30,22 @@ export interface Config { persistOptions?: PersistOptions; /** * Reinit connection on mount + * + * @default true */ autoConnect?: boolean; + /** + * Specify custom sign option + * + * @default + * + * { + * preferNoSetFee: false, + * preferNoSetMemo: true, + * disableBalanceCheck: true, + * } + */ + signOptions?: SignOptions; } const excludedKeys: (keyof AppState)[] = [ @@ -64,8 +80,18 @@ export const createConfig = (config: Config) => { assetsLists, autoConnect = true, persistOptions = defaultPersistOptions, + signOptions, } = config; + const signOverrideOptions = signOptions + ? signOptions + : signInitialState.signOptions; + + const signOverrideInitialState = { + ...signInitialState, + signOptions: signOverrideOptions, + }; + const store = createStore( subscribeWithSelector( persist( @@ -76,11 +102,14 @@ export const createConfig = (config: Config) => { assetsLists, ...createConnectSlice(...props), ...createAccountSlice(...props), + ...createSignSlice(...props), + signOverrideOptions, reset: () => { props[0]({ ...configInitialState, ...connectInitialState, ...accountInitialState, + ...signOverrideInitialState, wallets, chains, assetsLists, diff --git a/packages/store/src/types/index.ts b/packages/store/src/types/index.ts index 741d90b9..6987a013 100644 --- a/packages/store/src/types/index.ts +++ b/packages/store/src/types/index.ts @@ -2,3 +2,4 @@ export * from './config'; export * from './store'; export * from './connect'; export * from './account'; +export * from './sign'; diff --git a/packages/store/src/types/sign.ts b/packages/store/src/types/sign.ts new file mode 100644 index 00000000..c3de20d5 --- /dev/null +++ b/packages/store/src/types/sign.ts @@ -0,0 +1,35 @@ +import type { + AminoSignResponse, + OfflineAminoSigner, + StdSignDoc, +} from '@cosmjs/amino'; +import type { + DirectSignResponse, + OfflineDirectSigner, +} from '@cosmjs/proto-signing'; +import type { SignOptions } from '@quirks/core'; +import type { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; + +export interface SignState { + signOptions: SignOptions; +} + +export interface SignActions { + getOfflineSigner: ( + chainId: string, + ) => Promise; + getOfflineSignerOnlyAmino: (chainId: string) => Promise; + getOfflineSignerAuto: ( + chainId: string, + ) => Promise; + signAmino: ( + chainId: string, + signDoc: StdSignDoc, + ) => Promise; + signDirect: ( + chainId: string, + signDoc: SignDoc, + ) => Promise; +} + +export type SignSlice = SignState & SignActions; diff --git a/packages/store/src/types/store.ts b/packages/store/src/types/store.ts index efe4c2e0..f8c786ea 100644 --- a/packages/store/src/types/store.ts +++ b/packages/store/src/types/store.ts @@ -1,3 +1,4 @@ +import { SignSlice } from './sign'; import { AccountSlice } from './account'; import { ConfigSlice } from './config'; import { ConnectSlice } from './connect'; @@ -6,4 +7,8 @@ export interface AppActions { reset: () => void; } -export type AppState = ConfigSlice & ConnectSlice & AccountSlice & AppActions; +export type AppState = ConfigSlice & + ConnectSlice & + AccountSlice & + SignSlice & + AppActions; From 286c8f9d08a775847ca1673525cc61adbad56b2e Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 16:39:22 +0100 Subject: [PATCH 07/42] chore(store): :wrench: add peer deps --- packages/store/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/store/package.json b/packages/store/package.json index b5afc8fe..68c6cbf0 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -18,7 +18,10 @@ "@quirks/core": "*" }, "peerDependencies": { - "zustand": "^4.4.4" + "zustand": "^4.4.4", + "@cosmjs/amino": "^0.31.3", + "@cosmjs/proto-signing": "^0.31.3", + "cosmjs-types": "^0.9.0" }, "main": "./index.js", "module": "./index.mjs", From 6f8fc7ee06631449c7acad7e2b6920024675c684 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 16:40:06 +0100 Subject: [PATCH 08/42] chore(react): :wrench: add package deps --- packages/react/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react/package.json b/packages/react/package.json index 3525b24d..a686a5d4 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -14,7 +14,8 @@ "version": "0.2.0", "sideEffects": false, "dependencies": { - "@quirks/store": "*" + "@quirks/store": "*", + "@quirks/core": "*" }, "peerDependencies": { "react": "18.2.0" From da0cd779e86ff5bdefabdc1099e8a5dfded674f3 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 17:06:30 +0100 Subject: [PATCH 09/42] feat(core): :sparkles: add sign and verify arbitrary --- packages/core/src/wallet.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/core/src/wallet.ts b/packages/core/src/wallet.ts index dde01a3a..fc274aa6 100644 --- a/packages/core/src/wallet.ts +++ b/packages/core/src/wallet.ts @@ -7,6 +7,7 @@ import type { AminoSignResponse, OfflineAminoSigner, StdSignDoc, + StdSignature, } from '@cosmjs/amino'; import type { SignOptions, @@ -90,6 +91,19 @@ export abstract class Wallet { signOptions?: SignOptions, ): Promise; + abstract signArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + ): Promise; + + abstract verifyArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + signature: StdSignature, + ): Promise; + /** * Asks the user to add a tokens to the wallet */ From f94d830301a4ee6a52b4786e6a53359120de1231 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 17:07:19 +0100 Subject: [PATCH 10/42] feat(wallets): :sparkles: implement arbitrary keplr implemented sign and verify arbitrary for keplr. --- packages/wallets/src/keplr/extension.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/wallets/src/keplr/extension.ts b/packages/wallets/src/keplr/extension.ts index 9ab80709..f86e90dc 100644 --- a/packages/wallets/src/keplr/extension.ts +++ b/packages/wallets/src/keplr/extension.ts @@ -2,6 +2,7 @@ import type { OfflineAminoSigner, StdSignDoc, AminoSignResponse, + StdSignature, } from '@cosmjs/amino'; import type { OfflineDirectSigner, @@ -116,6 +117,27 @@ export class KeplrWalletExtension extends ExtensionWallet { ); } + override signArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + ): Promise { + assertIsDefined(this.client); + + return this.client.signArbitrary(chainId, signer, data); + } + + override verifyArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + signature: StdSignature, + ): Promise { + assertIsDefined(this.client); + + return this.client.verifyArbitrary(chainId, signer, data, signature); + } + override async suggestTokens(suggestions: SuggestToken[]): Promise { assertIsDefined(this.client); From ecc805f0dec32a179fc166e594db526be8b228f3 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 17:07:39 +0100 Subject: [PATCH 11/42] feat(wallets): :sparkles: implement arbitrary leap implemented sign and verify arbitrary for leap. --- packages/wallets/src/leap/extension.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/wallets/src/leap/extension.ts b/packages/wallets/src/leap/extension.ts index b9487199..cdc7e6a5 100644 --- a/packages/wallets/src/leap/extension.ts +++ b/packages/wallets/src/leap/extension.ts @@ -2,6 +2,7 @@ import type { OfflineAminoSigner, StdSignDoc, AminoSignResponse, + StdSignature, } from '@cosmjs/amino'; import type { OfflineDirectSigner, @@ -120,6 +121,27 @@ export class LeapWalletExtension extends ExtensionWallet { ); } + override signArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + ): Promise { + assertIsDefined(this.client); + + return this.client.signArbitrary(chainId, signer, data); + } + + override verifyArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + signature: StdSignature, + ): Promise { + assertIsDefined(this.client); + + return this.client.verifyArbitrary(chainId, signer, data, signature); + } + override async suggestTokens(suggestions: SuggestToken[]): Promise { assertIsDefined(this.client); From 4fbab45842ef426464bbde7d23abb5554c67d150 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 18:36:18 +0100 Subject: [PATCH 12/42] refactor(react): :recycle: refactor useChain hook --- packages/react/src/hooks/chain.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react/src/hooks/chain.tsx b/packages/react/src/hooks/chain.tsx index 24e72865..8f1e4e76 100644 --- a/packages/react/src/hooks/chain.tsx +++ b/packages/react/src/hooks/chain.tsx @@ -14,15 +14,15 @@ export const useChains = () => { }; export const useChain = (chainName: string) => { - const { getChain, getAddress, accountName } = useChains(); + const store = useQuirks(); - const chain = getChain(chainName); + const chain = store.use.getChain()(chainName); assertIsDefined(chain, `there is no chain named "${chainName}"`); return { chain, - address: getAddress(chain.chain_id), - accountName, + address: store.use.getAddress()(chain.chain_id), + accountName: store.use.accountName ? store.use.accountName() : undefined, }; }; From 20cf8748415b8dfb16a21365dad20caf452f5ea1 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 3 Nov 2023 20:43:57 +0100 Subject: [PATCH 13/42] feat(react): :sparkles: add sign utils inside useChain --- packages/react/src/hooks/chain.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/react/src/hooks/chain.tsx b/packages/react/src/hooks/chain.tsx index 8f1e4e76..1f682c61 100644 --- a/packages/react/src/hooks/chain.tsx +++ b/packages/react/src/hooks/chain.tsx @@ -1,5 +1,7 @@ import { assertIsDefined } from '@quirks/core'; import { useQuirks } from '../providers'; +import type { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; +import type { StdSignDoc } from '@cosmjs/amino'; export const useChains = () => { const store = useQuirks(); @@ -24,5 +26,14 @@ export const useChain = (chainName: string) => { chain, address: store.use.getAddress()(chain.chain_id), accountName: store.use.accountName ? store.use.accountName() : undefined, + getOfflineSigner: () => store.use.getOfflineSigner()(chain.chain_id), + getOfflineSignerOnlyAmino: () => + store.use.getOfflineSignerOnlyAmino()(chain.chain_id), + getOfflineSignerAuto: () => + store.use.getOfflineSignerAuto()(chain.chain_id), + signAmino: (signDoc: StdSignDoc) => + store.use.signAmino()(chain.chain_id, signDoc), + signDirect: (signDoc: SignDoc) => + store.use.signDirect()(chain.chain_id, signDoc), }; }; From f6ec538adb3f0746cab72b24dd5e326a400f2ccc Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 11:15:16 +0100 Subject: [PATCH 14/42] chore(react): :wrench: add peer deps --- packages/react/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react/package.json b/packages/react/package.json index a686a5d4..f0062f70 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -18,7 +18,9 @@ "@quirks/core": "*" }, "peerDependencies": { - "react": "18.2.0" + "react": "18.2.0", + "cosmjs-types": "^0.9.0", + "@cosmjs/amino": "^0.31.3" }, "main": "./index.js", "module": "./index.mjs", From 259ec86d1da062b0d368d6b43f2e9ef910f499be Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 11:47:33 +0100 Subject: [PATCH 15/42] feat: :heavy_plus_sign: add @cosmjs/stargate deps --- package.json | 2 + pnpm-lock.yaml | 155 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 145 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index df2d797b..d9c579ac 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,9 @@ }, "dependencies": { "@cosmjs/amino": "^0.31.3", + "@cosmjs/cosmwasm-stargate": "^0.31.3", "@cosmjs/proto-signing": "^0.31.3", + "@cosmjs/stargate": "^0.31.3", "@keplr-wallet/cosmos": "^0.12.38", "cosmjs-types": "^0.9.0", "eventemitter3": "^5.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bfc1a582..a6e5f486 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,15 @@ dependencies: '@cosmjs/amino': specifier: ^0.31.3 version: 0.31.3 + '@cosmjs/cosmwasm-stargate': + specifier: ^0.31.3 + version: 0.31.3 '@cosmjs/proto-signing': specifier: ^0.31.3 version: 0.31.3 + '@cosmjs/stargate': + specifier: ^0.31.3 + version: 0.31.3 '@keplr-wallet/cosmos': specifier: ^0.12.38 version: 0.12.38 @@ -1722,6 +1728,13 @@ packages: chalk: 4.1.2 dev: true + /@confio/ics23@0.6.8: + resolution: {integrity: sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==} + dependencies: + '@noble/hashes': 1.3.2 + protobufjs: 6.11.4 + dev: false + /@cosmjs/amino@0.31.3: resolution: {integrity: sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==} dependencies: @@ -1731,6 +1744,26 @@ packages: '@cosmjs/utils': 0.31.3 dev: false + /@cosmjs/cosmwasm-stargate@0.31.3: + resolution: {integrity: sha512-Uv9TmCn3650gdFeZm7SEfUZF3uX3lfJfFhXOk6I2ZLr/FrKximnlb+vwAfZaZnWYvlA7qrKtHIjeRNHvT23zcw==} + dependencies: + '@cosmjs/amino': 0.31.3 + '@cosmjs/crypto': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/proto-signing': 0.31.3 + '@cosmjs/stargate': 0.31.3 + '@cosmjs/tendermint-rpc': 0.31.3 + '@cosmjs/utils': 0.31.3 + cosmjs-types: 0.8.0 + long: 4.0.0 + pako: 2.1.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: false + /@cosmjs/crypto@0.31.3: resolution: {integrity: sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==} dependencies: @@ -1751,6 +1784,13 @@ packages: readonly-date: 1.0.0 dev: false + /@cosmjs/json-rpc@0.31.3: + resolution: {integrity: sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg==} + dependencies: + '@cosmjs/stream': 0.31.3 + xstream: 11.14.0 + dev: false + /@cosmjs/math@0.31.3: resolution: {integrity: sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==} dependencies: @@ -1769,6 +1809,64 @@ packages: long: 4.0.0 dev: false + /@cosmjs/socket@0.31.3: + resolution: {integrity: sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==} + dependencies: + '@cosmjs/stream': 0.31.3 + isomorphic-ws: 4.0.1(ws@7.5.9) + ws: 7.5.9 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@cosmjs/stargate@0.31.3: + resolution: {integrity: sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw==} + dependencies: + '@confio/ics23': 0.6.8 + '@cosmjs/amino': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/proto-signing': 0.31.3 + '@cosmjs/stream': 0.31.3 + '@cosmjs/tendermint-rpc': 0.31.3 + '@cosmjs/utils': 0.31.3 + cosmjs-types: 0.8.0 + long: 4.0.0 + protobufjs: 6.11.4 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: false + + /@cosmjs/stream@0.31.3: + resolution: {integrity: sha512-8keYyI7X0RjsLyVcZuBeNjSv5FA4IHwbFKx7H60NHFXszN8/MvXL6aZbNIvxtcIHHsW7K9QSQos26eoEWlAd+w==} + dependencies: + xstream: 11.14.0 + dev: false + + /@cosmjs/tendermint-rpc@0.31.3: + resolution: {integrity: sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g==} + dependencies: + '@cosmjs/crypto': 0.31.3 + '@cosmjs/encoding': 0.31.3 + '@cosmjs/json-rpc': 0.31.3 + '@cosmjs/math': 0.31.3 + '@cosmjs/socket': 0.31.3 + '@cosmjs/stream': 0.31.3 + '@cosmjs/utils': 0.31.3 + axios: 0.21.4 + readonly-date: 1.0.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: false + /@cosmjs/utils@0.31.3: resolution: {integrity: sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==} dev: false @@ -5028,6 +5126,14 @@ packages: engines: {node: '>=4'} dev: true + /axios@0.21.4: + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + dependencies: + follow-redirects: 1.15.3 + transitivePeerDependencies: + - debug + dev: false + /axios@1.5.1: resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} dependencies: @@ -6259,7 +6365,6 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.1 - dev: true /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} @@ -6273,7 +6378,6 @@ packages: define-data-property: 1.1.1 has-property-descriptors: 1.0.1 object-keys: 1.1.1 - dev: true /delay@4.4.1: resolution: {integrity: sha512-aL3AhqtfhOlT/3ai6sWXeqwnw63ATNpnUiN4HL7x9q+My5QtHlO3OIkasmug9LKzpheLdmUKGRKnYXYAS7FQkQ==} @@ -7335,7 +7439,6 @@ packages: peerDependenciesMeta: debug: optional: true - dev: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -7419,7 +7522,6 @@ packages: /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true /function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} @@ -7455,7 +7557,6 @@ packages: has-proto: 1.0.1 has-symbols: 1.0.3 hasown: 2.0.0 - dev: true /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} @@ -7653,7 +7754,6 @@ packages: engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 - dev: true /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} @@ -7683,7 +7783,6 @@ packages: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.2 - dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -7745,17 +7844,14 @@ packages: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} dependencies: get-intrinsic: 1.2.2 - dev: true /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} - dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - dev: true /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} @@ -7790,7 +7886,6 @@ packages: engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 - dev: true /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} @@ -8291,6 +8386,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /isomorphic-ws@4.0.1(ws@7.5.9): + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + dependencies: + ws: 7.5.9 + dev: false + /isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} dev: true @@ -9940,7 +10043,6 @@ packages: /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - dev: true /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} @@ -10143,6 +10245,10 @@ packages: engines: {node: '>=6'} dev: true + /pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + dev: false + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -11427,6 +11533,11 @@ packages: picocolors: 1.0.0 dev: true + /symbol-observable@2.0.3: + resolution: {integrity: sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==} + engines: {node: '>=0.10'} + dev: false + /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true @@ -12649,6 +12760,19 @@ packages: signal-exit: 3.0.7 dev: true + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /ws@8.14.2: resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} engines: {node: '>=10.0.0'} @@ -12671,6 +12795,13 @@ packages: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true + /xstream@11.14.0: + resolution: {integrity: sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==} + dependencies: + globalthis: 1.0.3 + symbol-observable: 2.0.3 + dev: false + /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} From c23cdf6775f492a7797176216eb72eb7a4991c96 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 11:47:55 +0100 Subject: [PATCH 16/42] feat(core): :sparkles: add estimateFee utility --- packages/core/package.json | 2 ++ packages/core/src/index.ts | 1 + packages/core/src/sign/fee.ts | 26 ++++++++++++++++++++++++++ packages/core/src/sign/index.ts | 1 + packages/core/vite.config.ts | 2 ++ 5 files changed, 32 insertions(+) create mode 100644 packages/core/src/sign/fee.ts create mode 100644 packages/core/src/sign/index.ts diff --git a/packages/core/package.json b/packages/core/package.json index ec899cc2..906a01af 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -17,6 +17,8 @@ "@nabla-studio/chain-registry": "*" }, "peerDependencies": { + "@cosmjs/stargate": "^0.31.3", + "@cosmjs/cosmwasm-stargate": "^0.31.3", "@cosmjs/proto-signing": "^0.31.3", "cosmjs-types": "^0.9.0", "@cosmjs/amino": "^0.31.3", diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 4d921420..d0b5a5f6 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,3 +2,4 @@ export * from './wallet'; export * from './ext-wallet'; export * from './types'; export * from './utils'; +export * from './sign'; diff --git a/packages/core/src/sign/fee.ts b/packages/core/src/sign/fee.ts new file mode 100644 index 00000000..d76917a8 --- /dev/null +++ b/packages/core/src/sign/fee.ts @@ -0,0 +1,26 @@ +import type { EncodeObject } from '@cosmjs/proto-signing'; +import { + calculateFee, + type GasPrice, + SigningStargateClient, +} from '@cosmjs/stargate'; +import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; +import { assertIsDefined } from '../utils'; + +export const estimateFee = async ( + client: SigningStargateClient | SigningCosmWasmClient, + sender: string, + messages: EncodeObject[], + gasPrice?: string | GasPrice, + memo?: string, + multiplier = 1.3, +) => { + assertIsDefined( + gasPrice, + 'Gas price must be set in the client options when auto gas is used.', + ); + + const gasEstimation = await client.simulate(sender, messages, memo); + + return calculateFee(Math.round(gasEstimation * multiplier), gasPrice); +}; diff --git a/packages/core/src/sign/index.ts b/packages/core/src/sign/index.ts new file mode 100644 index 00000000..98e0ae5e --- /dev/null +++ b/packages/core/src/sign/index.ts @@ -0,0 +1 @@ +export * from './fee'; diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts index 7bf67cfb..2f8666f9 100644 --- a/packages/core/vite.config.ts +++ b/packages/core/vite.config.ts @@ -38,6 +38,8 @@ export default defineConfig({ 'cosmjs-types', '@cosmjs/proto-signing', '@cosmjs/amino', + '@cosmjs/stargate', + '@cosmjs/cosmwasm-stargate', 'eventemitter3', ], }, From cee77f744fe7f3702160e8fa288fa35bff457bb7 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 12:04:30 +0100 Subject: [PATCH 17/42] refactor(core): :recycle: move estimateFee to utils dir --- packages/core/src/index.ts | 1 - packages/core/src/sign/index.ts | 1 - packages/core/src/types/fees.ts | 9 +++++++++ packages/core/src/types/index.ts | 1 + packages/core/src/{sign/fee.ts => utils/fees.ts} | 12 ++++-------- packages/core/src/utils/index.ts | 1 + packages/core/vite.config.ts | 1 - 7 files changed, 15 insertions(+), 11 deletions(-) delete mode 100644 packages/core/src/sign/index.ts create mode 100644 packages/core/src/types/fees.ts rename packages/core/src/{sign/fee.ts => utils/fees.ts} (64%) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index d0b5a5f6..4d921420 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,4 +2,3 @@ export * from './wallet'; export * from './ext-wallet'; export * from './types'; export * from './utils'; -export * from './sign'; diff --git a/packages/core/src/sign/index.ts b/packages/core/src/sign/index.ts deleted file mode 100644 index 98e0ae5e..00000000 --- a/packages/core/src/sign/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './fee'; diff --git a/packages/core/src/types/fees.ts b/packages/core/src/types/fees.ts new file mode 100644 index 00000000..8df4b8fe --- /dev/null +++ b/packages/core/src/types/fees.ts @@ -0,0 +1,9 @@ +import type { EncodeObject } from '@cosmjs/proto-signing'; + +export interface SigningSimulatorClient { + simulate( + signerAddress: string, + messages: readonly EncodeObject[], + memo: string | undefined, + ): Promise; +} diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index 42e9a356..769032a7 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -2,3 +2,4 @@ export * from './suggest-tokens'; export * from './suggest-chains'; export * from './wallet'; export * from './account'; +export * from './fees'; diff --git a/packages/core/src/sign/fee.ts b/packages/core/src/utils/fees.ts similarity index 64% rename from packages/core/src/sign/fee.ts rename to packages/core/src/utils/fees.ts index d76917a8..d4add236 100644 --- a/packages/core/src/sign/fee.ts +++ b/packages/core/src/utils/fees.ts @@ -1,14 +1,10 @@ import type { EncodeObject } from '@cosmjs/proto-signing'; -import { - calculateFee, - type GasPrice, - SigningStargateClient, -} from '@cosmjs/stargate'; -import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; -import { assertIsDefined } from '../utils'; +import { calculateFee, type GasPrice } from '@cosmjs/stargate'; +import { assertIsDefined } from './asserts'; +import type { SigningSimulatorClient } from '../types'; export const estimateFee = async ( - client: SigningStargateClient | SigningCosmWasmClient, + client: SigningSimulatorClient, sender: string, messages: EncodeObject[], gasPrice?: string | GasPrice, diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 8b948c6c..0bb17cba 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,3 +1,4 @@ export * from './extension'; export * from './asserts'; export * from './errors'; +export * from './fees'; diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts index 2f8666f9..a3821be1 100644 --- a/packages/core/vite.config.ts +++ b/packages/core/vite.config.ts @@ -39,7 +39,6 @@ export default defineConfig({ '@cosmjs/proto-signing', '@cosmjs/amino', '@cosmjs/stargate', - '@cosmjs/cosmwasm-stargate', 'eventemitter3', ], }, From 23e92512cae767c339c8f876b478cc33ea9e100e Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 12:40:09 +0100 Subject: [PATCH 18/42] feat: :heavy_plus_sign: add cosmjs missing deps added utf-8-validate and bufferutil. --- package.json | 2 ++ pnpm-lock.yaml | 73 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index d9c579ac..c6200de9 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@cosmjs/proto-signing": "^0.31.3", "@cosmjs/stargate": "^0.31.3", "@keplr-wallet/cosmos": "^0.12.38", + "bufferutil": "^4.0.8", "cosmjs-types": "^0.9.0", "eventemitter3": "^5.0.1", "long": "^5.2.3", @@ -86,6 +87,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "semver": "^7.5.4", + "utf-8-validate": "^6.0.3", "zustand": "^4.4.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6e5f486..7eeca875 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,16 +13,19 @@ dependencies: version: 0.31.3 '@cosmjs/cosmwasm-stargate': specifier: ^0.31.3 - version: 0.31.3 + version: 0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@cosmjs/proto-signing': specifier: ^0.31.3 version: 0.31.3 '@cosmjs/stargate': specifier: ^0.31.3 - version: 0.31.3 + version: 0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@keplr-wallet/cosmos': specifier: ^0.12.38 version: 0.12.38 + bufferutil: + specifier: ^4.0.8 + version: 4.0.8 cosmjs-types: specifier: ^0.9.0 version: 0.9.0 @@ -44,6 +47,9 @@ dependencies: semver: specifier: ^7.5.4 version: 7.5.4 + utf-8-validate: + specifier: ^6.0.3 + version: 6.0.3 zustand: specifier: ^4.4.4 version: 4.4.4(@types/react@18.2.31)(react@18.2.0) @@ -171,10 +177,10 @@ devDependencies: version: 29.7.0(@types/node@20.8.8)(ts-node@10.9.1) jest-environment-jsdom: specifier: ^29.7.0 - version: 29.7.0 + version: 29.7.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) jsdom: specifier: ^22.1.0 - version: 22.1.0 + version: 22.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) json-schema-to-typescript: specifier: ^13.1.1 version: 13.1.1 @@ -1744,7 +1750,7 @@ packages: '@cosmjs/utils': 0.31.3 dev: false - /@cosmjs/cosmwasm-stargate@0.31.3: + /@cosmjs/cosmwasm-stargate@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-Uv9TmCn3650gdFeZm7SEfUZF3uX3lfJfFhXOk6I2ZLr/FrKximnlb+vwAfZaZnWYvlA7qrKtHIjeRNHvT23zcw==} dependencies: '@cosmjs/amino': 0.31.3 @@ -1752,8 +1758,8 @@ packages: '@cosmjs/encoding': 0.31.3 '@cosmjs/math': 0.31.3 '@cosmjs/proto-signing': 0.31.3 - '@cosmjs/stargate': 0.31.3 - '@cosmjs/tendermint-rpc': 0.31.3 + '@cosmjs/stargate': 0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@cosmjs/tendermint-rpc': 0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@cosmjs/utils': 0.31.3 cosmjs-types: 0.8.0 long: 4.0.0 @@ -1809,19 +1815,19 @@ packages: long: 4.0.0 dev: false - /@cosmjs/socket@0.31.3: + /@cosmjs/socket@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==} dependencies: '@cosmjs/stream': 0.31.3 isomorphic-ws: 4.0.1(ws@7.5.9) - ws: 7.5.9 + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) xstream: 11.14.0 transitivePeerDependencies: - bufferutil - utf-8-validate dev: false - /@cosmjs/stargate@0.31.3: + /@cosmjs/stargate@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw==} dependencies: '@confio/ics23': 0.6.8 @@ -1830,7 +1836,7 @@ packages: '@cosmjs/math': 0.31.3 '@cosmjs/proto-signing': 0.31.3 '@cosmjs/stream': 0.31.3 - '@cosmjs/tendermint-rpc': 0.31.3 + '@cosmjs/tendermint-rpc': 0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@cosmjs/utils': 0.31.3 cosmjs-types: 0.8.0 long: 4.0.0 @@ -1848,14 +1854,14 @@ packages: xstream: 11.14.0 dev: false - /@cosmjs/tendermint-rpc@0.31.3: + /@cosmjs/tendermint-rpc@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g==} dependencies: '@cosmjs/crypto': 0.31.3 '@cosmjs/encoding': 0.31.3 '@cosmjs/json-rpc': 0.31.3 '@cosmjs/math': 0.31.3 - '@cosmjs/socket': 0.31.3 + '@cosmjs/socket': 0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@cosmjs/stream': 0.31.3 '@cosmjs/utils': 0.31.3 axios: 0.21.4 @@ -5482,6 +5488,13 @@ packages: base64-js: 1.5.1 ieee754: 1.2.1 + /bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.6.1 + /builtins@5.0.1: resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} dependencies: @@ -8391,7 +8404,7 @@ packages: peerDependencies: ws: '*' dependencies: - ws: 7.5.9 + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) dev: false /isstream@0.1.2: @@ -8622,7 +8635,7 @@ packages: pretty-format: 29.7.0 dev: true - /jest-environment-jsdom@29.7.0: + /jest-environment-jsdom@29.7.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -8638,7 +8651,7 @@ packages: '@types/node': 20.8.8 jest-mock: 29.7.0 jest-util: 29.7.0 - jsdom: 20.0.3 + jsdom: 20.0.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - supports-color @@ -8960,7 +8973,7 @@ packages: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} dev: true - /jsdom@20.0.3: + /jsdom@20.0.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} engines: {node: '>=14'} peerDependencies: @@ -8993,7 +9006,7 @@ packages: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.14.2 + ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -9001,7 +9014,7 @@ packages: - utf-8-validate dev: true - /jsdom@22.1.0: + /jsdom@22.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==} engines: {node: '>=16'} peerDependencies: @@ -9031,7 +9044,7 @@ packages: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 12.0.1 - ws: 8.14.2 + ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -9889,7 +9902,6 @@ packages: /node-gyp-build@4.6.1: resolution: {integrity: sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==} hasBin: true - dev: true /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -12197,6 +12209,13 @@ packages: react: 18.2.0 dev: false + /utf-8-validate@6.0.3: + resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.6.1 + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -12477,7 +12496,7 @@ packages: cac: 6.7.14 chai: 4.3.10 debug: 4.3.4 - jsdom: 22.1.0 + jsdom: 22.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) local-pkg: 0.4.3 magic-string: 0.30.5 pathe: 1.1.1 @@ -12760,7 +12779,7 @@ packages: signal-exit: 3.0.7 dev: true - /ws@7.5.9: + /ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} engines: {node: '>=8.3.0'} peerDependencies: @@ -12771,9 +12790,12 @@ packages: optional: true utf-8-validate: optional: true + dependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.3 dev: false - /ws@8.14.2: + /ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} engines: {node: '>=10.0.0'} peerDependencies: @@ -12784,6 +12806,9 @@ packages: optional: true utf-8-validate: optional: true + dependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.3 dev: true /xml-name-validator@4.0.0: From 13ba1461252297090eae73964d579c285f1234df Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 13:45:37 +0100 Subject: [PATCH 19/42] feat(store): :sparkles: add cosmjs sign utils --- packages/store/src/cosmjs/index.ts | 1 + packages/store/src/cosmjs/sign.ts | 105 +++++++++++++++++++++++++++++ packages/store/src/index.ts | 1 + packages/store/src/store.ts | 30 ++++++++- 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 packages/store/src/cosmjs/index.ts create mode 100644 packages/store/src/cosmjs/sign.ts diff --git a/packages/store/src/cosmjs/index.ts b/packages/store/src/cosmjs/index.ts new file mode 100644 index 00000000..4baa8dbe --- /dev/null +++ b/packages/store/src/cosmjs/index.ts @@ -0,0 +1 @@ +export * from './sign'; diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts new file mode 100644 index 00000000..6640c9fc --- /dev/null +++ b/packages/store/src/cosmjs/sign.ts @@ -0,0 +1,105 @@ +import type { StdFee } from '@cosmjs/amino'; +import type { EncodeObject } from '@cosmjs/proto-signing'; +import { store } from '../store'; +import { assertIsDefined, estimateFee } from '@quirks/core'; +import { SigningStargateClient } from '@cosmjs/stargate'; +import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; +import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; + +/** + * Why is this part outside the store? + * + * It is useful for it to be external since it depends on the store, + * but it doesn't have to be reactive, it also allows us to pass these functions outside of a react component, + * for example if I want to create a promise that signs a message and then I want to give this promise to a library like tanstack-query + */ + +/** + * Sign a TX using CosmJS Stargate Client + * + * @param chainName + * @param messages + * @param fee + * @param memo + * @returns TxRa + */ +export const sign = async ( + chainName: string, + messages: EncodeObject[], + fee: StdFee | 'auto' = 'auto', + memo?: string, +): Promise => { + const state = store.getState(); + assertIsDefined(state.wallet); + + const chain = store + .getState() + .chains.find((el) => el.chain_name === chainName); + assertIsDefined(chain); + + const sender = store.getState().getAddress(chain.chain_id); + assertIsDefined(sender); + + const offlineSigner = await state.wallet.getOfflineSignerAuto( + chain.chain_id, + store.getState().signOptions, + ); + + const client = await SigningStargateClient.connectWithSigner( + // TODO: Add dynamic RPC + '', + offlineSigner, + ); + + if (fee === 'auto') { + // TODO: Add dynamic gasPrice + fee = await estimateFee(client, sender, messages, '', memo); + } + + return client.sign(sender, messages, fee, memo ?? ''); +}; + +/** + * Sign a TX using CosmJS Stargate Client + * + * @param chainName + * @param messages + * @param fee + * @param memo + * @returns TxRa + */ +export const signCW = async ( + chainName: string, + messages: EncodeObject[], + fee: StdFee | 'auto' = 'auto', + memo?: string, +): Promise => { + const state = store.getState(); + assertIsDefined(state.wallet); + + const chain = store + .getState() + .chains.find((el) => el.chain_name === chainName); + assertIsDefined(chain); + + const sender = store.getState().getAddress(chain.chain_id); + assertIsDefined(sender); + + const offlineSigner = await state.wallet.getOfflineSignerAuto( + chain.chain_id, + store.getState().signOptions, + ); + + const client = await SigningCosmWasmClient.connectWithSigner( + // TODO: Add dynamic RPC + '', + offlineSigner, + ); + + if (fee === 'auto') { + // TODO: Add dynamic gasPrice + fee = await estimateFee(client, sender, messages, '', memo); + } + + return client.sign(sender, messages, fee, memo ?? ''); +}; diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts index dbe62159..81cb984f 100644 --- a/packages/store/src/index.ts +++ b/packages/store/src/index.ts @@ -1,3 +1,4 @@ export * from './store'; export * from './utils'; export * from './types'; +export * from './cosmjs'; diff --git a/packages/store/src/store.ts b/packages/store/src/store.ts index f48b2192..49e09c53 100644 --- a/packages/store/src/store.ts +++ b/packages/store/src/store.ts @@ -14,7 +14,7 @@ import { signInitialState, createSignSlice, } from './slices'; -import { createSSRStorage } from './utils'; +import { createSSRStorage, noopStorage } from './utils'; import { createStore } from 'zustand/vanilla'; import type { SignOptions, Wallet } from '@quirks/core'; import type { AssetLists, Chain } from '@nabla-studio/chain-registry'; @@ -73,6 +73,32 @@ export const ssrPersistOptions: PersistOptions = { skipHydration: true, }; +const emptyPersistOptions: PersistOptions = { + ...defaultPersistOptions, + storage: createJSONStorage(() => noopStorage), +}; + +export let store = createStore( + subscribeWithSelector( + persist( + (...props) => ({ + ...createConfigSlice(...props), + ...createConnectSlice(...props), + ...createAccountSlice(...props), + ...createSignSlice(...props), + reset: () => { + props[0]({ + ...configInitialState, + ...connectInitialState, + ...accountInitialState, + }); + }, + }), + emptyPersistOptions, + ), + ), +); + export const createConfig = (config: Config) => { const { wallets, @@ -92,7 +118,7 @@ export const createConfig = (config: Config) => { signOptions: signOverrideOptions, }; - const store = createStore( + store = createStore( subscribeWithSelector( persist( (...props) => ({ From ee683334fc6b61da375ab6cf0a825173f302ae76 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 14:19:23 +0100 Subject: [PATCH 20/42] docs(store): :memo: update doc --- packages/store/src/cosmjs/sign.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index 6640c9fc..fb1604a3 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -21,7 +21,7 @@ import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; * @param messages * @param fee * @param memo - * @returns TxRa + * @returns TxRaw */ export const sign = async ( chainName: string, @@ -66,7 +66,7 @@ export const sign = async ( * @param messages * @param fee * @param memo - * @returns TxRa + * @returns TxRaw */ export const signCW = async ( chainName: string, From 79b4cf82f58df75cb4ce1820fb50e6dd244d399a Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 14:34:11 +0100 Subject: [PATCH 21/42] feat(core): :sparkles: add getEndpoint util --- packages/core/package.json | 1 - packages/core/src/utils/endpoints.ts | 18 ++++++++++++++++++ packages/core/src/utils/index.ts | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/utils/endpoints.ts diff --git a/packages/core/package.json b/packages/core/package.json index 906a01af..2eb888a7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -18,7 +18,6 @@ }, "peerDependencies": { "@cosmjs/stargate": "^0.31.3", - "@cosmjs/cosmwasm-stargate": "^0.31.3", "@cosmjs/proto-signing": "^0.31.3", "cosmjs-types": "^0.9.0", "@cosmjs/amino": "^0.31.3", diff --git a/packages/core/src/utils/endpoints.ts b/packages/core/src/utils/endpoints.ts new file mode 100644 index 00000000..b8407bbb --- /dev/null +++ b/packages/core/src/utils/endpoints.ts @@ -0,0 +1,18 @@ +import { Chain } from '@nabla-studio/chain-registry'; +import { assertIsDefined } from './asserts'; + +export const getEndpoint = (chainName: string, chains: Chain[]) => { + const chain = chains.find((el) => el.chain_name === chainName); + + assertIsDefined(chain); + assertIsDefined(chain.apis?.rpc); + assertIsDefined(chain.apis?.rest); + + const rpc = chain.apis.rpc[0]; + const rest = chain.apis.rest[0]; + + return { + rpc, + rest, + }; +}; diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 0bb17cba..a6142fcc 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -2,3 +2,4 @@ export * from './extension'; export * from './asserts'; export * from './errors'; export * from './fees'; +export * from './endpoints'; From 4e47969b9ce9d1bda8863611b8f465215fc24eae Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 14:40:52 +0100 Subject: [PATCH 22/42] feat(store): :sparkles: add dynamic endpoint --- packages/store/package.json | 2 ++ packages/store/src/cosmjs/sign.ts | 16 +++++++++------- packages/store/vite.config.ts | 14 +++++++++++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/store/package.json b/packages/store/package.json index 68c6cbf0..7f9b144b 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -21,6 +21,8 @@ "zustand": "^4.4.4", "@cosmjs/amino": "^0.31.3", "@cosmjs/proto-signing": "^0.31.3", + "@cosmjs/stargate": "^0.31.3", + "@cosmjs/cosmwasm-stargate": "^0.31.3", "cosmjs-types": "^0.9.0" }, "main": "./index.js", diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index fb1604a3..4740f4fd 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -1,7 +1,7 @@ import type { StdFee } from '@cosmjs/amino'; import type { EncodeObject } from '@cosmjs/proto-signing'; import { store } from '../store'; -import { assertIsDefined, estimateFee } from '@quirks/core'; +import { assertIsDefined, estimateFee, getEndpoint } from '@quirks/core'; import { SigningStargateClient } from '@cosmjs/stargate'; import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; @@ -37,6 +37,8 @@ export const sign = async ( .chains.find((el) => el.chain_name === chainName); assertIsDefined(chain); + const endpoint = getEndpoint(chainName, store.getState().chains); + const sender = store.getState().getAddress(chain.chain_id); assertIsDefined(sender); @@ -46,14 +48,13 @@ export const sign = async ( ); const client = await SigningStargateClient.connectWithSigner( - // TODO: Add dynamic RPC - '', + endpoint.rpc.address, offlineSigner, ); if (fee === 'auto') { // TODO: Add dynamic gasPrice - fee = await estimateFee(client, sender, messages, '', memo); + fee = await estimateFee(client, sender, messages, '1uosmo', memo); } return client.sign(sender, messages, fee, memo ?? ''); @@ -82,6 +83,8 @@ export const signCW = async ( .chains.find((el) => el.chain_name === chainName); assertIsDefined(chain); + const endpoint = getEndpoint(chainName, store.getState().chains); + const sender = store.getState().getAddress(chain.chain_id); assertIsDefined(sender); @@ -91,14 +94,13 @@ export const signCW = async ( ); const client = await SigningCosmWasmClient.connectWithSigner( - // TODO: Add dynamic RPC - '', + endpoint.rpc.address, offlineSigner, ); if (fee === 'auto') { // TODO: Add dynamic gasPrice - fee = await estimateFee(client, sender, messages, '', memo); + fee = await estimateFee(client, sender, messages, '1uosmo', memo); } return client.sign(sender, messages, fee, memo ?? ''); diff --git a/packages/store/vite.config.ts b/packages/store/vite.config.ts index dcd019fd..7f315404 100644 --- a/packages/store/vite.config.ts +++ b/packages/store/vite.config.ts @@ -34,7 +34,19 @@ export default defineConfig({ }, rollupOptions: { // External packages that should not be bundled into your library. - external: ['zustand', 'zustand/middleware', 'zustand/vanilla'], + external: [ + 'zustand', + 'zustand/middleware', + 'zustand/vanilla', + '@cosmjs/amino', + '@cosmjs/proto-signing', + '@cosmjs/stargate', + '@cosmjs/cosmwasm-stargate', + '@cosmjs/stargate', + 'cosmjs-types', + '@quirks/core', + '@nabla-studio/chain-registry', + ], }, }, From 88382f93c91eef22ae801837fa14fe3790fd3dd0 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 14:42:26 +0100 Subject: [PATCH 23/42] chore(wallets): :wrench: exclude dep bundling --- packages/wallets/vite.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/wallets/vite.config.ts b/packages/wallets/vite.config.ts index c9534de0..15a3b36d 100644 --- a/packages/wallets/vite.config.ts +++ b/packages/wallets/vite.config.ts @@ -41,6 +41,8 @@ export default defineConfig({ '@cosmjs/amino', 'semver', 'long', + '@quirks/core', + '@nabla-studio/chain-registry', ], }, }, From f13de67bd6f8a48f3cc7f2e338332a946f8a9c6c Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 14:44:24 +0100 Subject: [PATCH 24/42] chore(react): :wrench: exclude dep bundling --- packages/react/vite.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts index 6df515ba..f0a7eb24 100644 --- a/packages/react/vite.config.ts +++ b/packages/react/vite.config.ts @@ -43,6 +43,10 @@ export default defineConfig({ 'zustand', 'zustand/vanilla', 'zustand/middleware', + '@quirks/store', + '@quirks/core', + 'cosmjs-types', + '@cosmjs/amino', ], }, }, From 3afcfabc887132fcb7f9fab5cb8db89cbc6ec08a Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 14:46:05 +0100 Subject: [PATCH 25/42] chore(core): :wrench: exclude dep bundling --- packages/core/vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts index a3821be1..386e4e00 100644 --- a/packages/core/vite.config.ts +++ b/packages/core/vite.config.ts @@ -40,6 +40,7 @@ export default defineConfig({ '@cosmjs/amino', '@cosmjs/stargate', 'eventemitter3', + '@nabla-studio/chain-registry', ], }, }, From b1a4b773441103e60bf75b400567606c381fd854 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 16:26:06 +0100 Subject: [PATCH 26/42] feat(core): :sparkles: increase fee multiplier --- packages/core/src/utils/fees.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/utils/fees.ts b/packages/core/src/utils/fees.ts index d4add236..6e71f447 100644 --- a/packages/core/src/utils/fees.ts +++ b/packages/core/src/utils/fees.ts @@ -9,7 +9,7 @@ export const estimateFee = async ( messages: EncodeObject[], gasPrice?: string | GasPrice, memo?: string, - multiplier = 1.3, + multiplier = 1.4, ) => { assertIsDefined( gasPrice, From 684c8d92bd5215a3180c50eb3b79e8e40b4324a1 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 16:28:28 +0100 Subject: [PATCH 27/42] feat: :heavy_plus_sign: add osmojs --- package.json | 1 + pnpm-lock.yaml | 176 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 169 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index c6200de9..f9f69559 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "eventemitter3": "^5.0.1", "long": "^5.2.3", "next": "13.5.6", + "osmojs": "^16.5.1", "react": "18.2.0", "react-dom": "18.2.0", "semver": "^7.5.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7eeca875..4903b2a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ dependencies: next: specifier: 13.5.6 version: 13.5.6(@babel/core@7.23.2)(react-dom@18.2.0)(react@18.2.0) + osmojs: + specifier: ^16.5.1 + version: 16.5.1(bufferutil@4.0.8)(utf-8-validate@6.0.3) react: specifier: 18.2.0 version: 18.2.0 @@ -1517,7 +1520,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 - dev: true /@babel/template@7.22.15: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} @@ -1741,6 +1743,15 @@ packages: protobufjs: 6.11.4 dev: false + /@cosmjs/amino@0.29.3: + resolution: {integrity: sha512-BFz1++ERerIggiFc7iGHhGe1CeV3rCv8BvkoBQTBN/ZwzHOaKvqQj8smDlRGlQxX3HWlTwgiLN2A+OB5yX4ZRw==} + dependencies: + '@cosmjs/crypto': 0.29.5 + '@cosmjs/encoding': 0.29.5 + '@cosmjs/math': 0.29.5 + '@cosmjs/utils': 0.29.5 + dev: false + /@cosmjs/amino@0.31.3: resolution: {integrity: sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==} dependencies: @@ -1770,6 +1781,18 @@ packages: - utf-8-validate dev: false + /@cosmjs/crypto@0.29.5: + resolution: {integrity: sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ==} + dependencies: + '@cosmjs/encoding': 0.29.5 + '@cosmjs/math': 0.29.5 + '@cosmjs/utils': 0.29.5 + '@noble/hashes': 1.3.2 + bn.js: 5.2.1 + elliptic: 6.5.4 + libsodium-wrappers: 0.7.13 + dev: false + /@cosmjs/crypto@0.31.3: resolution: {integrity: sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==} dependencies: @@ -1782,6 +1805,14 @@ packages: libsodium-wrappers-sumo: 0.7.13 dev: false + /@cosmjs/encoding@0.29.5: + resolution: {integrity: sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ==} + dependencies: + base64-js: 1.5.1 + bech32: 1.1.4 + readonly-date: 1.0.0 + dev: false + /@cosmjs/encoding@0.31.3: resolution: {integrity: sha512-6IRtG0fiVYwyP7n+8e54uTx2pLYijO48V3t9TLiROERm5aUAIzIlz6Wp0NYaI5he9nh1lcEGJ1lkquVKFw3sUg==} dependencies: @@ -1790,6 +1821,13 @@ packages: readonly-date: 1.0.0 dev: false + /@cosmjs/json-rpc@0.29.5: + resolution: {integrity: sha512-C78+X06l+r9xwdM1yFWIpGl03LhB9NdM1xvZpQHwgCOl0Ir/WV8pw48y3Ez2awAoUBRfTeejPe4KvrE6NoIi/w==} + dependencies: + '@cosmjs/stream': 0.29.5 + xstream: 11.14.0 + dev: false + /@cosmjs/json-rpc@0.31.3: resolution: {integrity: sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg==} dependencies: @@ -1797,12 +1835,30 @@ packages: xstream: 11.14.0 dev: false + /@cosmjs/math@0.29.5: + resolution: {integrity: sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q==} + dependencies: + bn.js: 5.2.1 + dev: false + /@cosmjs/math@0.31.3: resolution: {integrity: sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==} dependencies: bn.js: 5.2.1 dev: false + /@cosmjs/proto-signing@0.29.3: + resolution: {integrity: sha512-Ai3l9THjMOrLJ4Ebn1Dgptwg6W5ZIRJqtnJjijHhGwTVC1WT0WdYU3aMZ7+PwubcA/cA1rH4ZTK7jrfYbra63g==} + dependencies: + '@cosmjs/amino': 0.29.3 + '@cosmjs/crypto': 0.29.5 + '@cosmjs/encoding': 0.29.5 + '@cosmjs/math': 0.29.5 + '@cosmjs/utils': 0.29.5 + cosmjs-types: 0.5.2 + long: 4.0.0 + dev: false + /@cosmjs/proto-signing@0.31.3: resolution: {integrity: sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA==} dependencies: @@ -1815,6 +1871,18 @@ packages: long: 4.0.0 dev: false + /@cosmjs/socket@0.29.5(bufferutil@4.0.8)(utf-8-validate@6.0.3): + resolution: {integrity: sha512-5VYDupIWbIXq3ftPV1LkS5Ya/T7Ol/AzWVhNxZ79hPe/mBfv1bGau/LqIYOm2zxGlgm9hBHOTmWGqNYDwr9LNQ==} + dependencies: + '@cosmjs/stream': 0.29.5 + isomorphic-ws: 4.0.1(ws@7.5.9) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + /@cosmjs/socket@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==} dependencies: @@ -1827,6 +1895,27 @@ packages: - utf-8-validate dev: false + /@cosmjs/stargate@0.29.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): + resolution: {integrity: sha512-455TgXStCi6E8KDjnhDAM8wt6aLSjobH4Dixvd7Up1DfCH6UB9NkC/G0fMJANNcNXMaM4wSX14niTXwD1d31BA==} + dependencies: + '@confio/ics23': 0.6.8 + '@cosmjs/amino': 0.29.3 + '@cosmjs/encoding': 0.29.5 + '@cosmjs/math': 0.29.5 + '@cosmjs/proto-signing': 0.29.3 + '@cosmjs/stream': 0.29.5 + '@cosmjs/tendermint-rpc': 0.29.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@cosmjs/utils': 0.29.5 + cosmjs-types: 0.5.2 + long: 4.0.0 + protobufjs: 6.11.4 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: false + /@cosmjs/stargate@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw==} dependencies: @@ -1848,12 +1937,37 @@ packages: - utf-8-validate dev: false + /@cosmjs/stream@0.29.5: + resolution: {integrity: sha512-TToTDWyH1p05GBtF0Y8jFw2C+4783ueDCmDyxOMM6EU82IqpmIbfwcdMOCAm0JhnyMh+ocdebbFvnX/sGKzRAA==} + dependencies: + xstream: 11.14.0 + dev: false + /@cosmjs/stream@0.31.3: resolution: {integrity: sha512-8keYyI7X0RjsLyVcZuBeNjSv5FA4IHwbFKx7H60NHFXszN8/MvXL6aZbNIvxtcIHHsW7K9QSQos26eoEWlAd+w==} dependencies: xstream: 11.14.0 dev: false + /@cosmjs/tendermint-rpc@0.29.5(bufferutil@4.0.8)(utf-8-validate@6.0.3): + resolution: {integrity: sha512-ar80twieuAxsy0x2za/aO3kBr2DFPAXDmk2ikDbmkda+qqfXgl35l9CVAAjKRqd9d+cRvbQyb5M4wy6XQpEV6w==} + dependencies: + '@cosmjs/crypto': 0.29.5 + '@cosmjs/encoding': 0.29.5 + '@cosmjs/json-rpc': 0.29.5 + '@cosmjs/math': 0.29.5 + '@cosmjs/socket': 0.29.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@cosmjs/stream': 0.29.5 + '@cosmjs/utils': 0.29.5 + axios: 0.21.4 + readonly-date: 1.0.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: false + /@cosmjs/tendermint-rpc@0.31.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g==} dependencies: @@ -1873,10 +1987,23 @@ packages: - utf-8-validate dev: false + /@cosmjs/utils@0.29.5: + resolution: {integrity: sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ==} + dev: false + /@cosmjs/utils@0.31.3: resolution: {integrity: sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==} dev: false + /@cosmology/lcd@0.12.0: + resolution: {integrity: sha512-f2mcySYO1xdislAhuWtNFmg4q/bzY3Aem2UkDzYzI0ZELVev5i2Pi0bQrYUNTeNg1isAo0Kyrdqj/4YPqEwjGA==} + dependencies: + '@babel/runtime': 7.23.2 + axios: 0.27.2 + transitivePeerDependencies: + - debug + dev: false + /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -5107,7 +5234,6 @@ packages: /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true /atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} @@ -5140,6 +5266,15 @@ packages: - debug dev: false + /axios@0.27.2: + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.3 + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: false + /axios@1.5.1: resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} dependencies: @@ -5760,7 +5895,6 @@ packages: engines: {node: '>= 0.8'} dependencies: delayed-stream: 1.0.0 - dev: true /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -6083,6 +6217,13 @@ packages: typescript: 5.2.2 dev: true + /cosmjs-types@0.5.2: + resolution: {integrity: sha512-zxCtIJj8v3Di7s39uN4LNcN3HIE1z0B9Z0SPE8ZNQR0oSzsuSe1ACgxoFkvhkS7WBasCAFcglS11G2hyfd5tPg==} + dependencies: + long: 4.0.0 + protobufjs: 6.11.4 + dev: false + /cosmjs-types@0.8.0: resolution: {integrity: sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg==} dependencies: @@ -6400,7 +6541,6 @@ packages: /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - dev: true /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} @@ -7487,7 +7627,6 @@ packages: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: true /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} @@ -9276,6 +9415,16 @@ packages: libsodium-sumo: 0.7.13 dev: false + /libsodium-wrappers@0.7.13: + resolution: {integrity: sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw==} + dependencies: + libsodium: 0.7.13 + dev: false + + /libsodium@0.7.13: + resolution: {integrity: sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw==} + dev: false + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -9624,14 +9773,12 @@ packages: /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - dev: true /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 - dev: true /mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} @@ -10198,6 +10345,20 @@ packages: engines: {node: '>=0.10.0'} dev: true + /osmojs@16.5.1(bufferutil@4.0.8)(utf-8-validate@6.0.3): + resolution: {integrity: sha512-V2Q2yMt7Paax6i+S5Q1l29Km0As/waXKmSVRe8gtd9he42kcbkpwwk/QUCvgS98XsL7Qz+vas2Tca016uBQHTQ==} + dependencies: + '@cosmjs/amino': 0.29.3 + '@cosmjs/proto-signing': 0.29.3 + '@cosmjs/stargate': 0.29.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@cosmjs/tendermint-rpc': 0.29.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@cosmology/lcd': 0.12.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: false + /p-limit@1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -10770,7 +10931,6 @@ packages: /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} - dev: true /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} From 94f47ca6bd69028c793643bc16ecf2347b371fb9 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 16:29:06 +0100 Subject: [PATCH 28/42] feat(store): :sparkles: add getAddress util --- packages/store/src/cosmjs/sign.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index 4740f4fd..1b156739 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -14,6 +14,18 @@ import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; * for example if I want to create a promise that signs a message and then I want to give this promise to a library like tanstack-query */ +export const getAddress = (chainName: string) => { + const chain = store + .getState() + .chains.find((el) => el.chain_name === chainName); + assertIsDefined(chain); + + const sender = store.getState().getAddress(chain.chain_id); + assertIsDefined(sender); + + return sender; +}; + /** * Sign a TX using CosmJS Stargate Client * @@ -39,8 +51,7 @@ export const sign = async ( const endpoint = getEndpoint(chainName, store.getState().chains); - const sender = store.getState().getAddress(chain.chain_id); - assertIsDefined(sender); + const sender = getAddress(chainName); const offlineSigner = await state.wallet.getOfflineSignerAuto( chain.chain_id, @@ -85,8 +96,7 @@ export const signCW = async ( const endpoint = getEndpoint(chainName, store.getState().chains); - const sender = store.getState().getAddress(chain.chain_id); - assertIsDefined(sender); + const sender = getAddress(chainName); const offlineSigner = await state.wallet.getOfflineSignerAuto( chain.chain_id, From ccb095f9c77f56767da1bd155a9ce2b94fd4a138 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 16:29:41 +0100 Subject: [PATCH 29/42] docs(examples-nextjs): :sparkles: add send sign example --- examples/nextjs/components/test.tsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/examples/nextjs/components/test.tsx b/examples/nextjs/components/test.tsx index 4eed8733..eac2c234 100644 --- a/examples/nextjs/components/test.tsx +++ b/examples/nextjs/components/test.tsx @@ -2,6 +2,30 @@ import { useChains, useConnect } from '@quirks/react'; +const send = async () => { + const cosmos = (await import('osmojs')).cosmos; + const sign = (await import('@quirks/store')).sign; + const getAddress = (await import('@quirks/store')).getAddress; + const { send } = cosmos.bank.v1beta1.MessageComposer.withTypeUrl; + + const address = getAddress('osmosis'); + + const msg = send({ + amount: [ + { + denom: 'uosmo', + amount: '1', + }, + ], + toAddress: address, + fromAddress: address, + }); + + console.log(msg); + + await sign('osmosis', [msg]); +}; + export const Test = () => { const { status, connected } = useConnect(); const { accounts } = useChains(); @@ -12,6 +36,7 @@ export const Test = () => { {connected ? (
Addresses: + {accounts.map((account) => (
Chain ID: {account.chainId}
From 5e59b321d623514443e3e95aedb2cc26ddbe6282 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 16:30:51 +0100 Subject: [PATCH 30/42] feat(examples-nextjs): :sparkles: add cosmjs noop added bundle size reducer for cosmjs from osmosis-frontend repo. --- examples/nextjs/etc/noop/README.md | 7 +++++++ examples/nextjs/etc/noop/index.js | 1 + examples/nextjs/etc/noop/package.json | 8 ++++++++ examples/nextjs/next.config.js | 21 +++++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 examples/nextjs/etc/noop/README.md create mode 100644 examples/nextjs/etc/noop/index.js create mode 100644 examples/nextjs/etc/noop/package.json diff --git a/examples/nextjs/etc/noop/README.md b/examples/nextjs/etc/noop/README.md new file mode 100644 index 00000000..45705258 --- /dev/null +++ b/examples/nextjs/etc/noop/README.md @@ -0,0 +1,7 @@ +# Noop + +This is copied as a design pattern from Keplr-wallet! + +https://github.com/chainapsis/keplr-wallet/tree/v0.12.25/etc/noop + +> This directory isn’t actually used, and would be preferred to not be added. But it is needed to explicitly ignore specific libraries used by the dependency. Specifically, libsodium isn’t actually used and WebAssembly can’t be used in the extension’s sandbox environment but creates various errors so the directory exists to ignore libsodium. diff --git a/examples/nextjs/etc/noop/index.js b/examples/nextjs/etc/noop/index.js new file mode 100644 index 00000000..f053ebf7 --- /dev/null +++ b/examples/nextjs/etc/noop/index.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/examples/nextjs/etc/noop/package.json b/examples/nextjs/etc/noop/package.json new file mode 100644 index 00000000..1e0f254d --- /dev/null +++ b/examples/nextjs/etc/noop/package.json @@ -0,0 +1,8 @@ +{ + "name": "noop", + "version": "0.0.1", + "main": "index.js", + "private": true, + "scripts": {}, + "dependencies": {} +} diff --git a/examples/nextjs/next.config.js b/examples/nextjs/next.config.js index 007b2aa5..01017f7f 100644 --- a/examples/nextjs/next.config.js +++ b/examples/nextjs/next.config.js @@ -2,6 +2,7 @@ // eslint-disable-next-line @typescript-eslint/no-var-requires const { composePlugins, withNx } = require('@nx/next'); +const { resolve } = require('path'); /** * @type {import('@nx/next/plugins/with-nx').WithNxOptions} @@ -12,6 +13,26 @@ const nextConfig = { // See: https://github.com/gregberge/svgr svgr: false, }, + webpack: (config) => { + const noop = resolve(__dirname, 'etc', 'noop', 'index.js'); + + config.resolve = { + ...config.resolve, // This spreads existing resolve configuration (if any) + alias: { + ...config.resolve.alias, // This spreads any existing alias configurations + libsodium: noop, + 'libsodium-wrappers': noop, + 'libsodium-sumo': noop, + 'libsodium-wrappers-sumo': noop, + // bip39 is only used in the context of the extension wallet, so we can replace it. + // replacing it with a no-op breaks build, so we can at least replace it with a lighter weight version for now. + // ideally this becomes replaced with an API-compatible no-op. + bip39: noop, + }, + }; + + return config; + }, }; const plugins = [ From 41c48d35df1466091d7e4881d0589022afc45c4b Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 21:12:39 +0100 Subject: [PATCH 31/42] feat(core): :sparkles: add getGasPrice utility --- packages/core/src/utils/fees.ts | 37 ++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/core/src/utils/fees.ts b/packages/core/src/utils/fees.ts index 6e71f447..53c5639b 100644 --- a/packages/core/src/utils/fees.ts +++ b/packages/core/src/utils/fees.ts @@ -1,7 +1,42 @@ import type { EncodeObject } from '@cosmjs/proto-signing'; -import { calculateFee, type GasPrice } from '@cosmjs/stargate'; +import { calculateFee, GasPrice } from '@cosmjs/stargate'; import { assertIsDefined } from './asserts'; import type { SigningSimulatorClient } from '../types'; +import type { Chain } from '@nabla-studio/chain-registry'; + +/** + * Retrieve chain gas price so we can use fee auto. + * + * @param chain + * @param feeDenom ex. uosmo + * @returns + */ +export const getGasPrice = (chain: Chain, feeDenom?: string) => { + let gasPrice: GasPrice | undefined = undefined; + + if (chain.fees && chain.fees.fee_tokens.length > 0) { + let feeToken = undefined; + + if (feeToken) { + feeToken = chain.fees.fee_tokens.find( + (token) => token.denom === feeDenom, + ); + } else { + chain.fees.fee_tokens[0]; + } + + const averageGasPrice = feeToken?.average_gas_price; + const denom = feeToken?.denom; + + if (averageGasPrice && denom && !denom.startsWith('ibc/')) { + gasPrice = GasPrice.fromString(`${averageGasPrice}${denom}`); + } else { + gasPrice = GasPrice.fromString(`1${denom}`); + } + } + + return gasPrice; +}; export const estimateFee = async ( client: SigningSimulatorClient, From c2ed561d9a2bc87c7b095510778c10a0c86c8c36 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 4 Nov 2023 21:35:05 +0100 Subject: [PATCH 32/42] feat(store): :sparkles: add gasPrice options --- packages/store/src/cosmjs/sign.ts | 49 ++++++++++++++++++++++++----- packages/store/src/slices/sign.ts | 1 + packages/store/src/store.ts | 36 +++------------------ packages/store/src/types/index.ts | 1 + packages/store/src/types/options.ts | 40 +++++++++++++++++++++++ packages/store/src/types/sign.ts | 2 ++ 6 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 packages/store/src/types/options.ts diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index 1b156739..5165397a 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -1,9 +1,20 @@ import type { StdFee } from '@cosmjs/amino'; import type { EncodeObject } from '@cosmjs/proto-signing'; import { store } from '../store'; -import { assertIsDefined, estimateFee, getEndpoint } from '@quirks/core'; -import { SigningStargateClient } from '@cosmjs/stargate'; -import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; +import { + assertIsDefined, + estimateFee, + getEndpoint, + getGasPrice, +} from '@quirks/core'; +import { + SigningStargateClient, + SigningStargateClientOptions, +} from '@cosmjs/stargate'; +import { + SigningCosmWasmClient, + SigningCosmWasmClientOptions, +} from '@cosmjs/cosmwasm-stargate'; import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; /** @@ -58,14 +69,26 @@ export const sign = async ( store.getState().signOptions, ); + let clientOptions: SigningStargateClientOptions | undefined = undefined; + + const signingStargate = store.getState().signerOptions?.signingStargate; + + if (signingStargate) { + clientOptions = signingStargate(chain); + } + const client = await SigningStargateClient.connectWithSigner( endpoint.rpc.address, offlineSigner, + clientOptions, ); if (fee === 'auto') { - // TODO: Add dynamic gasPrice - fee = await estimateFee(client, sender, messages, '1uosmo', memo); + const gasPrice = clientOptions?.gasPrice + ? clientOptions.gasPrice + : getGasPrice(chain); + + fee = await estimateFee(client, sender, messages, gasPrice, memo); } return client.sign(sender, messages, fee, memo ?? ''); @@ -103,14 +126,26 @@ export const signCW = async ( store.getState().signOptions, ); + let clientOptions: SigningCosmWasmClientOptions | undefined = undefined; + + const signingCosmwasm = store.getState().signerOptions?.signingCosmwasm; + + if (signingCosmwasm) { + clientOptions = signingCosmwasm(chain); + } + const client = await SigningCosmWasmClient.connectWithSigner( endpoint.rpc.address, offlineSigner, + clientOptions, ); if (fee === 'auto') { - // TODO: Add dynamic gasPrice - fee = await estimateFee(client, sender, messages, '1uosmo', memo); + const gasPrice = clientOptions?.gasPrice + ? clientOptions.gasPrice + : getGasPrice(chain); + + fee = await estimateFee(client, sender, messages, gasPrice, memo); } return client.sign(sender, messages, fee, memo ?? ''); diff --git a/packages/store/src/slices/sign.ts b/packages/store/src/slices/sign.ts index 76ae4751..d8a1212e 100644 --- a/packages/store/src/slices/sign.ts +++ b/packages/store/src/slices/sign.ts @@ -8,6 +8,7 @@ export const signInitialState: SignState = { preferNoSetMemo: true, disableBalanceCheck: true, }, + signerOptions: undefined, }; export const createSignSlice: StateCreator = ( diff --git a/packages/store/src/store.ts b/packages/store/src/store.ts index 49e09c53..2fbaba44 100644 --- a/packages/store/src/store.ts +++ b/packages/store/src/store.ts @@ -16,37 +16,7 @@ import { } from './slices'; import { createSSRStorage, noopStorage } from './utils'; import { createStore } from 'zustand/vanilla'; -import type { SignOptions, Wallet } from '@quirks/core'; -import type { AssetLists, Chain } from '@nabla-studio/chain-registry'; -import type { AppState } from './types'; - -export interface Config { - wallets: Wallet[]; - chains: Chain[]; - assetsLists: AssetLists[]; - /** - * State manager persister - */ - persistOptions?: PersistOptions; - /** - * Reinit connection on mount - * - * @default true - */ - autoConnect?: boolean; - /** - * Specify custom sign option - * - * @default - * - * { - * preferNoSetFee: false, - * preferNoSetMemo: true, - * disableBalanceCheck: true, - * } - */ - signOptions?: SignOptions; -} +import type { AppState, Config } from './types'; const excludedKeys: (keyof AppState)[] = [ 'wallet', @@ -107,6 +77,7 @@ export const createConfig = (config: Config) => { autoConnect = true, persistOptions = defaultPersistOptions, signOptions, + signerOptions, } = config; const signOverrideOptions = signOptions @@ -116,6 +87,7 @@ export const createConfig = (config: Config) => { const signOverrideInitialState = { ...signInitialState, signOptions: signOverrideOptions, + signerOptions, }; store = createStore( @@ -129,7 +101,7 @@ export const createConfig = (config: Config) => { ...createConnectSlice(...props), ...createAccountSlice(...props), ...createSignSlice(...props), - signOverrideOptions, + ...signOverrideInitialState, reset: () => { props[0]({ ...configInitialState, diff --git a/packages/store/src/types/index.ts b/packages/store/src/types/index.ts index 6987a013..16b26006 100644 --- a/packages/store/src/types/index.ts +++ b/packages/store/src/types/index.ts @@ -3,3 +3,4 @@ export * from './store'; export * from './connect'; export * from './account'; export * from './sign'; +export * from './options'; diff --git a/packages/store/src/types/options.ts b/packages/store/src/types/options.ts new file mode 100644 index 00000000..266074af --- /dev/null +++ b/packages/store/src/types/options.ts @@ -0,0 +1,40 @@ +import type { SignOptions, Wallet } from '@quirks/core'; +import type { AssetLists, Chain } from '@nabla-studio/chain-registry'; +import type { SigningStargateClientOptions } from '@cosmjs/stargate'; +import type { SigningCosmWasmClientOptions } from '@cosmjs/cosmwasm-stargate'; +import type { PersistOptions } from 'zustand/middleware'; +import type { AppState } from './store'; + +export interface SignerOptions { + signingStargate?: (chain: Chain) => SigningStargateClientOptions | undefined; + signingCosmwasm?: (chain: Chain) => SigningCosmWasmClientOptions | undefined; +} + +export interface Config { + wallets: Wallet[]; + chains: Chain[]; + assetsLists: AssetLists[]; + /** + * State manager persister + */ + persistOptions?: PersistOptions; + /** + * Reinit connection on mount + * + * @default true + */ + autoConnect?: boolean; + /** + * Specify custom sign option + * + * @default + * + * { + * preferNoSetFee: false, + * preferNoSetMemo: true, + * disableBalanceCheck: true, + * } + */ + signOptions?: SignOptions; + signerOptions?: SignerOptions; +} diff --git a/packages/store/src/types/sign.ts b/packages/store/src/types/sign.ts index c3de20d5..b54aaf0e 100644 --- a/packages/store/src/types/sign.ts +++ b/packages/store/src/types/sign.ts @@ -9,9 +9,11 @@ import type { } from '@cosmjs/proto-signing'; import type { SignOptions } from '@quirks/core'; import type { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; +import type { SignerOptions } from './options'; export interface SignState { signOptions: SignOptions; + signerOptions?: SignerOptions; } export interface SignActions { From 2a6f6c392d6c342935b559133bebabbaa6da5e6a Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sun, 5 Nov 2023 01:42:10 +0100 Subject: [PATCH 33/42] feat(store): :sparkles: add broadcast utils --- packages/store/src/cosmjs/sign.ts | 89 ++++++++++++++++++++++++++++- packages/store/src/types/options.ts | 6 +- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index 5165397a..a0f18495 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -10,12 +10,13 @@ import { import { SigningStargateClient, SigningStargateClientOptions, + StargateClient, } from '@cosmjs/stargate'; import { SigningCosmWasmClient, SigningCosmWasmClientOptions, } from '@cosmjs/cosmwasm-stargate'; -import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; +import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; /** * Why is this part outside the store? @@ -25,6 +26,12 @@ import type { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; * for example if I want to create a promise that signs a message and then I want to give this promise to a library like tanstack-query */ +/** + * Get current account address by chainName + * + * @param chainName + * @returns string + */ export const getAddress = (chainName: string) => { const chain = store .getState() @@ -37,6 +44,86 @@ export const getAddress = (chainName: string) => { return sender; }; +/** + * Allows you to broadcast a txraw + * + * @param chainName + * @param txRaw + * @param timeoutMs + * @param pollIntervalMs + * @returns Promise + */ +export const broadcast = async ( + chainName: string, + txRaw: TxRaw, + timeoutMs = 60_000, + pollIntervalMs = 3_000, +) => { + const state = store.getState(); + + const chain = store + .getState() + .chains.find((el) => el.chain_name === chainName); + assertIsDefined(chain); + + const endpoint = getEndpoint(chainName, state.chains); + + let clientOptions: SigningStargateClientOptions | undefined = undefined; + + const stargate = store.getState().signerOptions?.stargate; + + if (stargate) { + clientOptions = stargate(chain); + } + + const client = await StargateClient.connect( + endpoint.rpc.address, + clientOptions, + ); + + const txBytes = TxRaw.encode(txRaw).finish(); + + return client.broadcastTx(txBytes, timeoutMs, pollIntervalMs); +}; + +/** + * allows you to broadcast a txraw, but in synchronous mode, + * it does not stay polled but directly returns the hash of the transaction. + * + * @param chainName + * @param txRaw + * @param timeoutMs + * @param pollIntervalMs + * @returns string + */ +export const broadcastSync = async (chainName: string, txRaw: TxRaw) => { + const state = store.getState(); + + const chain = store + .getState() + .chains.find((el) => el.chain_name === chainName); + assertIsDefined(chain); + + const endpoint = getEndpoint(chainName, state.chains); + + let clientOptions: SigningStargateClientOptions | undefined = undefined; + + const stargate = store.getState().signerOptions?.stargate; + + if (stargate) { + clientOptions = stargate(chain); + } + + const client = await StargateClient.connect( + endpoint.rpc.address, + clientOptions, + ); + + const txBytes = TxRaw.encode(txRaw).finish(); + + return client.broadcastTxSync(txBytes); +}; + /** * Sign a TX using CosmJS Stargate Client * diff --git a/packages/store/src/types/options.ts b/packages/store/src/types/options.ts index 266074af..00b16d7e 100644 --- a/packages/store/src/types/options.ts +++ b/packages/store/src/types/options.ts @@ -1,11 +1,15 @@ import type { SignOptions, Wallet } from '@quirks/core'; import type { AssetLists, Chain } from '@nabla-studio/chain-registry'; -import type { SigningStargateClientOptions } from '@cosmjs/stargate'; +import type { + SigningStargateClientOptions, + StargateClientOptions, +} from '@cosmjs/stargate'; import type { SigningCosmWasmClientOptions } from '@cosmjs/cosmwasm-stargate'; import type { PersistOptions } from 'zustand/middleware'; import type { AppState } from './store'; export interface SignerOptions { + stargate?: (chain: Chain) => StargateClientOptions | undefined; signingStargate?: (chain: Chain) => SigningStargateClientOptions | undefined; signingCosmwasm?: (chain: Chain) => SigningCosmWasmClientOptions | undefined; } From b577f1a1f083bb88a3c53cb9f1b7230ac14f1b97 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sun, 5 Nov 2023 01:48:00 +0100 Subject: [PATCH 34/42] refactor(store): :recycle: refactor store utils --- packages/store/src/cosmjs/sign.ts | 32 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index a0f18495..92fa4465 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -33,12 +33,12 @@ import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; * @returns string */ export const getAddress = (chainName: string) => { - const chain = store - .getState() - .chains.find((el) => el.chain_name === chainName); + const state = store.getState(); + + const chain = state.chains.find((el) => el.chain_name === chainName); assertIsDefined(chain); - const sender = store.getState().getAddress(chain.chain_id); + const sender = state.getAddress(chain.chain_id); assertIsDefined(sender); return sender; @@ -70,7 +70,7 @@ export const broadcast = async ( let clientOptions: SigningStargateClientOptions | undefined = undefined; - const stargate = store.getState().signerOptions?.stargate; + const stargate = state.signerOptions?.stargate; if (stargate) { clientOptions = stargate(chain); @@ -99,16 +99,14 @@ export const broadcast = async ( export const broadcastSync = async (chainName: string, txRaw: TxRaw) => { const state = store.getState(); - const chain = store - .getState() - .chains.find((el) => el.chain_name === chainName); + const chain = state.chains.find((el) => el.chain_name === chainName); assertIsDefined(chain); const endpoint = getEndpoint(chainName, state.chains); let clientOptions: SigningStargateClientOptions | undefined = undefined; - const stargate = store.getState().signerOptions?.stargate; + const stargate = state.signerOptions?.stargate; if (stargate) { clientOptions = stargate(chain); @@ -142,23 +140,21 @@ export const sign = async ( const state = store.getState(); assertIsDefined(state.wallet); - const chain = store - .getState() - .chains.find((el) => el.chain_name === chainName); + const chain = state.chains.find((el) => el.chain_name === chainName); assertIsDefined(chain); - const endpoint = getEndpoint(chainName, store.getState().chains); + const endpoint = getEndpoint(chainName, state.chains); const sender = getAddress(chainName); const offlineSigner = await state.wallet.getOfflineSignerAuto( chain.chain_id, - store.getState().signOptions, + state.signOptions, ); let clientOptions: SigningStargateClientOptions | undefined = undefined; - const signingStargate = store.getState().signerOptions?.signingStargate; + const signingStargate = state.signerOptions?.signingStargate; if (signingStargate) { clientOptions = signingStargate(chain); @@ -204,18 +200,18 @@ export const signCW = async ( .chains.find((el) => el.chain_name === chainName); assertIsDefined(chain); - const endpoint = getEndpoint(chainName, store.getState().chains); + const endpoint = getEndpoint(chainName, state.chains); const sender = getAddress(chainName); const offlineSigner = await state.wallet.getOfflineSignerAuto( chain.chain_id, - store.getState().signOptions, + state.signOptions, ); let clientOptions: SigningCosmWasmClientOptions | undefined = undefined; - const signingCosmwasm = store.getState().signerOptions?.signingCosmwasm; + const signingCosmwasm = state.signerOptions?.signingCosmwasm; if (signingCosmwasm) { clientOptions = signingCosmwasm(chain); From 6dd0d4f0af9773bfe42969f0b9082c6a9253dd3b Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sun, 5 Nov 2023 10:56:39 +0100 Subject: [PATCH 35/42] docs(examples-nextjs): :memo: add broadcast example --- examples/nextjs/components/test.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/nextjs/components/test.tsx b/examples/nextjs/components/test.tsx index eac2c234..58372bd6 100644 --- a/examples/nextjs/components/test.tsx +++ b/examples/nextjs/components/test.tsx @@ -23,7 +23,13 @@ const send = async () => { console.log(msg); - await sign('osmosis', [msg]); + const txRaw = await sign('osmosis', [msg]); + + const broadcast = (await import('@quirks/store')).broadcast; + + const res = await broadcast('osmosis', txRaw); + + console.log(res); }; export const Test = () => { From a9bb8ebfa547d980b3ab1ad9e73d0d7c54977f45 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sun, 5 Nov 2023 23:48:35 +0100 Subject: [PATCH 36/42] feat(store): :sparkles: add getChain util --- packages/store/src/cosmjs/sign.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/store/src/cosmjs/sign.ts b/packages/store/src/cosmjs/sign.ts index 92fa4465..b16fd600 100644 --- a/packages/store/src/cosmjs/sign.ts +++ b/packages/store/src/cosmjs/sign.ts @@ -44,6 +44,14 @@ export const getAddress = (chainName: string) => { return sender; }; +export const getChain = (chainName: string) => { + const chain = store + .getState() + .chains.find((el) => el.chain_name === chainName); + + return chain; +}; + /** * Allows you to broadcast a txraw * From 90ce803ab520f0c403de585b4d847ff16cbf2dba Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Mon, 6 Nov 2023 00:03:42 +0100 Subject: [PATCH 37/42] feat(store): :sparkles: add chain and tokens suggestions --- packages/store/src/utils/index.ts | 1 + packages/store/src/utils/suggestions.ts | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 packages/store/src/utils/suggestions.ts diff --git a/packages/store/src/utils/index.ts b/packages/store/src/utils/index.ts index e8ceb432..8356b716 100644 --- a/packages/store/src/utils/index.ts +++ b/packages/store/src/utils/index.ts @@ -1,2 +1,3 @@ export * from './storage'; export * from './selectors'; +export * from './suggestions'; diff --git a/packages/store/src/utils/suggestions.ts b/packages/store/src/utils/suggestions.ts new file mode 100644 index 00000000..ed1122f7 --- /dev/null +++ b/packages/store/src/utils/suggestions.ts @@ -0,0 +1,22 @@ +import { SuggestChain, SuggestToken, assertIsDefined } from '@quirks/core'; +import { store } from '../store'; + +export const suggestChains = (walletName: string, chains: SuggestChain[]) => { + const state = store.getState(); + + const wallet = state.wallets.find((el) => el.options.name === walletName); + + assertIsDefined(wallet); + + return wallet.suggestChains(chains); +}; + +export const suggestTokens = (walletName: string, tokens: SuggestToken[]) => { + const state = store.getState(); + + const wallet = state.wallets.find((el) => el.options.name === walletName); + + assertIsDefined(wallet); + + return wallet.suggestTokens(tokens); +}; From 6735935073580d1b40b584a1d1a58e69f69bb67b Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Mon, 6 Nov 2023 00:04:05 +0100 Subject: [PATCH 38/42] docs(examples-nextjs): :memo: add chain suggestion example --- examples/nextjs/components/button.tsx | 9 +++++++-- examples/nextjs/components/provider.tsx | 13 +++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/examples/nextjs/components/button.tsx b/examples/nextjs/components/button.tsx index 60b04dcd..ae58e7d0 100644 --- a/examples/nextjs/components/button.tsx +++ b/examples/nextjs/components/button.tsx @@ -1,6 +1,8 @@ 'use client'; +import { bitsong, bitsongAssetList } from '@nabla-studio/chain-registry'; import { useConfig, useConnect } from '@quirks/react'; +import { suggestChains } from '@quirks/store'; export const Button = () => { const { wallets } = useConfig(); @@ -13,8 +15,11 @@ export const Button = () => { return wallets.map((wallet) => (