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

feat(wallets): Add sanchonet wallet option #2937

Merged
merged 12 commits into from
Dec 12, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {useWalletNavigation} from '../../navigation'
import {COLORS} from '../../theme'
import {useWalletManager} from '../../WalletManager'
import * as HASKELL_SHELLEY from '../../yoroi-wallets/cardano/constants/mainnet/constants'
import * as SANCHONET from '../../yoroi-wallets/cardano/constants/sanchonet/constants'
import * as HASKELL_SHELLEY_TESTNET from '../../yoroi-wallets/cardano/constants/testnet/constants'
import {InvalidState, NetworkError} from '../../yoroi-wallets/cardano/errors'
import {isJormungandr} from '../../yoroi-wallets/cardano/networks'
Expand Down Expand Up @@ -89,6 +90,8 @@ export const WalletSelectionScreen = () => {

<OnlyNightlyShelleyTestnetButton />

<OnlyNightlyShelleySanchonetButton />

<OnlyDevButton />

<PleaseWaitModal title={strings.loadingWallet} spinnerText={strings.pleaseWait} visible={isLoading} />
Expand Down Expand Up @@ -197,6 +200,25 @@ const OnlyNightlyShelleyTestnetButton = () => {
)
}

const OnlyNightlyShelleySanchonetButton = () => {
const navigation = useNavigation()
const strings = useStrings()

if (!isNightly() && !__DEV__) return null

const onPress = () => {
navigation.navigate('new-wallet', {
screen: 'choose-create-restore',
params: {
networkId: SANCHONET.NETWORK_ID,
walletImplementationId: SANCHONET.WALLET_IMPLEMENTATION_ID,
},
})
}

return <Button onPress={onPress} title={`${strings.addWalletButton} (sanchonet)`} style={styles.button} />
}

const OnlyDevButton = () => {
const navigation = useNavigation()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@ const apiMock: GovernanceApi = {
export const GovernanceNavigator = () => {
const {networkId} = useSelectedWallet()
const strings = useStrings()
const wallet = useSelectedWallet()
const manager = useMemo(
() =>
governanceManagerMaker({
walletId: wallet.id,
networkId,
api: USE_MOCKED_API ? apiMock : governanceApiMaker({networkId}),
cardano: CardanoMobile,
storage: AsyncStorage,
}),
[networkId],
[networkId, wallet.id],
)
return (
<GovernanceProvider manager={manager}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {Text} from '../../../../../components'
import {COLORS} from '../../../../../theme'
import {useStrings} from '../strings'

// TODO: replace with real link
const LEARN_MORE_LINK = 'https://google.com'
const LEARN_MORE_LINK = ''
Copy link
Collaborator Author

@michaeljscript michaeljscript Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Links will be hidden until we have them ready YOMO-1025


export const LearnMoreLink = () => {
const strings = useStrings()
Expand All @@ -15,6 +14,8 @@ export const LearnMoreLink = () => {
Linking.openURL(LEARN_MORE_LINK)
}

if (LEARN_MORE_LINK.length === 0) return null

return (
<TouchableOpacity style={styles.root} onPress={onPress}>
<Text style={styles.blueText}>{strings.learnMoreAboutGovernance}</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type Props = {
onSubmit?: (drepId: string) => void
}

const FIND_DREPS_LINK = ''
Copy link
Collaborator Author

@michaeljscript michaeljscript Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Links will be hidden until we have them ready YOMO-1025


export const EnterDrepIdModal = ({onSubmit}: Props) => {
const strings = useStrings()
const [drepId, setDrepId] = useState('')
Expand All @@ -22,8 +24,7 @@ export const EnterDrepIdModal = ({onSubmit}: Props) => {
}

const onLinkPress = () => {
// TODO: Add link to DREPs
Linking.openURL('https://google.com')
Linking.openURL(FIND_DREPS_LINK)
}

return (
Expand All @@ -32,11 +33,15 @@ export const EnterDrepIdModal = ({onSubmit}: Props) => {

<Text style={styles.text}>{strings.enterDRepID}</Text>

<Spacer height={24} />
{FIND_DREPS_LINK.length > 0 && (
<>
<Spacer height={24} />

<Text style={[styles.text, styles.link]} onPress={onLinkPress}>
{strings.findDRepHere}
</Text>
<Text style={[styles.text, styles.link]} onPress={onLinkPress}>
{strings.findDRepHere}
</Text>
</>
)}

<Spacer height={24} />

Expand All @@ -48,7 +53,7 @@ export const EnterDrepIdModal = ({onSubmit}: Props) => {
errorText={error?.message}
/>

<Spacer height={24} />
<Spacer fill />

<Button
title={strings.confirm}
Expand All @@ -57,7 +62,7 @@ export const EnterDrepIdModal = ({onSubmit}: Props) => {
onPress={onPress}
/>

<Spacer height={44} />
<Spacer height={24} />
</View>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {useFocusEffect} from '@react-navigation/native'
import {isNonNullable, isString} from '@yoroi/common'
import {
GovernanceProvider,
Expand All @@ -6,7 +7,7 @@ import {
useLatestGovernanceAction,
useVotingCertificate,
} from '@yoroi/staking'
import React, {ReactNode} from 'react'
import React, {ReactNode, useCallback, useState} from 'react'
import {StyleSheet, Text, View} from 'react-native'

import {Spacer, useModal} from '../../../../../components'
Expand All @@ -20,10 +21,11 @@ import {EnterDrepIdModal} from '../EnterDrepIdModal'
export const HomeScreen = () => {
const wallet = useSelectedWallet()
const txInfos = useTransactionInfos(wallet)
useRerenderOnFocus()

const lastVotingAction = useLatestConfirmedGovernanceAction(wallet)

const {data: lastSubmittedTx} = useLatestGovernanceAction()
const {data: lastSubmittedTx} = useLatestGovernanceAction(wallet.id)

const isTxPending =
isString(lastSubmittedTx?.txID) && !Object.values(txInfos).some((tx) => tx.id === lastSubmittedTx?.txID)
Expand Down Expand Up @@ -230,6 +232,12 @@ const NeverParticipatedInGovernanceVariant = () => {
)
}

const useRerenderOnFocus = () => {
michaeljscript marked this conversation as resolved.
Show resolved Hide resolved
const [_, rerender] = useState(0)
const callback = useCallback(() => rerender((r) => r + 1), [rerender])
useFocusEffect(callback)
}

const styles = StyleSheet.create({
root: {
paddingHorizontal: 18,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,16 @@ export class ByronWallet implements YoroiWallet {
}

private getBaseNetworkConfig() {
return this.getNetworkConfig().BASE_CONFIG.reduce((acc, next) => Object.assign(acc, next), {})
type Config = {
PROTOCOL_MAGIC?: number
GENESIS_DATE?: string
START_AT: number
SLOTS_PER_EPOCH: number
SLOT_DURATION: number
}

const config: Config[] = this.getNetworkConfig().BASE_CONFIG
return config.reduce((acc, next) => Object.assign(acc, next), {})
}

private getBackendConfig(): BackendConfig {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {Balance} from '@yoroi/types'

import {DefaultAsset} from '../../../types'
import {COIN_TYPE, COINS_PER_UTXO_WORD, KEY_DEPOSIT, LINEAR_FEE, MINIMUM_UTXO_VAL, POOL_DEPOSIT} from '../common'

export * from '../common'

export const NETWORK_ID = 4_50
michaeljscript marked this conversation as resolved.
Show resolved Hide resolved
export const API_ROOT = 'https://sanchonet-backend.yoroiwallet.com/api'
export const TOKEN_INFO_SERVICE = 'https://stage-cdn.yoroiwallet.com'

export const BACKEND = {
API_ROOT,
NFT_STORAGE_URL: 'https://validated-nft-images.s3.amazonaws.com',
TOKEN_INFO_SERVICE,
FETCH_UTXOS_MAX_ADDRESSES: 50,
TX_HISTORY_MAX_ADDRESSES: 50,
FILTER_USED_MAX_ADDRESSES: 50,
TX_HISTORY_RESPONSE_LIMIT: 50,
} as const
export const CHAIN_NETWORK_ID = 0

export const IS_MAINNET = false

export const PROTOCOL_MAGIC = 1097911063
export const BASE_CONFIG = {
GENESIS_DATE: '1686789000000',
PROTOCOL_MAGIC,
SLOTS_PER_EPOCH: 432000,
SLOT_DURATION: 20,
START_AT: 0,
} as const
export const BYRON_BASE_CONFIG = {
// byron-era
PROTOCOL_MAGIC,
// aka byron network id
START_AT: 0,
GENESIS_DATE: '1686789000000',
SLOTS_PER_EPOCH: 4320,
SLOT_DURATION: 20,
} as const

export const SHELLEY_BASE_CONFIG = {
GENESIS_DATE: '1686789000000',
PROTOCOL_MAGIC,
// shelley-era
START_AT: 0,
SLOTS_PER_EPOCH: 86400,
SLOT_DURATION: 1,
} as const

const CARDANO_BASE_CONFIG = [BYRON_BASE_CONFIG, SHELLEY_BASE_CONFIG]
export const NETWORK_CONFIG = {
BACKEND,
BASE_CONFIG: CARDANO_BASE_CONFIG,
CHAIN_NETWORK_ID: CHAIN_NETWORK_ID.toString(),
COIN_TYPE,
ENABLED: true,
EXPLORER_URL_FOR_ADDRESS: (address: string) => `https://preprod.cardanoscan.io/address/${address}`,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No sanchonet explorers yet

EXPLORER_URL_FOR_TOKEN: (fingerprint: string) =>
fingerprint.length > 0
? `https://preprod.cardanoscan.io/token/${fingerprint}`
: `https://preprod.cardanoscan.io/tokens`,
CEXPLORER_URL_FOR_TOKEN: (fingerprint: string) =>
fingerprint.length > 0 ? `https://preprod.cexplorer.io/asset/${fingerprint}` : `https://preprod.cexplorer.io/asset`,
EXPLORER_URL_FOR_TX: (txid: string) => `https://preprod.cardanoscan.io/transaction/${txid}`,
POOL_EXPLORER: 'https://adapools.yoroiwallet.com/?source=mobile',
IS_MAINNET,
KEY_DEPOSIT,
LINEAR_FEE,
MARKETING_NAME: 'Cardano Sancho Testnet',
MINIMUM_UTXO_VAL,
NETWORK_ID,
PER_EPOCH_PERCENTAGE_REWARD: 69344,
POOL_DEPOSIT,
PROVIDER_ID: 300,
COINS_PER_UTXO_WORD,
} as const

export const PRIMARY_TOKEN_INFO: Balance.TokenInfo = {
id: '',
name: 'TADA',
description: 'Cardano',
fingerprint: '',
kind: 'ft',
group: '',
icon: '',
ticker: 'TADA',
image: '',
decimals: 6,
symbol: '₳',
metadatas: {},
} as const

export const PRIMARY_TOKEN: DefaultAsset = {
identifier: '',
networkId: NETWORK_ID,
isDefault: true,
metadata: {
type: 'Cardano',
policyId: '',
assetName: '',
numberOfDecimals: 6,
ticker: 'TADA',
longName: null,
maxSupply: '45000000000000000',
},
} as const
7 changes: 6 additions & 1 deletion apps/wallet-mobile/src/yoroi-wallets/cardano/getWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import {WALLET_IMPLEMENTATION_REGISTRY, WalletFactory} from '../types'
import {ByronWallet} from './byron'
import {WALLET_CONFIG, WALLET_CONFIG_24} from './constants/common'
import * as MAINNET from './constants/mainnet/constants'
import * as SANCHONET from './constants/sanchonet/constants'
import * as TESTNET from './constants/testnet/constants'
import {ShelleyWalletMainnet, ShelleyWalletTestnet} from './shelley'
import {ShelleySanchonetWallet, ShelleyWalletMainnet, ShelleyWalletTestnet} from './shelley'

export const getCardanoWalletFactory = ({
networkId,
Expand All @@ -22,6 +23,10 @@ export const getCardanoWalletFactory = ({
[WALLET_CONFIG.WALLET_IMPLEMENTATION_ID]: ShelleyWalletTestnet,
[WALLET_CONFIG_24.WALLET_IMPLEMENTATION_ID]: ShelleyWalletTestnet,
},
[SANCHONET.NETWORK_ID]: /* cardano sanchonet */ {
[WALLET_CONFIG.WALLET_IMPLEMENTATION_ID]: ShelleySanchonetWallet,
[WALLET_CONFIG_24.WALLET_IMPLEMENTATION_ID]: ShelleySanchonetWallet,
},
} as const

return walletMap[networkId]?.[implementationId]
Expand Down
15 changes: 13 additions & 2 deletions apps/wallet-mobile/src/yoroi-wallets/cardano/networks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {flatten} from 'lodash'

import * as SANCHONET_CONFIG from '../cardano/constants/sanchonet/constants'
import type {NetworkId} from '../types/other'
import {NETWORK_REGISTRY, YOROI_PROVIDER_IDS} from '../types/other'
import {NUMBERS} from './numbers'
Expand Down Expand Up @@ -189,13 +190,15 @@ const JORMUNGANDR = {
ADDRESS: 'addr',
},
}

export const NETWORKS = {
// Deprecated
BYRON_MAINNET,
HASKELL_SHELLEY,
HASKELL_SHELLEY_TESTNET,
// Deprecated. Consider removing
JORMUNGANDR,
SANCHONET: SANCHONET_CONFIG.NETWORK_CONFIG,
}
type NetworkConfig =
| typeof NETWORKS.BYRON_MAINNET
Expand All @@ -209,7 +212,9 @@ type NetworkConfig =
// TODO: perhaps rename as isJormungandrNetwork for better naming consistency
export const isJormungandr = (networkId: NetworkId): boolean => networkId === NETWORK_REGISTRY.JORMUNGANDR
export const isHaskellShelleyNetwork = (networkId: NetworkId): boolean =>
networkId === NETWORK_REGISTRY.HASKELL_SHELLEY || networkId === NETWORK_REGISTRY.HASKELL_SHELLEY_TESTNET
networkId === NETWORK_REGISTRY.HASKELL_SHELLEY ||
networkId === NETWORK_REGISTRY.HASKELL_SHELLEY_TESTNET ||
networkId === NETWORK_REGISTRY.SANCHONET
export const getCardanoByronConfig = () => NETWORKS.BYRON_MAINNET
export const getNetworkConfigById = (id: NetworkId): NetworkConfig => {
const idx = Object.values(NETWORK_REGISTRY).indexOf(id)
Expand All @@ -221,7 +226,10 @@ export const getNetworkConfigById = (id: NetworkId): NetworkConfig => {

throw new Error('invalid networkId')
}
export type CardanoHaskellShelleyNetwork = typeof NETWORKS.HASKELL_SHELLEY | typeof NETWORKS.HASKELL_SHELLEY_TESTNET
export type CardanoHaskellShelleyNetwork =
| typeof NETWORKS.HASKELL_SHELLEY
| typeof NETWORKS.HASKELL_SHELLEY_TESTNET
| typeof NETWORKS.SANCHONET
export const getCardanoNetworkConfigById = (networkId: NetworkId): CardanoHaskellShelleyNetwork => {
switch (networkId) {
case NETWORKS.HASKELL_SHELLEY.NETWORK_ID:
Expand All @@ -230,6 +238,9 @@ export const getCardanoNetworkConfigById = (networkId: NetworkId): CardanoHaskel
case NETWORKS.HASKELL_SHELLEY_TESTNET.NETWORK_ID:
return NETWORKS.HASKELL_SHELLEY_TESTNET

case NETWORKS.SANCHONET.NETWORK_ID:
return NETWORKS.SANCHONET

default:
throw new Error('network id is not a valid Haskell Shelley id')
}
Expand Down
Loading
Loading