diff --git a/package.json b/package.json
index 4ea16de6..3a149969 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "extension",
- "version": "1.21.0",
+ "version": "1.22.0",
"description": "extension",
"private": false,
"repository": "https://github.com/SimpleHold/extension.git",
@@ -45,6 +45,7 @@
"detect-browser": "^5.2.0",
"digibyte-lib": "https://github.com/DigiByte-Core/digibyte-lib",
"lodash": "^4.17.21",
+ "nanocurrency": "^2.5.0",
"neblio-lib": "https://github.com/NeblioTeam/bitcore-lib#neblcore-lib",
"nerve-sdk-js": "^1.0.8",
"nuls-sdk-js": "^2.5.0",
diff --git a/src/assets/currencies/xno.svg b/src/assets/currencies/xno.svg
new file mode 100644
index 00000000..9c7a0d6a
--- /dev/null
+++ b/src/assets/currencies/xno.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/components/CurrencyAddress/CurrencyAddress.tsx b/src/components/CurrencyAddress/CurrencyAddress.tsx
index d8ddb5ef..04d5976a 100644
--- a/src/components/CurrencyAddress/CurrencyAddress.tsx
+++ b/src/components/CurrencyAddress/CurrencyAddress.tsx
@@ -7,7 +7,7 @@ import CheckBox from '@components/CheckBox'
// Utils
import { short, toUpper } from '@utils/format'
-import { getBalance } from '@utils/api'
+import { getBalance } from '@utils/currencies'
import { getCurrency } from '@config/currencies'
// Styles
@@ -33,7 +33,7 @@ const CurrencyAddress: React.FC = (props) => {
const currency = getCurrency(symbol)
const onGetBalance = async (): Promise => {
- const request = await getBalance(address, currency?.chain)
+ const request = await getBalance(symbol, address, currency?.chain)
setBalance(request.balance)
}
diff --git a/src/components/CurrencyLogo/CurrencyLogo.tsx b/src/components/CurrencyLogo/CurrencyLogo.tsx
index 806cd0e9..70752a18 100644
--- a/src/components/CurrencyLogo/CurrencyLogo.tsx
+++ b/src/components/CurrencyLogo/CurrencyLogo.tsx
@@ -25,7 +25,7 @@ const CurrencyLogo: React.FC = (props) => {
const [logo, setLogo] = React.useState(null)
- const getChainogo = chain ? getCurrencyByChain(chain) : null
+ const getChainLogo = chain ? getCurrencyByChain(chain) : null
const currency = chain ? getToken(symbol, chain) : getCurrency(symbol)
React.useEffect(() => {
@@ -47,7 +47,7 @@ const CurrencyLogo: React.FC = (props) => {
{currency || logo ? (
@@ -57,9 +57,9 @@ const CurrencyLogo: React.FC = (props) => {
{toUpper(name[0])}
) : null}
- {getChainogo ? (
+ {getChainLogo ? (
-
+
) : null}
diff --git a/src/components/WalletCard/WalletCard.tsx b/src/components/WalletCard/WalletCard.tsx
index f47b4eb4..0771432e 100644
--- a/src/components/WalletCard/WalletCard.tsx
+++ b/src/components/WalletCard/WalletCard.tsx
@@ -7,7 +7,8 @@ import CurrencyLogo from '@components/CurrencyLogo'
import Skeleton from '@components/Skeleton'
// Utils
-import { getBalance } from '@utils/api'
+import { updateWalletActivationStatus } from '@utils/currencies/nano'
+import { getBalance } from '@utils/currencies'
import { toUpper, numberFriendly, formatEstimated, getFormatBalance } from '@utils/format'
import {
updateBalance,
@@ -94,6 +95,7 @@ const WalletCard: React.FC = React.memo((props) => {
const [balance, setBalance] = React.useState(null)
const [estimated, setEstimated] = React.useState(null)
const [pendingBalance, setPendingBalance] = React.useState(0)
+ const [notActivatedStatus, setActivationStatus] = React.useState(!!isNotActivated)
const walletData: TTxWallet = {
chain: getWalletChain(symbol, chain),
@@ -104,23 +106,34 @@ const WalletCard: React.FC = React.memo((props) => {
}
React.useEffect(() => {
+ checkActivatedStatus()
loadBalance()
}, [])
+ const checkActivatedStatus = () => {
+ if (symbol === 'xno') {
+ updateWalletActivationStatus(address).then(res => {
+ if (res) {
+ setActivationStatus(true)
+ }
+ })
+ }
+ }
+
const loadBalance = async (): Promise => {
const savedData = getLatestBalance(address, chain, symbol)
const isFetchReady = checkIfTimePassed(savedData.lastBalanceCheck || 0, { seconds: 20 })
const isFullData = !Object.entries(savedData).find(v => v[1] === null)
- let data = isNotActivated ? emptyData : savedData
+ let data = notActivatedStatus ? emptyData : savedData
- const isFetchRequired = !isNotActivated && (isFetchReady || !isFullData)
+ const isFetchRequired = !notActivatedStatus && (isFetchReady || !isFullData)
if (isFetchRequired) {
updateLast('lastBalanceCheck', address, chain)
- const fetchedData = await getBalance(address, currency?.chain || chain, tokenSymbol, contractAddress)
+ const fetchedData = await getBalance(symbol, address, currency?.chain || chain, tokenSymbol, contractAddress)
data = { ...data, ...fetchedData }
}
@@ -185,7 +198,7 @@ const WalletCard: React.FC = React.memo((props) => {
-
+
{hardware ? (
@@ -199,9 +212,9 @@ const WalletCard: React.FC = React.memo((props) => {
) : null}
{walletName}
- {isNotActivated ? (
+ {notActivatedStatus ? (
- Need activation
+ Activation is required
) : (
@@ -209,7 +222,7 @@ const WalletCard: React.FC = React.memo((props) => {
)}
- {!isNotActivated ? (
+ {!notActivatedStatus ? (
diff --git a/src/config/currencies.ts b/src/config/currencies.ts
index 30d62c06..4a164d27 100644
--- a/src/config/currencies.ts
+++ b/src/config/currencies.ts
@@ -30,6 +30,7 @@ import toncoinLogo from '@assets/currencies/toncoin.svg'
import ravencoinLogo from '@assets/currencies/rvn.svg'
import digibyteLogo from '@assets/currencies/dgb.svg'
import ftmLogo from '@assets/currencies/ftm.svg'
+import xnoLogo from '@assets/currencies/xno.svg'
// Utils
import { toLower } from '@utils/format'
@@ -314,6 +315,15 @@ const currencies: ICurrency[] = [
chain: 'ftm',
minSendAmount: 1000,
isCustomFee: true,
+ },
+ {
+ name: 'Nano',
+ symbol: 'xno',
+ logo: xnoLogo,
+ background: '#209CE9',
+ chain: 'xno',
+ minSendAmount: 1000000000000000,
+ isCustomFee: false,
}
]
diff --git a/src/drawers/Wallets/components/Wallet/Wallet.tsx b/src/drawers/Wallets/components/Wallet/Wallet.tsx
index fbacb8ff..bfff1fff 100644
--- a/src/drawers/Wallets/components/Wallet/Wallet.tsx
+++ b/src/drawers/Wallets/components/Wallet/Wallet.tsx
@@ -7,7 +7,7 @@ import CurrencyLogo from '@components/CurrencyLogo'
import Skeleton from '@components/Skeleton'
// Utils
-import { getBalance } from '@utils/api'
+import { getBalance } from '@utils/currencies'
import { toUpper, numberFriendly, short, formatEstimated } from '@utils/format'
import { updateBalance, THardware } from '@utils/wallet'
@@ -58,6 +58,7 @@ const Wallet: React.FC = (props) => {
const fetchBalance = async (): Promise => {
const { balance, balance_usd, balance_btc, pending } = await getBalance(
+ symbol,
address,
currency?.chain || chain,
chain ? symbol : undefined,
diff --git a/src/externalPages/RestoreBackup/RestoreBackup.tsx b/src/externalPages/RestoreBackup/RestoreBackup.tsx
index 1a6c50ed..bfc73396 100644
--- a/src/externalPages/RestoreBackup/RestoreBackup.tsx
+++ b/src/externalPages/RestoreBackup/RestoreBackup.tsx
@@ -47,7 +47,7 @@ const initialState: IState = {
activeDrawer: null,
password: '',
passwordErrorLabel: null,
- isPageActive: false,
+ isPageActive: false
}
const RestoreBackup: React.FC = () => {
@@ -77,7 +77,7 @@ const RestoreBackup: React.FC = () => {
const onConfirm = (): void => {
logEvent({
- name: START_RESTORE_CONFIRM,
+ name: START_RESTORE_CONFIRM
})
updateState({ activeDrawer: 'confirm' })
@@ -85,7 +85,7 @@ const RestoreBackup: React.FC = () => {
const onConfirmRestore = (): void => {
logEvent({
- name: START_RESTORE_PASSWORD,
+ name: START_RESTORE_PASSWORD
})
if (state.passwordErrorLabel) {
@@ -137,7 +137,7 @@ const RestoreBackup: React.FC = () => {
}
return (
-
+
<>
Restore
@@ -151,9 +151,9 @@ const RestoreBackup: React.FC = () => {
-
+
- {isNotActivated ? (
-
- Activate
+
+ {isNotActivated &&
+
+ Activate
+ }
+
+ {hasUnreceivedTxs && !isNotActivated &&
+
+ Receive assets
+ }
+
+ {!isNotActivated && !hasUnreceivedTxs &&
+ <>
+
+ Send
+
+
+ Receive
+
+
+ Exchange
- ) : (
- <>
-
- Send
-
-
- Receive
-
-
- Exchange
-
- >
- )}
+ >}
)
diff --git a/src/pages/Wallet/types.ts b/src/pages/Wallet/types.ts
index 54aa7e27..b4a5940b 100644
--- a/src/pages/Wallet/types.ts
+++ b/src/pages/Wallet/types.ts
@@ -19,7 +19,7 @@ export interface IState {
balance: null | number
estimated: null | number
txHistory: TAddressTxGroup[] | null
- activeDrawer: null | 'confirm' | 'privateKey' | 'renameWallet' | 'success'
+ activeDrawer: null | 'confirm' | 'privateKey' | 'renameWallet' | 'success' | 'txsReceivedSuccess'
isBalanceRefreshing: boolean
password: string
passwordErrorLabel: null | string
@@ -28,7 +28,7 @@ export interface IState {
isHiddenWallet: boolean
warning: null | string
confirmDrawerTitle: string
- confirmDrawerType: 'showPhrase' | 'showPrivateKey' | 'activateWallet' | null
+ confirmDrawerType: 'showPhrase' | 'showPrivateKey' | 'activateWallet' | 'receivePendingTxs' | null
isDrawerButtonLoading: boolean
isNotActivated: boolean
address: string
diff --git a/src/utils/api/index.ts b/src/utils/api/index.ts
index 0a87f98a..1e603bac 100644
--- a/src/utils/api/index.ts
+++ b/src/utils/api/index.ts
@@ -27,7 +27,7 @@ import {
} from './types'
import { IToken } from '@config/tokens'
-export const getBalance = async (
+export const requestBalance = async (
address: string,
chain?: string,
tokenSymbol?: string,
@@ -504,7 +504,7 @@ export const getHistoryTxInfo = async (
}
}
-export const activateAccount = async (chain: string, publicKey: string): Promise => {
+export const activateAccount = async (chain: string, publicKey: string): Promise => {
try {
const { data }: AxiosResponse = await axios.post(
`${config.serverUrl}/wallet/activate`,
@@ -617,3 +617,38 @@ export const getTokens = async (): Promise => {
return null
}
}
+
+export const sendNanoRpcRequest = async (input: any): Promise => {
+ try {
+ const { data }: AxiosResponse = await axios.post(
+ `${config.serverUrl}/rpc/nano`,
+ { input },
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ )
+ return data.data
+ } catch {
+ return null
+ }
+}
+
+export const getNanoPow = async (hash: string, type: string): Promise => {
+ try {
+ const input = { hash, type }
+ const { data } = await axios.post(
+ `${config.serverUrl}/rpc/nano/pow`,
+ { input },
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ )
+ return data.data
+ } catch {
+ return null
+ }
+}
\ No newline at end of file
diff --git a/src/utils/backup.ts b/src/utils/backup.ts
index 85360509..7d97714f 100644
--- a/src/utils/backup.ts
+++ b/src/utils/backup.ts
@@ -1,9 +1,11 @@
import { v4 } from 'uuid'
// Utils
-import { IWallet } from '@utils/wallet'
import { validateWallet } from '@utils/validate'
+// Types
+import { IWallet } from '@utils/wallet'
+
const pjson = require('../../package.json')
type TGenerateCurrency = {
@@ -45,7 +47,6 @@ export const generate = (currencies: TGenerateCurrency[]): { [key: string]: stri
wallets.push(data)
backup.wallets.push({ ...data, ...{ privateKey, mnemonic } })
}
-
return {
backup: JSON.stringify(backup),
wallets: JSON.stringify(wallets),
@@ -77,4 +78,4 @@ export const validate = (backup: string): string | null => {
}
}
return null
-}
+}
\ No newline at end of file
diff --git a/src/utils/currencies/hedera/index.ts b/src/utils/currencies/hedera/index.ts
index 8a7a9f56..88b2aeb5 100644
--- a/src/utils/currencies/hedera/index.ts
+++ b/src/utils/currencies/hedera/index.ts
@@ -2,7 +2,7 @@ import { PrivateKey, Hbar, HbarUnit, Client, TransferTransaction } from '@hashgr
import { Buffer } from 'buffer'
// Utils
-import { getHederaAccountId } from '@utils/api'
+import { activateAccount, getHederaAccountId } from '@utils/api'
// Types
import { TInternalTxProps } from '../types'
@@ -71,6 +71,12 @@ export const createInternalTx = async ({
}
}
+export const activateWallet = async (chain: string, publicKey: string) => {
+ const res = await activateAccount(chain, publicKey)
+ return res
+}
+
+
export const validateAddress = (address: string): boolean => {
try {
return new RegExp('^(0.0.)[0-9]{5,40}$').test(address)
diff --git a/src/utils/currencies/index.ts b/src/utils/currencies/index.ts
index 85198037..3f149b57 100644
--- a/src/utils/currencies/index.ts
+++ b/src/utils/currencies/index.ts
@@ -8,11 +8,14 @@ import {
getEtherNetworkFee,
getThetaNetworkFee,
getNetworkFee as getNetworkFeeRequest,
- getCustomFee,
+ getCustomFee, requestBalance
} from '@utils/api'
-import { TCustomFee } from '@utils/api/types'
import { toLower } from '@utils/format'
+// Types
+import { TProvider, TCreateTransactionProps, IGetFeeParams, TGetFeeData } from './types'
+import { IGetBalance, TCustomFee } from '@utils/api/types'
+
// Currencies
import * as ethereumLike from '@utils/currencies/ethereumLike'
import * as bitcoinLike from '@utils/currencies/bitcoinLike'
@@ -33,14 +36,28 @@ import * as vechain from '@utils/currencies/vechain'
import * as toncoin from '@utils/currencies/toncoin'
import * as digibyte from '@utils/currencies/digibyte'
import * as ravencoin from '@utils/currencies/ravencoin'
-
-// Types
-import { TProvider, TCreateTransactionProps, IGetFeeParams, TGetFeeData } from './types'
+import * as nano from '@utils/currencies/nano'
export const isEthereumLike = (symbol: string, chain?: string): boolean => {
return ethereumLike.coins.indexOf(symbol) !== -1 || typeof chain !== 'undefined'
}
+export const getBalance = async (
+ symbol: string,
+ address: string,
+ chain?: string,
+ tokenSymbol?: string,
+ contractAddress?: string,
+ isFullBalance?: boolean
+): Promise => {
+
+ if (['xno'].indexOf(symbol) !== -1) {
+ nano.updateWalletActivationStatus(address)
+ }
+
+ return await requestBalance(address, chain, tokenSymbol, contractAddress, isFullBalance)
+}
+
const getProvider = (symbol: string): TProvider | null => {
try {
if (digibyte.coins.indexOf(symbol) !== -1) {
@@ -111,12 +128,28 @@ const getProvider = (symbol: string): TProvider | null => {
return ravencoin
}
+ if (nano.coins.indexOf(symbol) !== -1) {
+ return nano
+ }
+
+
return null
} catch {
return null
}
}
+
+export const activateWallet = async (chain: string, publicKey: string, privateKey?: string): Promise => {
+ if (chain === 'xno') {
+ if (!privateKey) return null;
+ return await nano.activateWallet(chain, publicKey, privateKey)
+ }
+ if (chain === 'hedera') {
+ return await hedera.activateWallet(chain, publicKey)
+ }
+}
+
export const generate = async (
symbol: string,
chain?: string
@@ -207,6 +240,10 @@ export const createTransaction = async ({
return await cardano.createTransaction(outputs, from, to, amount, privateKey)
}
+ if (nano.coins.indexOf(symbol) !== -1) {
+ return await nano.createTransaction(from, to, amount, privateKey)
+ }
+
if (isEthereumLike(symbol, tokenChain)) {
const getContractAddress = contractAddress
? contractAddress
@@ -525,6 +562,9 @@ export const checkWithZeroFee = (symbol: string): boolean => {
if (nerve.coins.indexOf(symbol) !== -1) {
return true
}
+ if (nano.coins.indexOf(symbol) !== -1) {
+ return true
+ }
return false
}
diff --git a/src/utils/currencies/nano/index.ts b/src/utils/currencies/nano/index.ts
new file mode 100644
index 00000000..c5ab44d3
--- /dev/null
+++ b/src/utils/currencies/nano/index.ts
@@ -0,0 +1,340 @@
+import * as nano from 'nanocurrency'
+
+// Utils
+import { activateAccount, getNanoPow, sendNanoRpcRequest } from '@utils/api'
+import { setItem } from '@utils/storage'
+import { getWallets } from '@utils/wallet'
+
+// Types
+import { BlockRepresentation, ConvertParams } from 'nanocurrency'
+import {
+ TAccountInfo,
+ TActivateData,
+ TBlockInfo,
+ TProcessBlock, TQueueRequest,
+ TReceivableResponse,
+ TReceiveBlock, TRequestHandler, TRpcRequest
+} from '@utils/currencies/nano/types'
+import { IWallet } from '@utils/wallet'
+
+export const coins: string[] = ['xno']
+
+const RPC_CALL_DELAY = 200
+
+const requestHandler: TRequestHandler = {
+ _queue: [],
+ _inProgress: false,
+ add(request: TQueueRequest) {
+ this._queue.push(request)
+ if (!this._inProgress) {
+ this.run()
+ }
+ },
+
+ async run() {
+ while (this._queue.length) {
+ this._inProgress = true
+ const item = this._queue.shift()
+ if (!item) break;
+ const { request, resolver } = item
+ request().then(result => {
+ resolver(result)
+ })
+ await new Promise(res => setTimeout(res, RPC_CALL_DELAY))
+ }
+ this._inProgress = false
+ }
+}
+
+export const sendThrottledRequest = async (input: any): Promise => {
+ const request: TRpcRequest = () => sendNanoRpcRequest(input)
+ return await new Promise(async (resolver) => {
+ requestHandler.add({request, resolver})
+ })
+}
+
+export const generateWallet = async (): Promise => {
+ try {
+ const seed = await nano.generateSeed()
+ const privateKey = nano.deriveSecretKey(seed, 0)
+ const publicKey = nano.derivePublicKey(privateKey)
+ const address = nano.deriveAddress(publicKey)
+ const formatAddress = getFormatAddress(address)
+ if (address) {
+ return {
+ address: formatAddress,
+ privateKey,
+ isNotActivated: true
+ }
+ }
+ return null
+ } catch {
+ return null
+ }
+}
+
+const getFormatAddress = (address: string) => {
+ if (address.slice(0, 3).toLowerCase() === 'xrb') {
+ return 'nano' + address.slice(3)
+ }
+ return address
+}
+
+export const formatValue = (value: string | number, type: 'from' | 'to'): string => {
+ return nano.convert(`${value}`, {
+ from: type === 'from' ? 'raw' : 'Nano',
+ to: type === 'from' ? 'Nano' : 'raw'
+ })
+}
+
+export const importPrivateKey = (privateKey: string): string | null => {
+ try {
+ const publicKey = nano.derivePublicKey(privateKey)
+ const address = nano.deriveAddress(publicKey)
+
+ if (address) {
+ return address
+ }
+
+ return null
+ } catch {
+ return null
+ }
+}
+
+export const validateAddress = (address: string): boolean => nano.checkAddress(address)
+
+export const getExplorerLink = (address: string): string => {
+ return `https://nanocrawler.cc/explorer/account/${address}`
+}
+
+export const getTransactionLink = (hash: string): string => {
+ return `https://nanocrawler.cc/explorer/block/${hash}`
+}
+
+export const getPubKeyFromPriv = (privateKey: string): string | null => {
+ try {
+ const publicKey = nano.derivePublicKey(privateKey)
+
+ if (publicKey) {
+ return publicKey
+ }
+
+ return null
+ } catch {
+ return null
+ }
+}
+
+export const receiveAllPendingTxs = async (address: string, privKey: string): Promise => {
+ try {
+ let isReceived = false
+ const pubKey = nano.derivePublicKey(privKey)
+ const response = await getReceivableBlocks(address)
+
+ if (!response) return false
+
+ const receivableBlocks = response.blocks
+
+ for (const link of receivableBlocks) {
+ let response = await receiveBlock({ address, pubKey, privKey, blockHash: link })
+ if (response && response.hash !== undefined) {
+ isReceived = true
+ }
+ }
+ return isReceived
+ } catch {
+ return false
+ }
+
+}
+
+export const getStandingFee = (): number => {
+ return 0
+}
+
+const processBlock = async (block: BlockRepresentation, subtype: string): Promise => {
+ const input = {
+ action: 'process',
+ json_block: true,
+ subtype,
+ block
+ }
+ return await sendThrottledRequest(input)
+}
+
+
+const getBlockInfo = async (hash: string): Promise => {
+ const input = {
+ action: 'block_info',
+ json_block: true,
+ hash
+ }
+ return await sendThrottledRequest(input)
+}
+
+const getAccountInfo = async (address: string, representative = true): Promise => {
+ const input = {
+ action: 'account_info',
+ account: address,
+ representative
+ }
+ return await sendThrottledRequest(input)
+}
+
+const getReceivableBlocks = async (address: string, count = undefined, threshold = undefined): Promise => {
+ const input = {
+ action: 'receivable',
+ account: address,
+ count,
+ threshold
+ }
+ return await sendThrottledRequest(input)
+}
+
+export const activateWallet = async (chain: string, pubKey: string, privKey: string): Promise => {
+ try {
+ const pubKeyFromPriv = nano.derivePublicKey(privKey)
+
+ const data = await activateAccount(chain, pubKeyFromPriv)
+
+ if (data) {
+ const { hash, representative } = data
+ const address = nano.deriveAddress(pubKeyFromPriv)
+ const formatAddress = getFormatAddress(address)
+ const result = await receiveBlock({
+ address: formatAddress,
+ pubKey: pubKeyFromPriv,
+ privKey,
+ blockHash: hash,
+ walletActivation: { representative }
+ })
+ if (result) {
+ return address
+ }
+ }
+ return null
+ } catch {
+ return null
+ }
+}
+
+export const getActivationStatus = async (address: string): Promise => {
+ try {
+ const account = await getAccountInfo(address)
+ if (account) {
+ return account.balance !== undefined
+ }
+ return false
+ } catch {
+ return false
+ }
+}
+
+export const updateWalletActivationStatus = async (address: string): Promise => {
+ try {
+ const wallets = getWallets()
+ if (wallets?.length) {
+ const findWallet = wallets.find(
+ (wallet: IWallet) => wallet.address === address
+ )
+ if (!findWallet || !findWallet.isNotActivated) return false
+ const isActivated = await getActivationStatus(address)
+ if (isActivated) {
+ findWallet.isNotActivated = false
+ setItem('wallets', JSON.stringify(wallets))
+ return true
+ }
+ }
+ return false
+ } catch {
+ return false
+ }
+}
+
+const receiveBlock = async ({ address, pubKey, privKey, blockHash, walletActivation }: TReceiveBlock): Promise => {
+ try {
+ const link = blockHash
+ const blockInfo = await getBlockInfo(link)
+ let subtype = 'receive'
+
+ if (!blockInfo) return null;
+
+ let representative: string
+ let previous: string
+ let oldBalance: string
+ let workInput: string
+
+ if (walletActivation) {
+ representative = walletActivation.representative
+ workInput = pubKey
+ oldBalance = '0';
+ previous = '0'.padStart(64, '0');
+ } else {
+ const account = await getAccountInfo(address)
+ if (!account) return null;
+ representative = account.representative
+ previous = account.frontier
+ oldBalance = account.balance
+ workInput = account.frontier
+ }
+
+ const work = await getNanoPow(workInput, subtype)
+ const balance = stringAdd(oldBalance, blockInfo.amount)
+ const block = nano.createBlock(privKey, {
+ work,
+ previous,
+ representative,
+ balance,
+ link
+ })
+ return await processBlock(block.block, subtype)
+ } catch {
+ return null
+ }
+
+}
+
+export const stringSub = (n1: string, n2: string, pad = 0) => {
+ return (BigInt(n1) - BigInt(n2)).toString().padStart(pad, '0')
+}
+
+export const stringAdd = (n1: string, n2: string, pad = 0) => {
+ return (BigInt(n1) + BigInt(n2)).toString().padStart(pad, '0')
+}
+
+export const createTransaction = async (
+ fromAddress: string,
+ toAddress: string,
+ amount: string,
+ privateKey: string
+): Promise => {
+ try {
+ const account = await getAccountInfo(fromAddress)
+ if (!account) return null
+ const subtype = 'send'
+ const link = toAddress
+ const representative = account.representative
+ const previous = account.frontier
+ const oldBalance = account.balance
+ const workInput = account.frontier
+ const work = await getNanoPow(workInput, subtype)
+ const balance = stringSub(oldBalance, amount)
+ const block = nano.createBlock(privateKey, {
+ work,
+ previous,
+ representative,
+ balance,
+ link
+ })
+
+ const response = await processBlock(block.block, subtype)
+ if (response) {
+ const { hash } = response
+ return hash
+ }
+ return null
+ } catch {
+ return null
+ }
+}
\ No newline at end of file
diff --git a/src/utils/currencies/nano/types.ts b/src/utils/currencies/nano/types.ts
new file mode 100644
index 00000000..afeb7d5d
--- /dev/null
+++ b/src/utils/currencies/nano/types.ts
@@ -0,0 +1,72 @@
+export type TBlockInfo = {
+ block_account: string
+ amount: string
+ balance: string
+ height: string
+ local_timestamp: string
+ confirmed: string
+ contents: {
+ type: string
+ account: string
+ previous: string
+ representative: string
+ balance: string
+ link: string
+ link_as_account: string
+ signature: string
+ work: string
+ }
+ subtype: string
+ successor?: string
+}
+
+export type TAccountInfo = {
+ account_version: string
+ balance: string
+ block_count: string
+ confirmation_height: string
+ confirmation_height_frontier: string
+ frontier: string
+ modified_timestamp: string
+ open_block: string
+ representative: string
+ representative_block: string
+}
+
+
+export type TReceiveBlock = {
+ address: string
+ pubKey: string
+ privKey: string
+ blockHash: string
+ walletActivation?: {
+ representative: string
+ }
+}
+
+export type TActivateData = {
+ hash: string
+ representative: string
+}
+
+export type TReceivableResponse = {
+ blocks: string[]
+}
+
+export type TProcessBlock = {
+ hash: string
+}
+
+export type TRpcRequest = () => Promise
+
+export type TQueueRequest = {
+ request: TRpcRequest
+ resolver: any //
+}
+
+export type TRequestHandler = {
+ _queue: TQueueRequest[]
+ _inProgress: boolean
+ add(request: TQueueRequest): void
+ run(): void
+}
\ No newline at end of file
diff --git a/src/utils/currencies/types.ts b/src/utils/currencies/types.ts
index 0e65dc34..43e3a876 100644
--- a/src/utils/currencies/types.ts
+++ b/src/utils/currencies/types.ts
@@ -10,7 +10,7 @@ export type TProvider = {
importRecoveryPhrase?: (recoveryPhrase: string) => Promise
generateExtraId?: () => string
getStandingFee?: () => number | null
- formatValue: (value: string | number, type: 'from' | 'to') => number
+ formatValue: (value: string | number, type: 'from' | 'to') => number | string
isInternalTx?: boolean
createInternalTx?: (props: TInternalTxProps) => Promise
isWithOutputs?: boolean
diff --git a/src/utils/currencies/vechain/index.ts b/src/utils/currencies/vechain/index.ts
index e3d70b97..e6b260a7 100644
--- a/src/utils/currencies/vechain/index.ts
+++ b/src/utils/currencies/vechain/index.ts
@@ -5,7 +5,7 @@ import Web3 from 'web3'
import { thorify } from 'thorify'
// Utils
-import { getBalance, getVechainParams, getVechainFee } from '@utils/api'
+import { requestBalance, getVechainParams, getVechainFee } from '@utils/api'
import { toLower, toUnit } from '@utils/format'
// Config
@@ -68,7 +68,7 @@ export const getNetworkFee = async (
chain: string
): Promise => {
try {
- const { balance: currencyBalance } = await getBalance(from, 'vethor')
+ const { balance: currencyBalance } = await requestBalance(from, 'vethor')
if (chain === 'vechain') {
const fee = Devkit.Transaction.intrinsicGas([
diff --git a/src/utils/format.ts b/src/utils/format.ts
index 4fd86afa..35cba9f2 100644
--- a/src/utils/format.ts
+++ b/src/utils/format.ts
@@ -31,7 +31,7 @@ export const numberFriendly = (amount: number | null): number | string => {
const abbrev = 'KMB'
const round = (n: number, precision: number) => {
- var prec = Math.pow(10, precision)
+ const prec = Math.pow(10, precision)
return Math.round(n * prec) / prec
}
diff --git a/src/utils/history.ts b/src/utils/history.ts
index 0c59f656..8ae29e85 100644
--- a/src/utils/history.ts
+++ b/src/utils/history.ts
@@ -1,13 +1,14 @@
// Utils
-import { getWalletChain, getWallets } from '@utils/wallet'
+import { filterWallets, getWalletChain, getWallets } from '@utils/wallet'
import { getFullTxHistory, getFullTxHistoryInfo } from '@utils/api'
-import { compareFullHistory, saveFullHistory } from '@utils/txs'
-import { setItem } from '@utils/storage'
+import { compareFullHistory, getWalletKey, saveFullHistory } from '@utils/txs'
+import { getItem, getJSON, setItem } from '@utils/storage'
// Types
import { IWallet } from '@utils/wallet'
-import { TFullTxWallet, TTxAddressItem, TTxWallet } from '@utils/api/types'
+import { TAddressTx, TFullTxInfo, TFullTxWallet, TTxAddressItem, TTxWallet } from '@utils/api/types'
import { TGetFullTxHistoryOptions } from '@utils/api'
+import { toLower } from 'utils/format'
export type THistoryUpdateOptions = {
latest?: number
@@ -32,12 +33,11 @@ export const updateTxsHistory = async (
fetchOptions
}: THistoryUpdateOptions = {}): Promise => {
try {
- if (checkIsLoadingFlag()) return false;
+ if (checkIsLoadingFlag()) return false
setIsLoadingFlag(true)
let payload: TTxWallet[]
-
if (updateSingleWallet) {
payload = [updateSingleWallet]
} else {
@@ -58,6 +58,8 @@ export const updateTxsHistory = async (
})
}
+ // removeTempTxs(payload)
+
const data = await getFullTxHistory(payload)
if (!data.length) return false
@@ -77,7 +79,6 @@ export const updateTxsHistory = async (
contractAddress
}
})
-
const fullTxsInfo = await getFullTxHistoryInfo(mapData, fetchOptions)
saveFullHistory(fullTxsInfo)
if (!updateSingleWallet) {
@@ -87,8 +88,7 @@ export const updateTxsHistory = async (
return !!(fullTxsInfo && fullTxsInfo.length)
}
return false
- } catch (err) {
- console.error(err)
+ } catch {
return false
} finally {
setIsLoadingFlag(false)
@@ -96,3 +96,28 @@ export const updateTxsHistory = async (
}
export default updateTxsHistory
+
+
+export const removeTempTxs = (wallets: TTxWallet[] | TTxWallet) => {
+ const formatWallets = Array.isArray(wallets) ? wallets : [wallets]
+ for (const wallet of formatWallets) {
+ const { address, chain, contractAddress, symbol } = wallet
+ if (['xno'].indexOf(symbol) !== -1) {
+ // const getTokenSymbol = chain ? symbol : undefined
+ // const getChain = getWalletChain(symbol, chain)
+ const walletKey = getWalletKey(address, 'xno')
+ const walletTxs = getJSON(walletKey)
+ if (walletTxs?.length) {
+ const nonPendingTxs = walletTxs.filter((tx: TAddressTx) => !tx.isPending)
+ setItem(walletKey, JSON.stringify(nonPendingTxs))
+ }
+ const fullHistory = getJSON('full_history')
+ if (fullHistory?.length) {
+ const filteredTxs = fullHistory.filter((tx: TFullTxInfo) => {
+ return !(tx.symbol === symbol && tx.isPending);
+ })
+ setItem('full_history', JSON.stringify(filteredTxs))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/utils/txs.ts b/src/utils/txs.ts
index 25c18161..8c1ae441 100644
--- a/src/utils/txs.ts
+++ b/src/utils/txs.ts
@@ -20,7 +20,8 @@ export type THistoryTxGroup = {
data: TFullTxInfo[]
}
-const getWalletKey = (
+
+export const getWalletKey = (
address: string,
chain: string,
tokenSymbol?: string,
@@ -247,15 +248,22 @@ export const saveFullHistory = (txs: TFullTxInfo[]): void => {
return hashMatch && amountMatch && addressMatch
})
})
- let hasPendingUpdates = false
- const getUpdatedPendingTxs = getHistory.map((tx: TFullTxInfo) => {
+ // let hasPendingUpdates = false
+ const formatHistory = getHistory.filter((tx: TFullTxInfo) => {
+ if (toLower(tx.symbol) === "xno") {
+ return !tx.isPending
+ }
+ return tx
+ })
+ const getUpdatedPendingTxs = formatHistory.map((tx: TFullTxInfo) => {
const match = txs.find((newTx: TFullTxInfo) => {
const hashMatch = toLower(newTx.hash) === toLower(tx.hash)
+ const addressMatch = toLower(newTx.address) === toLower(tx.address)
const pendingStatusUpdated = tx.isPending !== newTx.isPending
- if (pendingStatusUpdated) {
- hasPendingUpdates = true
- }
- return hashMatch && pendingStatusUpdated
+ // if (pendingStatusUpdated) {
+ // hasPendingUpdates = true
+ // }
+ return hashMatch && addressMatch && pendingStatusUpdated
})
return match ? { ...tx, isPending: false } : tx
})
diff --git a/yarn.lock b/yarn.lock
index 09c6309b..9cb222fa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10592,6 +10592,14 @@ nano-json-stream-parser@^0.1.2:
resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f"
integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=
+nanocurrency@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/nanocurrency/-/nanocurrency-2.5.0.tgz#968659daadfa23150afc44a296fa3b211ffe9380"
+ integrity sha512-zMDlgBCML0vMGvldsZN1Np93vwiMjaBLCkOM2tXv0LNIpty8HghDMZiNRzfBPkP70oRhRU+hOpVCEpTzZK5gDQ==
+ dependencies:
+ bignumber.js "^9.0.0"
+ blakejs "^1.1.0"
+
nanoid@3.1.20:
version "3.1.20"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"