Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small app/api/wallet refactoring #332

Merged
merged 5 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions app/api/wallet/__snapshots__/network.test.ts.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 0 additions & 46 deletions app/api/wallet/index.test.ts

This file was deleted.

17 changes: 0 additions & 17 deletions app/api/wallet/index.ts

This file was deleted.

57 changes: 0 additions & 57 deletions app/api/wallet/mnemonic.test.ts

This file was deleted.

48 changes: 0 additions & 48 deletions app/api/wallet/mnemonic.ts

This file was deleted.

22 changes: 22 additions & 0 deletions app/api/wallet/network.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { EnvironmentNetwork } from "../../environment";
import { getBip32Option } from "./network";

it('should resolve bip32 option for MainNet', () => {
const bip32Options = getBip32Option(EnvironmentNetwork.MainNet)
expect(bip32Options).toMatchSnapshot()
})

it('should resolve bip32 option for TestNet', () => {
const bip32Options = getBip32Option(EnvironmentNetwork.TestNet)
expect(bip32Options).toMatchSnapshot()
})

it('should resolve bip32 option for LocalPlayground', () => {
const bip32Options = getBip32Option(EnvironmentNetwork.LocalPlayground)
expect(bip32Options).toMatchSnapshot()
})

it('should resolve bip32 option for RemotePlayground', () => {
const bip32Options = getBip32Option(EnvironmentNetwork.RemotePlayground)
expect(bip32Options).toMatchSnapshot()
})
12 changes: 12 additions & 0 deletions app/api/wallet/network.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MainNet, Network, RegTest, TestNet } from '@defichain/jellyfish-network'
import { Bip32Options } from '@defichain/jellyfish-wallet-mnemonic'
import { EnvironmentNetwork } from '../../environment'

export function getJellyfishNetwork (network: EnvironmentNetwork): Network {
Expand All @@ -12,3 +13,14 @@ export function getJellyfishNetwork (network: EnvironmentNetwork): Network {
return RegTest
}
}

export function getBip32Option (envNetwork: EnvironmentNetwork): Bip32Options {
const network = getJellyfishNetwork(envNetwork)
return {
bip32: {
public: network.bip32.publicPrefix,
private: network.bip32.privatePrefix
},
wif: network.wifPrefix
}
}
24 changes: 11 additions & 13 deletions app/api/wallet/persistence.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
import { getItem, setItem } from '../storage'

const KEY = 'WALLET'

export enum WalletType {
MNEMONIC_UNPROTECTED = 'MNEMONIC_UNPROTECTED',
// MNEMONIC_PASSWORD = 'MNEMONIC_PASSWORD',
// MNEMONIC_BIOMETRIC = 'MNEMONIC_BIOMETRIC',
// LEDGER_BLUE = 'LEDGER_BLUE',
MNEMONIC_UNPROTECTED = 'MNEMONIC_UNPROTECTED'
}

export interface WalletData {
export interface WalletPersistenceData<T> {
type: WalletType
/* To migrate between app version upgrade */
version: 'v1'
/* Raw Data encoded in WalletType specified format */
raw: string
raw: T
}

async function get (): Promise<WalletData[]> {
const json = await getItem(KEY)
async function get (): Promise<Array<WalletPersistenceData<any>>> {
const json = await getItem('WALLET')
if (json !== null) {
return JSON.parse(json)
}

return []
}

async function set (wallets: WalletData[]): Promise<void> {
await setItem(KEY, JSON.stringify(wallets))
async function set (wallets: Array<WalletPersistenceData<any>>): Promise<void> {
await setItem('WALLET', JSON.stringify(wallets))
}

async function add (data: WalletData): Promise<void> {
async function add (data: WalletPersistenceData<any>): Promise<void> {
const wallets = await get()
wallets.push(data)
await set(wallets)
Expand All @@ -42,6 +37,9 @@ async function remove (index: number): Promise<void> {
await set(wallets)
}

/**
* Multi Wallet Persistence Layer
*/
export const WalletPersistence = {
set,
get,
Expand Down
44 changes: 44 additions & 0 deletions app/api/wallet/provider/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { MnemonicProviderData } from "@defichain/jellyfish-wallet-mnemonic";
import { WhaleApiClient } from "@defichain/whale-api-client";
import { EnvironmentNetwork } from "../../../environment";
import { WalletPersistenceData, WalletType } from "../persistence";
import { initWhaleWallet } from "./index";

beforeEach(async () => {
jest.clearAllMocks()
})

const network = EnvironmentNetwork.LocalPlayground
const client = new WhaleApiClient({ url: 'http://localhost:19553', network: 'regtest' })

it('should initWhaleWallet', async () => {
const data: WalletPersistenceData<MnemonicProviderData> = {
version: "v1",
type: WalletType.MNEMONIC_UNPROTECTED,
raw: {
words: ['abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'art'],
privKey: '235b34cd7c9f6d7e4595ffe9ae4b1cb5606df8aca2b527d20a07c8f56b2342f4',
chainCode: 'f40eaad21641ca7cb5ac00f9ce21cac9ba070bb673a237f7bce57acda54386a4'
}
}

const wallet = initWhaleWallet(data, network, client)

expect(wallet.get(0).withTransactionBuilder().utxo).toBeDefined()
expect(wallet.get(0).withTransactionBuilder().dex).toBeDefined()
expect(wallet.get(0).withTransactionBuilder().account).toBeDefined()
expect(wallet.get(0).withTransactionBuilder().liqPool).toBeDefined()
});


it('should fail as wallet type not available', async () => {
const data: WalletPersistenceData<string> = {
version: "v1",
type: undefined as any,
raw: ""
}

expect(() => {
initWhaleWallet(data, network, client)
}).toThrow('wallet undefined not available')
})
35 changes: 35 additions & 0 deletions app/api/wallet/provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { JellyfishWallet, WalletHdNode, WalletHdNodeProvider } from '@defichain/jellyfish-wallet'
import { WhaleApiClient } from '@defichain/whale-api-client'
import { WhaleWalletAccount, WhaleWalletAccountProvider } from '@defichain/whale-api-wallet'
import { EnvironmentNetwork } from '../../../environment'
import { getJellyfishNetwork } from '../network'
import { WalletPersistenceData, WalletType } from '../persistence'
import { MnemonicUnprotected } from './mnemonic_unprotected'

/**
* Whale JellyfishWallet connected to Whale APIs via the Ocean Infrastructure
*/
export type WhaleWallet = JellyfishWallet<WhaleWalletAccount, WalletHdNode>

export function initWhaleWallet (data: WalletPersistenceData<any>, network: EnvironmentNetwork, client: WhaleApiClient): WhaleWallet {
const jellyfishNetwork = getJellyfishNetwork(network)

const walletProvider = resolveProvider(data, network)
const accountProvider = new WhaleWalletAccountProvider(client, jellyfishNetwork)

return new JellyfishWallet(walletProvider, accountProvider)
}

/**
* @param {WalletPersistenceData} data to resolve wallet provider for init
* @param {EnvironmentNetwork} network
*/
function resolveProvider (data: WalletPersistenceData<any>, network: EnvironmentNetwork): WalletHdNodeProvider<WalletHdNode> {
switch (data.type) {
case WalletType.MNEMONIC_UNPROTECTED:
return MnemonicUnprotected.initProvider(data, network)

default:
throw new Error(`wallet ${data.type as string} not available`)
}
}
Loading