diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..50ec69c6
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "cSpell.words": ["bitcoinmainnet", "txslight"]
+}
diff --git a/src/api/extension/index.js b/src/api/extension/index.js
index 6e151167..abc1d180 100644
--- a/src/api/extension/index.js
+++ b/src/api/extension/index.js
@@ -163,9 +163,54 @@ export const getPoolMetadata = async (poolId) => {
};
};
+export const getBtcBalance = async (addr, node = NODE.bitcoinmainnet) => {
+ const result = await blockfrostRequest(
+ `/address/${addr}`,
+ undefined,
+ undefined,
+ undefined,
+ node
+ );
+ if (result.error) {
+ if (result.status_code === 400) throw APIError.InvalidRequest;
+ else if (result.status_code === 500) throw APIError.InternalError;
+ else return '0';
+ }
+
+ console.log('result.balance', result.balance);
+ return result.balance;
+};
+
export const getBalance = async () => {
await Loader.load();
const currentAccount = await getCurrentAccount();
+
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet ||
+ network.id === NETWORK_ID.dogecoinmainnet ||
+ network.id === NETWORK_ID.litecoinmainnet
+ ) {
+ const addr = await selectBitcoinAccountAddress();
+
+ const result = await blockfrostRequest(`/address/${addr}`);
+ if (result.error) {
+ if (result.status_code === 400) throw APIError.InvalidRequest;
+ else if (result.status_code === 500) throw APIError.InternalError;
+ else return Loader.Cardano.Value.new(Loader.Cardano.BigNum.from_str('0'));
+ }
+
+ const value = await assetsToValue([
+ {
+ unit: 'lovelace',
+ quantity: result.balance,
+ },
+ ]);
+ return value;
+ }
+
const result = await blockfrostRequest(
`/addresses/${currentAccount.paymentKeyHashBech32}`
);
@@ -180,9 +225,36 @@ export const getBalance = async () => {
export const getBalanceExtended = async () => {
const currentAccount = await getCurrentAccount();
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet ||
+ network.id === NETWORK_ID.dogecoinmainnet ||
+ network.id === NETWORK_ID.litecoinmainnet
+ ) {
+ const addr = await selectBitcoinAccountAddress();
+
+ const result = await blockfrostRequest(`/address/${addr}`);
+ if (result.error) {
+ if (result.status_code === 400) throw APIError.InvalidRequest;
+ else if (result.status_code === 500) throw APIError.InternalError;
+ else return [];
+ }
+ return [
+ {
+ unit: 'lovelace',
+ quantity: result.balance,
+ decimals: 8,
+ has_nft_onchain_metadata: false,
+ },
+ ];
+ }
+
const result = await blockfrostRequest(
`/addresses/${currentAccount.paymentKeyHashBech32}/extended`
);
+
if (result.error) {
if (result.status_code === 400) throw APIError.InvalidRequest;
else if (result.status_code === 500) throw APIError.InternalError;
@@ -202,8 +274,52 @@ export const getFullBalance = async () => {
).toString();
};
+export const selectBitcoinAccountAddress = async () => {
+ const currentAccount = await getCurrentAccount();
+ const network = await getNetwork();
+
+ if (network.id === NETWORK_ID.bitcoinmainnet) {
+ return currentAccount.bitcoinmainnet.paymentAddr;
+ } else if (network.id === NETWORK_ID.bitcointestnet) {
+ return currentAccount.bitcointestnet.paymentAddr;
+ } else if (network.id === NETWORK_ID.dogecoinmainnet) {
+ return currentAccount.dogecoinmainnet.paymentAddr;
+ } else if (network.id === NETWORK_ID.litecoinmainnet) {
+ return currentAccount.litecoinmainnet.paymentAddr;
+ }
+};
+
export const getTransactions = async (paginate = 1, count = 10) => {
const currentAccount = await getCurrentAccount();
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ const addr = await selectBitcoinAccountAddress();
+
+ const result = await blockfrostRequest(
+ `/address/${addr}?details=txslight&page=${paginate}`
+ );
+
+ return [
+ {
+ txHash:
+ '9b151508940dbdb104d6811d79ca1407e8eb3004c651b63b2b9f3250a79aaa10',
+ txIndex: 0,
+ blockHeight: 3005927,
+ },
+ ];
+
+ if (!result || result.error) return [];
+ return result.transactions.map((tx) => ({
+ txHash: tx.txid,
+ txIndex: 0,
+ blockHeight: tx.blockHeight,
+ }));
+ }
+
const result = await blockfrostRequest(
`/addresses/${currentAccount.paymentKeyHashBech32}/transactions?page=${paginate}&order=desc&count=${count}`
);
@@ -216,24 +332,143 @@ export const getTransactions = async (paginate = 1, count = 10) => {
};
export const getTxInfo = async (txHash) => {
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ return {
+ hash: '9b151508940dbdb104d6811d79ca1407e8eb3004c651b63b2b9f3250a79aaa10',
+ block: '0000000068fedf9bf1eb29f28e38ccbe7e0b0107b72443489ec32e3b3fad63c1',
+ block_height: 123456,
+ block_time: 1635505891,
+ slot: 42000000,
+ index: 1,
+ output_amount: [
+ {
+ unit: 'lovelace',
+ quantity: '42000000',
+ },
+ {
+ unit: 'b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e',
+ quantity: '12',
+ },
+ ],
+ fees: '182485',
+ deposit: '0',
+ size: 433,
+ invalid_before: null,
+ invalid_hereafter: '13885913',
+ utxo_count: 4,
+ withdrawal_count: 0,
+ mir_cert_count: 0,
+ delegation_count: 0,
+ stake_cert_count: 0,
+ pool_update_count: 0,
+ pool_retire_count: 0,
+ asset_mint_or_burn_count: 0,
+ redeemer_count: 0,
+ valid_contract: true,
+ };
+
+ const result = await blockfrostRequest(`/tx-specific/${txHash}`);
+ if (!result || result.error) return null;
+ return result;
+ }
+
const result = await blockfrostRequest(`/txs/${txHash}`);
if (!result || result.error) return null;
return result;
};
export const getBlock = async (blockHashOrNumb) => {
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ const result = await blockfrostRequest(`/block/${blockHashOrNumb}`);
+ if (!result || result.error) return null;
+ return result;
+ }
+
const result = await blockfrostRequest(`/blocks/${blockHashOrNumb}`);
if (!result || result.error) return null;
return result;
};
export const getTxUTxOs = async (txHash) => {
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ const result = await blockfrostRequest(`/tx-specific/${txHash}`);
+ // if (!result || result.error) return [];
+ return [
+ {
+ address: 'n3EmnmHcFAsWutzthg54v26mEaxGsDM6WX',
+ tx_hash:
+ '9b151508940dbdb104d6811d79ca1407e8eb3004c651b63b2b9f3250a79aaa10',
+ output_index: 0,
+ amount: [
+ {
+ unit: 'lovelace',
+ quantity: '12345678',
+ },
+ ],
+ block:
+ '7eb8e27d18686c7db9a18f8bbcfe34e3fed6e047afaa2d969904d15e934847e6',
+ data_hash: null,
+ inline_datum: null,
+ reference_script_hash: null,
+ inputs: [
+ {
+ address: 'n3EmnmHcFAsWutzthg54v26mEaxGsDM6WX',
+ amount: [
+ {
+ unit: 'lovelace',
+ quantity: '14656250',
+ },
+ ],
+ tx_hash:
+ 'e852cdcff2c866a49e44a0edf310563c0844c286917cd9407b7fae6332ccb11f',
+ },
+ ],
+ outputs: [
+ {
+ address: 'n3EmnmHcFAsWutzthg54v26mEaxGsDM6WX',
+ amount: [
+ {
+ unit: 'lovelace',
+ quantity: '14570750',
+ },
+ ],
+ output_index: 0,
+ },
+ ],
+ },
+ ];
+ }
+
const result = await blockfrostRequest(`/txs/${txHash}/utxos`);
if (!result || result.error) return null;
return result;
};
export const getTxMetadata = async (txHash) => {
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ return null;
+ }
+
const result = await blockfrostRequest(`/txs/${txHash}/metadata`);
if (!result || result.error) return null;
return result;
@@ -278,6 +513,15 @@ export const setTxDetail = async (txObject) => {
};
export const getSpecificUtxo = async (txHash, txId) => {
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ return null;
+ }
+
const result = await blockfrostRequest(`/txs/${txHash}/utxos`);
if (!result || result.error) return null;
return result.outputs[txId];
@@ -293,6 +537,16 @@ export const getSpecificUtxo = async (txHash, txId) => {
*/
export const getUtxos = async (amount = undefined, paginate = undefined) => {
const currentAccount = await getCurrentAccount();
+
+ const network = await getNetwork();
+
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ return [];
+ }
+
let result = [];
let page = paginate && paginate.page ? paginate.page + 1 : 1;
const limit = paginate && paginate.limit ? `&count=${paginate.limit}` : '';
@@ -350,6 +604,13 @@ export const getUtxos = async (amount = undefined, paginate = undefined) => {
};
const checkCollateral = async (currentAccount, network, checkTx) => {
+ if (
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ) {
+ return;
+ }
+
if (checkTx) {
const transactions = await getTransactions();
if (
@@ -474,6 +735,12 @@ export const setNetwork = async (network) => {
} else if (network.id === NETWORK_ID.preview) {
id = NETWORK_ID.preview;
node = NODE.preview;
+ } else if (network.id === NETWORK_ID.bitcoinmainnet) {
+ id = NETWORK_ID.bitcoinmainnet;
+ node = NODE.bitcoinmainnet;
+ } else if (network.id === NETWORK_ID.bitcoitestnet) {
+ id = NETWORK_ID.bitcoitestnet;
+ node = NODE.bitcoitestnet;
} else {
id = NETWORK_ID.preprod;
node = NODE.preprod;
@@ -493,6 +760,18 @@ export const setNetwork = async (network) => {
};
const accountToNetworkSpecific = (account, network) => {
+ // if (!account[network.id]) {
+ // account[network.id] = {
+ // lovelace: null,
+ // minAda: 0,
+ // assets: [],
+ // history: { confirmed: [], details: {} },
+ // paymentAddr: 'bc1q36fsqr0pl9sky30ex9y3tta3sg4ag9wd3f0gdq',
+ // paymentAddr: 'bc1q36fsqr0pl9sky30ex9y3tta3sg4ag9wd3f0gdq',
+ // rewardAddr: null,
+ // };
+ // }
+
const assets = account[network.id].assets;
const lovelace = account[network.id].lovelace;
const history = account[network.id].history;
@@ -1338,6 +1617,13 @@ export const createAccount = async (name, password, accountIndex = null) => {
history: { confirmed: [], details: {} },
};
+ const btcBalance = await getBtcBalance(
+ 'bc1p7l2cywf6qr9gwca3vsv6mwdlkfl3f7agw9kdm98re7jmn087q86suc2lpk',
+ NODE.bitcoinmainnet
+ );
+
+ // console.log('btcBalance', btcBalance);
+
const newAccount = {
[index]: {
index,
@@ -1366,6 +1652,22 @@ export const createAccount = async (name, password, accountIndex = null) => {
paymentAddr: paymentAddrTestnet,
rewardAddr: rewardAddrTestnet,
},
+ [NETWORK_ID.bitcoinmainnet]: {
+ ...networkDefault,
+ paymentAddr:
+ 'bc1p7l2cywf6qr9gwca3vsv6mwdlkfl3f7agw9kdm98re7jmn087q86suc2lpk',
+ rewardAddr: rewardAddrTestnet,
+ lovelace: btcBalance,
+ },
+ [NETWORK_ID.dogecoinmainnet]: {
+ ...networkDefault,
+ paymentAddr: 'DGZVagHvLrGv3bCjk6Yb1bLriFLKuhfEJg',
+ rewardAddr: rewardAddrTestnet,
+ lovelace: await getBtcBalance(
+ 'DGZVagHvLrGv3bCjk6Yb1bLriFLKuhfEJg',
+ NODE.dogecoinmainnet
+ ),
+ },
avatar: Math.random().toString(),
},
};
@@ -1558,12 +1860,12 @@ export const getAdaHandle = async (assetName) => {
const network = await getNetwork();
if (!network) return null;
let handleUrl;
- switch (network.id){
+ switch (network.id) {
case 'mainnet':
- handleUrl = 'https://api.handle.me'
+ handleUrl = 'https://api.handle.me';
break;
case 'preprod':
- handleUrl = 'https://preprod.api.handle.me'
+ handleUrl = 'https://preprod.api.handle.me';
break;
default:
return null;
@@ -1769,7 +2071,9 @@ export const getAsset = async (unit) => {
const metadata = metadataDatum && Data.toJson(metadataDatum.fields[0]);
asset.displayName = metadata.name;
- asset.image = metadata.image ? linkToSrc(convertMetadataPropToString(metadata.image)) : '';
+ asset.image = metadata.image
+ ? linkToSrc(convertMetadataPropToString(metadata.image))
+ : '';
asset.decimals = 0;
} catch (_e) {
asset.displayName = asset.name;
@@ -1796,7 +2100,8 @@ export const getAsset = async (unit) => {
const metadata = metadataDatum && Data.toJson(metadataDatum.fields[0]);
asset.displayName = metadata.name;
- asset.image = linkToSrc(convertMetadataPropToString(metadata.logo)) || '';
+ asset.image =
+ linkToSrc(convertMetadataPropToString(metadata.logo)) || '';
asset.decimals = metadata.decimals || 0;
} catch (_e) {
asset.displayName = asset.name;
@@ -1961,6 +2266,22 @@ export const updateAccount = async (forceUpdate = false) => {
await updateBalance(currentAccount, network);
+ console.log('before update balance', currentAccount);
+ console.log(
+ 'updating btc balance',
+ currentAccount['bitcoinmainnet'].paymentAddr
+ );
+ currentAccount['bitcoinmainnet'].lovelace = await getBtcBalance(
+ currentAccount['bitcoinmainnet'].paymentAddr,
+ NODE.bitcoinmainnet
+ );
+ currentAccount['dogecoinmainnet'].lovelace = await getBtcBalance(
+ currentAccount['dogecoinmainnet'].paymentAddr,
+ NODE.dogecoinmainnet
+ );
+
+ console.log('after update balance', currentAccount);
+
currentAccount[network.id].lastUpdate =
currentAccount[network.id].history.confirmed[0];
diff --git a/src/api/util.js b/src/api/util.js
index f7e29e9d..f43abfcd 100644
--- a/src/api/util.js
+++ b/src/api/util.js
@@ -43,7 +43,7 @@ export async function delay(delayInMs) {
});
}
-export async function blockfrostRequest(endpoint, headers, body, signal) {
+export async function blockfrostRequest(endpoint, headers, body, signal, node) {
const network = await getNetwork();
let result;
@@ -51,17 +51,21 @@ export async function blockfrostRequest(endpoint, headers, body, signal) {
if (result) {
await delay(100);
}
- const rawResult = await fetch(provider.api.base(network.node) + endpoint, {
- headers: {
- ...provider.api.key(network.name || network.id),
- ...provider.api.header,
- ...headers,
- 'Cache-Control': 'no-cache',
- },
- method: body ? 'POST' : 'GET',
- body,
- signal,
- });
+ console.log('url', provider.api.base(node ?? network.node) + endpoint);
+ const rawResult = await fetch(
+ provider.api.base(node ?? network.node) + endpoint,
+ {
+ headers: {
+ ...provider.api.key(network.name || network.id),
+ ...provider.api.header,
+ ...headers,
+ 'Cache-Control': 'no-cache',
+ },
+ method: body ? 'POST' : 'GET',
+ body,
+ signal,
+ }
+ );
result = await rawResult.json();
}
@@ -91,6 +95,8 @@ export const networkNameToId = (name) => {
[NETWORK_ID.testnet]: 0,
[NETWORK_ID.preview]: 0,
[NETWORK_ID.preprod]: 0,
+ [NETWORK_ID.bitcoinmainnet]: 2,
+ [NETWORK_ID.bitcointestnet]: 3,
};
return names[name];
};
diff --git a/src/config/config.js b/src/config/config.js
index 58b92666..2bf362e9 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -71,6 +71,12 @@ export const NODE = {
testnet: 'https://cardano-testnet.blockfrost.io/api/v0',
preview: 'https://cardano-preview.blockfrost.io/api/v0',
preprod: 'https://cardano-preprod.blockfrost.io/api/v0',
+ bitcoinmainnet: 'https://btc1.trezor.io/api/v2',
+ dogecoinmainnet: 'https://doge1.trezor.io/api/v2',
+ litecoinmainnet: 'https://ltc1.trezor.io/api/v2',
+ bitcointestnet: 'https://tbtc1.trezor.io/api/v2',
+ // bitcoinmainnet:
+ // 'https://bitcoin1.mainnet.core.blockfrost.io/blockbook/api/v2',
};
export const NETWORK_ID = {
@@ -78,6 +84,10 @@ export const NETWORK_ID = {
testnet: 'testnet',
preview: 'preview',
preprod: 'preprod',
+ bitcoinmainnet: 'bitcoinmainnet',
+ dogecoinmainnet: 'dogecoinmainnet',
+ litecoinmainnet: 'litecoinmainnet',
+ bitcointestnet: 'bitcointestnet',
};
export const NETWORKD_ID_NUMBER = {
@@ -85,6 +95,10 @@ export const NETWORKD_ID_NUMBER = {
testnet: 0,
preview: 0,
preprod: 0,
+ bitcoinmainnet: 2,
+ bitcointestnet: 3,
+ litecoinmainnet: 4,
+ dogecoinmainnet: 5,
};
export const POPUP = {
diff --git a/src/config/provider.js b/src/config/provider.js
index 67b9860c..6de8b2c1 100644
--- a/src/config/provider.js
+++ b/src/config/provider.js
@@ -7,6 +7,8 @@ const networkToProjectId = {
testnet: secrets.PROJECT_ID_TESTNET,
preprod: secrets.PROJECT_ID_PREPROD,
preview: secrets.PROJECT_ID_PREVIEW,
+ btcmainnet: secrets.PROJECT_ID_BTCMAINNET,
+ btctestnet: secrets.PROJECT_ID_BTCTESTNET,
};
export default {
@@ -17,6 +19,12 @@ export default {
key: (network = 'mainnet') => ({
project_id: networkToProjectId[network],
}),
+ priceBTC: (currency = 'usd') =>
+ fetch(
+ `https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=${currency}`
+ )
+ .then((res) => res.json())
+ .then((res) => res.bitcoin[currency]),
price: (currency = 'usd') =>
fetch(
`https://api.coingecko.com/api/v3/simple/price?ids=cardano&vs_currencies=${currency}`
diff --git a/src/features/analytics/config.ts b/src/features/analytics/config.ts
index 16161880..689bbcd8 100644
--- a/src/features/analytics/config.ts
+++ b/src/features/analytics/config.ts
@@ -1,6 +1,6 @@
export const PUBLIC_POSTHOG_HOST = 'https://eu.posthog.com';
-export const PRODUCTION_TRACKING_MODE_ENABLED = 'true';
+export const PRODUCTION_TRACKING_MODE_ENABLED = 'false';
export const POSTHOG_API_KEY =
'phc_5dRKCjaa549fL0kqSKAGz4tRvjHzQuaxVSrdmigUpBe';
diff --git a/src/ui/app/components/asset.jsx b/src/ui/app/components/asset.jsx
index 89c9169a..dff54376 100644
--- a/src/ui/app/components/asset.jsx
+++ b/src/ui/app/components/asset.jsx
@@ -13,7 +13,7 @@ import Copy from './copy';
import UnitDisplay from './unitDisplay';
import { useNavigate } from 'react-router-dom';
import { BsArrowUpRight } from 'react-icons/bs';
-import { getAsset } from '../../../api/extension';
+import { getAsset, getNetwork } from '../../../api/extension';
const useIsMounted = () => {
const isMounted = React.useRef(false);
@@ -24,6 +24,19 @@ const useIsMounted = () => {
return isMounted;
};
+export const getDisplayName = (assetUnit: string) => {
+ if (assetUnit === 'bitcoin') {
+ return 'BTC';
+ };
+ if (assetUnit === 'doge') {
+ return 'DOGE';
+ };
+ if (assetUnit === 'litecoin') {
+ return 'LTC';
+ };
+ return 'NA';
+}
+
const Asset = ({ asset, enableSend, ...props }) => {
const isMounted = useIsMounted();
const [token, setToken] = React.useState(null);
@@ -36,29 +49,43 @@ const Asset = ({ asset, enableSend, ...props }) => {
const navigate = useNavigate();
const settings = useStoreState((state) => state.settings.settings);
+
const fetchMetadata = async () => {
+ const isBitcoin = asset.unit === 'bitcoin' || asset.unit === 'doge';
let detailedConstructedAsset;
- if (asset.unit !== 'lovelace') {
- detailedConstructedAsset = await getAsset(asset.unit);
- }
+ if (isBitcoin) {
+ if (!isMounted.current) return;
+
+ const detailedAsset = {
+ ...asset,
+ displayName: getDisplayName(asset.unit),
+ decimals: 8,
+ };
- const detailedAsset =
- asset.unit === 'lovelace'
- ? {
- ...asset,
- displayName: 'Ada',
- decimals: 6,
- }
- : {
- ...detailedConstructedAsset,
- quantity: asset.quantity,
- input: asset.input,
- fingerprint:
- asset.fingerprint ?? detailedConstructedAsset.fingerprint,
- };
- if (!isMounted.current) return;
- setToken(detailedAsset);
+ setToken(detailedAsset);
+ } else {
+ if (asset.unit !== 'lovelace') {
+ detailedConstructedAsset = await getAsset(asset.unit);
+ }
+
+ const detailedAsset =
+ asset.unit === 'lovelace'
+ ? {
+ ...asset,
+ displayName: 'Ada',
+ decimals: 6,
+ }
+ : {
+ ...detailedConstructedAsset,
+ quantity: asset.quantity,
+ input: asset.input,
+ fingerprint:
+ asset.fingerprint ?? detailedConstructedAsset.fingerprint,
+ };
+ if (!isMounted.current) return;
+ setToken(detailedAsset);
+ }
};
React.useEffect(() => {
@@ -91,27 +118,77 @@ const Asset = ({ asset, enableSend, ...props }) => {
width="full"
src={token.image}
fallback={
- !token.image ? (
- token.unit === 'lovelace' ? (
-
- {settings.adaSymbol}
-
- ) : (
-
- )
- ) : (
-
- )
+ <>
+ {token.image && (
+
+ )}
+
+ {token.unit === 'lovelace' && (
+
+ {settings.adaSymbol}
+
+ )}
+
+ {token.unit === 'bitcoin' && (
+
+ ₿
+
+ )}
+
+ {token.unit === 'doge' && (
+
+ Ð
+
+ )}
+
+ {token.unit === 'litecoin' && (
+
+ Ł
+
+ )}
+
+ {token.unit !== 'lovelace' && token.unit !== 'doge' && token.unit !== 'bitcoin' && token.unit !== 'litecoin' && }
+ >
}
/>
diff --git a/src/ui/app/components/assetsViewer.jsx b/src/ui/app/components/assetsViewer.jsx
index 1f21de45..5b38b1d8 100644
--- a/src/ui/app/components/assetsViewer.jsx
+++ b/src/ui/app/components/assetsViewer.jsx
@@ -22,6 +22,7 @@ const AssetsViewer = ({ assets }) => {
const [assetsArray, setAssetsArray] = React.useState(null);
const [search, setSearch] = React.useState('');
const [total, setTotal] = React.useState(0);
+
const createArray = async () => {
if (!assets) {
setAssetsArray(null);
diff --git a/src/ui/app/components/historyViewer.jsx b/src/ui/app/components/historyViewer.jsx
index 17a95d91..ba08a513 100644
--- a/src/ui/app/components/historyViewer.jsx
+++ b/src/ui/app/components/historyViewer.jsx
@@ -23,6 +23,61 @@ const HistoryViewer = ({ history, network, currentAddr, addresses }) => {
const [page, setPage] = React.useState(1);
const [final, setFinal] = React.useState(false);
const [loadNext, setLoadNext] = React.useState(false);
+
+ const getBitcoinTx = (txHash, chain, amount, blockTime = 1727431131) => {
+ return {
+ block: {
+ confirmations: 0,
+ hash: txHash,
+ height: 2522850,
+ time: blockTime,
+ },
+ info: {
+ chain: chain,
+ block:
+ '016ea9f25fbd19e1fc777eb1211d00d756cf51d40f3b0aa3dbae9309f1bfad51',
+ block_height: 2522850,
+ block_time: blockTime,
+ deposit: '0',
+ fees: '200000',
+ hash: txHash,
+ output_amount: [
+ {
+ quantity: '2000000000',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ metadata: [],
+ utxos: {
+ hash: txHash,
+ inputs: [
+ {
+ address:
+ 'addr_test1vqeux7xwusdju9dvsj8h7mca9aup2k439kfmwy773xxc2hcu7zy99',
+ amount: [
+ {
+ quantity: '13000200000',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ ],
+ outputs: [
+ {
+ address: currentAddr,
+ amount: [
+ {
+ quantity: amount,
+ unit: 'lovelace',
+ },
+ ],
+ },
+ ],
+ },
+ };
+ };
+
const getTxs = async () => {
if (!history) {
slice = [];
@@ -37,7 +92,22 @@ const HistoryViewer = ({ history, network, currentAddr, addresses }) => {
);
if (slice.length < page * BATCH) {
- const txs = await getTransactions(page, BATCH);
+ let txs = await getTransactions(page, BATCH);
+
+ txs = txs.concat([
+ {
+ txHash:
+ '9b151508940dbdb104d6811d79ca1407e8eb3004c651b63b2b9f3250a79aaa10',
+ txIndex: 0,
+ blockHeight: 2522850,
+ },
+ {
+ txHash:
+ '52014d1f6f16f60306c25526ff79d375ec2cdfcfb406a876065229f0014d68b0',
+ txIndex: 0,
+ blockHeight: 2522850,
+ },
+ ]);
if (txs.length <= 0) {
setFinal(true);
@@ -102,8 +172,31 @@ const HistoryViewer = ({ history, network, currentAddr, addresses }) => {
}}
>
{historySlice.map((txHash, index) => {
+ // console.log('history.details[txHash]', history.details[txHash]);
if (!history.details[txHash]) history.details[txHash] = {};
+ console.log('history.details[txHash] ', history.details[txHash]);
+ switch (txHash) {
+ case '9b151508940dbdb104d6811d79ca1407e8eb3004c651b63b2b9f3250a79aaa10':
+ history.details[txHash] = getBitcoinTx(
+ txHash,
+ 'bitcoin',
+ 14300000,
+ 1727231131
+ );
+ break;
+ case '52014d1f6f16f60306c25526ff79d375ec2cdfcfb406a876065229f0014d68b0':
+ history.details[txHash] = getBitcoinTx(
+ txHash,
+ 'dogecoin',
+ 500000000,
+ 1726431131
+ );
+ break;
+ default:
+ break;
+ }
+
return (
{
@@ -115,6 +208,7 @@ const HistoryViewer = ({ history, network, currentAddr, addresses }) => {
currentAddr={currentAddr}
addresses={addresses}
network={network}
+ chain={history.details[txHash]?.info?.chain}
/>
);
})}
diff --git a/src/ui/app/components/transaction.jsx b/src/ui/app/components/transaction.jsx
index a23f8526..021e0e86 100644
--- a/src/ui/app/components/transaction.jsx
+++ b/src/ui/app/components/transaction.jsx
@@ -90,6 +90,7 @@ const Transaction = ({
currentAddr,
addresses,
network,
+ chain,
onLoad,
}) => {
const settings = useStoreState((state) => state.settings.settings);
@@ -98,13 +99,61 @@ const Transaction = ({
genDisplayInfo(txHash, detail, currentAddr, addresses)
);
- const colorMode = {
- iconBg: useColorModeValue('white', 'gray.800'),
- txBg: useColorModeValue('teal.50', 'gray.700'),
- txBgHover: useColorModeValue('teal.100', 'gray.600'),
- assetsBtnHover: useColorModeValue('teal.200', 'gray.700'),
+ const getColorMode = (chain) => {
+ if (chain === 'bitcoin') {
+ return {
+ iconBg: useColorModeValue('white', 'gray.800'),
+ txBg: useColorModeValue('orange.100', 'gray.700'),
+ txBgHover: useColorModeValue('orange.200', 'gray.600'),
+ assetsBtnHover: useColorModeValue('orange.200', 'gray.700'),
+ };
+ }
+
+ if (chain === 'litecoin') {
+ return {
+ iconBg: useColorModeValue('white', 'gray.800'),
+ txBg: useColorModeValue('blue.50', 'gray.700'),
+ txBgHover: useColorModeValue('blue.100', 'gray.600'),
+ assetsBtnHover: useColorModeValue('blue.200', 'gray.700'),
+ };
+ }
+
+ if (chain === 'dogecoin') {
+ return {
+ iconBg: useColorModeValue('white', 'gray.800'),
+ txBg: useColorModeValue('yellow.100', 'gray.700'),
+ txBgHover: useColorModeValue('yellow.200', 'gray.600'),
+ assetsBtnHover: useColorModeValue('yellow.200', 'gray.700'),
+ };
+ }
+
+ return {
+ iconBg: useColorModeValue('white', 'gray.800'),
+ txBg: useColorModeValue('teal.50', 'gray.700'),
+ txBgHover: useColorModeValue('teal.100', 'gray.600'),
+ assetsBtnHover: useColorModeValue('teal.200', 'gray.700'),
+ };
};
+ const getSymbol = (chain) => {
+ switch (chain) {
+ case 'bitcoin':
+ return '₿';
+ case 'litecoin':
+ return 'Ł';
+
+ case 'dogecoin':
+ return 'Ð';
+
+ case 'litecoin':
+ return 'Ł';
+ default:
+ return settings.adaSymbol;
+ }
+ };
+
+ const colorMode = getColorMode(chain);
+
const getTxDetail = async () => {
if (!displayInfo) {
let txDetail = await updateTxInfo(txHash);
@@ -172,8 +221,8 @@ const Transaction = ({
: txTypeColor.externalOut
}
quantity={displayInfo.lovelace}
- decimals={6}
- symbol={settings.adaSymbol}
+ decimals={chain ? 8 : 6}
+ symbol={getSymbol(chain)}
/>
) : displayInfo.extra.length ? (
@@ -237,7 +286,11 @@ const Transaction = ({
)}
{displayInfo && (
-
+
)}
@@ -306,7 +359,7 @@ const TxIcon = ({ txType, extra }) => {
);
};
-const TxDetail = ({ displayInfo, network }) => {
+const TxDetail = ({ displayInfo, network, chain }) => {
const capture = useCaptureEvent();
const colorMode = {
extraDetail: useColorModeValue('black', 'white'),
@@ -330,6 +383,17 @@ const TxDetail = ({ displayInfo, network }) => {
color="teal"
href={
(() => {
+ switch (chain) {
+ case 'bitcoin':
+ return 'https://blockchair.com/bitcoin/transaction/';
+ case 'litecoin':
+ return 'https://blockchair.com/litecoin/transaction/';
+ case 'dogecoin':
+ return 'https://blockchair.com/dogecoin/transaction/';
+ default:
+ break;
+ }
+
switch (network.id) {
case NETWORK_ID.mainnet:
return 'https://cardanoscan.io/transaction/';
diff --git a/src/ui/app/pages/settings.jsx b/src/ui/app/pages/settings.jsx
index 6887e309..4ea2b365 100644
--- a/src/ui/app/pages/settings.jsx
+++ b/src/ui/app/pages/settings.jsx
@@ -47,6 +47,7 @@ import { ChangePasswordModal } from '../components/changePasswordModal';
import { useCaptureEvent } from '../../../features/analytics/hooks';
import { Events } from '../../../features/analytics/events';
import { LegalSettings } from '../../../features/settings/legal/LegalSettings';
+import { getNetworkSymbol } from '../../store';
const Settings = () => {
const navigate = useNavigate();
@@ -484,19 +485,24 @@ const Network = () => {
const id = e.target.value;
- setSettings({
+ const s = {
...settings,
network: {
...settings.network,
id: NETWORK_ID[id],
node: NODE[id],
+ adaSymbol: getNetworkSymbol(settings.network.id),
},
- });
+ };
+
+ setSettings(s);
}}
>
-
-
-
+
+
+
+
+
diff --git a/src/ui/app/pages/wallet.jsx b/src/ui/app/pages/wallet.jsx
index 5732d4df..6086bf6a 100644
--- a/src/ui/app/pages/wallet.jsx
+++ b/src/ui/app/pages/wallet.jsx
@@ -197,14 +197,18 @@ const Wallet = () => {
currentAccount.nft.push(asset);
else currentAccount.ft.push(asset);
});
+ const network = await getNetwork();
let price = fiatPrice.current;
try {
if (!fiatPrice.current) {
- price = await provider.api.price(settings.currency);
+ price =
+ network.id === NETWORK_ID.bitcoinmainnet ||
+ network.id === NETWORK_ID.bitcointestnet
+ ? await provider.api.priceBTC(settings.currency)
+ : await provider.api.price(settings.currency);
fiatPrice.current = price;
}
} catch (e) {}
- const network = await getNetwork();
const delegation = await getDelegation();
if (!isMounted.current) return;
setState((s) => ({
@@ -231,6 +235,23 @@ const Wallet = () => {
};
}, []);
+ const isBitcoin = state.network.id.startsWith('bitcoin');
+
+ console.log('TU state.account', state.account);
+ const btcAssets = [
+ {
+ unit: 'bitcoin',
+ quantity: state.account?.bitcoinmainnet.lovelace ?? '0',
+ },
+ { unit: 'doge', quantity: state.account?.dogecoinmainnet.lovelace ?? '0' },
+ ];
+
+ console.log('btcAssets', btcAssets);
+ console.log(
+ 'state.account.bitcoinmainnet.lovelace',
+ state.account?.bitcoinmainnet.lovelace
+ );
+
return (
<>
{
>
{Object.keys(info.accounts).map((accountIndex) => {
const accountInfo = info.accounts[accountIndex];
+
const account =
state.accounts && state.accounts[accountIndex];
return (
@@ -404,7 +426,7 @@ const Wallet = () => {
)
).toString()
}
- decimals={6}
+ decimals={isBitcoin ? 8 : 6}
symbol={settings.adaSymbol}
/>
) : (
@@ -540,7 +562,7 @@ const Wallet = () => {
)
).toString()
}
- decimals={6}
+ decimals={isBitcoin ? 8 : 6}
symbol={settings.adaSymbol}
/>
{state.account &&
@@ -593,13 +615,53 @@ const Wallet = () => {
''
)}
+ {/* Bitcoin */}
+
+
+ {/* Doge */}
+
+
+
+
{
? state.account.collateral.lovelace
: 0
)
- ).toString()
+ ).toString(),
+ isBitcoin ? 8 : 6
) *
state.fiatPrice *
10 ** 2
@@ -744,7 +807,11 @@ const Wallet = () => {
-
+
{
}
onClick={() => {
capture(Events.OnboardingCreateEnterPassphraseNextClick);
@@ -378,7 +377,7 @@ const ImportSeed = () => {
else setAllValid(false);
};
- React.useEffect(() => {
+ React.useEffect(() => {
verifyAll();
}, [input]);
diff --git a/src/ui/store.jsx b/src/ui/store.jsx
index 68d19cb3..fed4be42 100644
--- a/src/ui/store.jsx
+++ b/src/ui/store.jsx
@@ -29,6 +29,19 @@ import ConfirmModal from './app/components/confirmModal';
import { UpgradeModal } from './app/components/UpgradeModal';
import { sendStore } from './app/pages/send';
+export const getNetworkSymbol = (networkId) => {
+ if (
+ networkId === NETWORK_ID.bitcoinmainnet ||
+ networkId === NETWORK_ID.bitcointestnet
+ ) {
+ return '₿';
+ } else if (networkId === NETWORK_ID.mainnet) {
+ return '₳';
+ } else {
+ return 't₳';
+ }
+};
+
const settings = {
settings: null,
setSettings: action((state, settings) => {
@@ -36,7 +49,7 @@ const settings = {
setNetwork(settings.network);
state.settings = {
...settings,
- adaSymbol: settings.network.id === NETWORK_ID.mainnet ? '₳' : 't₳',
+ adaSymbol: getNetworkSymbol(settings.network.id),
};
}),
};
@@ -62,7 +75,7 @@ const initSettings = async (setSettings) => {
setSettings({
currency: currency || 'usd',
network: network || { id: NETWORK_ID.mainnet, node: NODE.mainnet },
- adaSymbol: network ? (network.id === NETWORK_ID.mainnet ? '₳' : 't₳') : '₳',
+ adaSymbol: getNetworkSymbol(network?.id),
});
};