Skip to content

Commit

Permalink
Merge pull request #17 from nabla-studio/DavideSegullo/feat-xdefi_wallet
Browse files Browse the repository at this point in the history
Add xdefi wallet
  • Loading branch information
DavideSegullo authored Nov 13, 2023
2 parents 122e174 + 12d3793 commit 9334e8d
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 20 deletions.
19 changes: 10 additions & 9 deletions examples/nextjs/components/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
'use client';

import {
bitsong,
bitsongAssetList,
osmosis,
osmosisAssetList,
} from '@nabla-studio/chain-registry';
import { osmosis, osmosisAssetList } from '@nabla-studio/chain-registry';
import { QuirksConfig, QuirksNextProvider } from '@quirks/react';
import { type Config, ssrPersistOptions } from '@quirks/store';
import {
xdefiExtension,
keplrExtension,
leapExtension,
cosmostationExtension,
} from '@quirks/wallets';
import { PropsWithChildren } from 'react';

const config: Config = {
wallets: [keplrExtension, leapExtension, cosmostationExtension],
chains: [osmosis, bitsong],
assetsLists: [osmosisAssetList, bitsongAssetList],
wallets: [
keplrExtension,
leapExtension,
cosmostationExtension,
xdefiExtension,
],
chains: [osmosis /* bitsong */],
assetsLists: [osmosisAssetList /* bitsongAssetList */],
persistOptions: ssrPersistOptions,
};

Expand Down
5 changes: 1 addition & 4 deletions examples/nextjs/components/test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
'use client';

import { sign, getAddress, broadcast } from '@quirks/store';
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');
Expand All @@ -25,8 +24,6 @@ const send = async () => {

const txRaw = await sign('osmosis', [msg]);

const broadcast = (await import('@quirks/store')).broadcast;

const res = await broadcast('osmosis', txRaw);

console.log(res);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export interface WalletOptions {
/**
* Window extension key
*/
windowKey?: string;
windowKey?: string | string[];
/**
* Logo url
*/
Expand Down
27 changes: 23 additions & 4 deletions packages/core/src/utils/extension.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
import { createClientNotExistError } from './errors';

const objectTraverse = <T extends { [key: string]: never }>(
obj: T,
keys: string[],
) => {
let cursor = obj;

for (const key of keys) {
cursor = cursor[key];
}

return cursor;
};

export const getClientFromExtension = async <T>(
key: string,
key: string | string[],
): Promise<T | undefined> => {
if (typeof window === 'undefined') {
return undefined;
}

const wallet = (window as never)[key] as T;
const keys = Array.isArray(key) ? key : key.split('.');
const wallet = objectTraverse(window as never, keys) as T;
const latestKey = [...keys].pop();

if (!latestKey) {
throw Error(`Invalid key: ${JSON.stringify(key)}`);
}

if (wallet) {
return wallet;
}

const clientNotExistError = createClientNotExistError(key);
const clientNotExistError = createClientNotExistError(latestKey);

if (document.readyState === 'complete') {
if (wallet) {
Expand All @@ -29,7 +48,7 @@ export const getClientFromExtension = async <T>(
event.target &&
(event.target as Document).readyState === 'complete'
) {
const wallet = (window as never)[key] as T;
const wallet = objectTraverse(window as never, keys) as T;

if (wallet) {
resolve(wallet);
Expand Down
2 changes: 0 additions & 2 deletions packages/store/src/slices/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ export const createConnectSlice: StateCreator<
),
}));

console.log(chains);

return suggestChains(wallet.options.name, chains);
}
},
Expand Down
1 change: 1 addition & 0 deletions packages/wallets/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './keplr';
export * from './leap';
export * from './cosmostation';
export * from './xdefi';
141 changes: 141 additions & 0 deletions packages/wallets/src/xdefi/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import type {
OfflineAminoSigner,
StdSignDoc,
AminoSignResponse,
StdSignature,
} from '@cosmjs/amino';
import type {
OfflineDirectSigner,
DirectSignResponse,
} from '@cosmjs/proto-signing';
import type { Key, SignOptions, WalletOptions } from '@quirks/core';
import { ExtensionWallet, assertIsDefined } from '@quirks/core';
import type { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
import Long from 'long';
import type { XDEFI } from './types';

export class XDEFIWalletExtension extends ExtensionWallet<XDEFI> {
constructor(options: WalletOptions) {
super(options);
}

override enable(chainIds: string[]): Promise<void> {
assertIsDefined(this.client);

return this.client.enable(chainIds);
}

override disable(chainIds: string[]): Promise<void> {
assertIsDefined(this.client);

return this.client.disable(chainIds);
}

override async getAccount(chainId: string) {
assertIsDefined(this.client);

return await this.client.getKey(chainId);
}

override async getAccounts(chainIds: string[]) {
assertIsDefined(this.client);

const keys = await this.client.getKeysSettled(chainIds);

return keys
.map((key) => {
if (key.status === 'fulfilled') {
return key.value;
}

return undefined;
})
.filter((key) => key !== undefined) as Key[];
}

override async getOfflineSigner(
chainId: string,
options?: SignOptions | undefined,
): Promise<OfflineAminoSigner & OfflineDirectSigner> {
assertIsDefined(this.client);

return await this.client.getOfflineSigner(chainId, options);
}

override async getOfflineSignerOnlyAmino(
chainId: string,
options?: SignOptions | undefined,
): Promise<OfflineAminoSigner> {
assertIsDefined(this.client);

return await this.client.getOfflineSignerOnlyAmino(chainId, options);
}

override getOfflineSignerAuto(
chainId: string,
options?: SignOptions | undefined,
): Promise<OfflineAminoSigner | OfflineDirectSigner> {
assertIsDefined(this.client);

return this.client.getOfflineSignerAuto(chainId, options);
}

override signAmino(
chainId: string,
signer: string,
signDoc: StdSignDoc,
signOptions?: SignOptions | undefined,
): Promise<AminoSignResponse> {
assertIsDefined(this.client);

return this.client.signAmino(chainId, signer, signDoc, signOptions);
}

override signDirect(
chainId: string,
signer: string,
signDoc: SignDoc,
signOptions?: SignOptions | undefined,
): Promise<DirectSignResponse> {
assertIsDefined(this.client);

return this.client.signDirect(
chainId,
signer,
{
...signDoc,
accountNumber: Long.fromString(signDoc.accountNumber.toString(10)),
},
signOptions,
);
}

override signArbitrary(
chainId: string,
signer: string,
data: string | Uint8Array,
): Promise<StdSignature> {
assertIsDefined(this.client);

return this.client.signArbitrary(chainId, signer, data);
}

override verifyArbitrary(
chainId: string,
signer: string,
data: string | Uint8Array,
signature: StdSignature,
): Promise<boolean> {
assertIsDefined(this.client);

return this.client.verifyArbitrary(chainId, signer, data, signature);
}

override async suggestTokens(): Promise<void> {
console.warn("xDefi doesn't support suggestTokens");
}

override async suggestChains(): Promise<void> {
console.warn("xDefi doesn't support suggestChains");
}
}
6 changes: 6 additions & 0 deletions packages/wallets/src/xdefi/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { XDEFIWalletExtension } from './extension';
import { xdefiExtensionOptions } from './registry';

const xdefiExtension = new XDEFIWalletExtension(xdefiExtensionOptions);

export { xdefiExtension };
24 changes: 24 additions & 0 deletions packages/wallets/src/xdefi/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { WalletConnectionTypes, type WalletOptions } from '@quirks/core';

export const xdefiExtensionOptions: WalletOptions = {
name: 'xdefi-extension',
prettyName: 'XDEFI',
connectionType: WalletConnectionTypes.EXTENSION,
windowKey: 'xfi.keplr',
downloads: [
{
link: 'https://chrome.google.com/webstore/detail/xdefi-wallet/hmeobnfnfcmdkdcmlblgagmfpfboieaf',
},
],
logoUrls: {
light: {
jpg: 'https://lh3.googleusercontent.com/6TkuRn_tZ2v5Bw4MZ2nTwJLEWU-76bAQFJhXunA7cbroI0izn7Mwi46Wvu3q5WfNUbQiPucQTCSTrb0FD_BCXuo3=w128-h128-e365-rj-sc0x00ffffff',
},
dark: {
jpg: 'https://lh3.googleusercontent.com/6TkuRn_tZ2v5Bw4MZ2nTwJLEWU-76bAQFJhXunA7cbroI0izn7Mwi46Wvu3q5WfNUbQiPucQTCSTrb0FD_BCXuo3=w128-h128-e365-rj-sc0x00ffffff',
},
},
events: {
keystorechange: 'keplr_keystorechange',
},
};
6 changes: 6 additions & 0 deletions packages/wallets/src/xdefi/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Keplr } from '@keplr-wallet/types';

export interface XDEFI extends Keplr {
isXDEFI: boolean;
disconnect: () => Promise<void>;
}

0 comments on commit 9334e8d

Please sign in to comment.