decane-connect-kit 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +386 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -4
- package/dist/index.d.ts +31 -4
- package/dist/index.js +386 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -80,8 +80,12 @@ function createRegistry(emitter) {
|
|
|
80
80
|
};
|
|
81
81
|
if (incoming.chain === "evm") {
|
|
82
82
|
account.evmProvider = incoming.provider;
|
|
83
|
-
} else {
|
|
83
|
+
} else if (incoming.chain === "solana") {
|
|
84
84
|
account.solanaProvider = incoming.provider;
|
|
85
|
+
} else if (incoming.chain === "tron") {
|
|
86
|
+
account.tronProvider = incoming.provider;
|
|
87
|
+
} else if (incoming.chain === "bitcoin") {
|
|
88
|
+
account.bitcoinProvider = incoming.provider;
|
|
85
89
|
}
|
|
86
90
|
return account;
|
|
87
91
|
}
|
|
@@ -92,12 +96,10 @@ function createRegistry(emitter) {
|
|
|
92
96
|
incoming.chain
|
|
93
97
|
].sort();
|
|
94
98
|
}
|
|
95
|
-
if (incoming.chain === "evm")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (incoming.chain === "
|
|
99
|
-
existing.solanaProvider = incoming.provider;
|
|
100
|
-
}
|
|
99
|
+
if (incoming.chain === "evm") existing.evmProvider = incoming.provider;
|
|
100
|
+
if (incoming.chain === "solana") existing.solanaProvider = incoming.provider;
|
|
101
|
+
if (incoming.chain === "tron") existing.tronProvider = incoming.provider;
|
|
102
|
+
if (incoming.chain === "bitcoin") existing.bitcoinProvider = incoming.provider;
|
|
101
103
|
if (!existing.icon && incoming.icon) existing.icon = incoming.icon;
|
|
102
104
|
}
|
|
103
105
|
function registerOrMerge(incoming) {
|
|
@@ -144,9 +146,9 @@ function createRegistry(emitter) {
|
|
|
144
146
|
all: () => [...wallets],
|
|
145
147
|
evm: () => wallets.filter((w) => w.chainSupport.includes("evm")),
|
|
146
148
|
solana: () => wallets.filter((w) => w.chainSupport.includes("solana")),
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
),
|
|
149
|
+
tron: () => wallets.filter((w) => w.chainSupport.includes("tron")),
|
|
150
|
+
bitcoin: () => wallets.filter((w) => w.chainSupport.includes("bitcoin")),
|
|
151
|
+
multiChain: () => wallets.filter((w) => w.chainSupport.length >= 2),
|
|
150
152
|
byId: (id) => wallets.find((w) => w.id === id)
|
|
151
153
|
}
|
|
152
154
|
};
|
|
@@ -729,11 +731,37 @@ var BUILT_IN_CHAINS = [
|
|
|
729
731
|
name: "Solana Devnet",
|
|
730
732
|
nativeCurrency: SOL,
|
|
731
733
|
blockExplorerUrl: "https://solscan.io/?cluster=devnet"
|
|
734
|
+
},
|
|
735
|
+
// ── Tron ─────────────────────────────────────────────────────────────────────
|
|
736
|
+
{
|
|
737
|
+
id: "tron:mainnet",
|
|
738
|
+
type: "tron",
|
|
739
|
+
name: "Tron",
|
|
740
|
+
nativeCurrency: { name: "Tronix", symbol: "TRX", decimals: 6 },
|
|
741
|
+
blockExplorerUrl: "https://tronscan.org"
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
id: "tron:shasta",
|
|
745
|
+
type: "tron",
|
|
746
|
+
name: "Tron Shasta Testnet",
|
|
747
|
+
nativeCurrency: { name: "Tronix", symbol: "TRX", decimals: 6 },
|
|
748
|
+
blockExplorerUrl: "https://shasta.tronscan.org",
|
|
749
|
+
isCustom: true
|
|
750
|
+
},
|
|
751
|
+
// ── Bitcoin ───────────────────────────────────────────────────────────────────
|
|
752
|
+
{
|
|
753
|
+
id: "bip122:mainnet",
|
|
754
|
+
type: "bitcoin",
|
|
755
|
+
name: "Bitcoin",
|
|
756
|
+
nativeCurrency: { name: "Bitcoin", symbol: "BTC", decimals: 8 },
|
|
757
|
+
blockExplorerUrl: "https://blockstream.info"
|
|
732
758
|
}
|
|
733
759
|
];
|
|
734
760
|
function getChainType(caip2Id) {
|
|
735
761
|
if (caip2Id.startsWith("eip155:")) return "evm";
|
|
736
762
|
if (caip2Id.startsWith("solana:")) return "solana";
|
|
763
|
+
if (caip2Id.startsWith("tron:")) return "tron";
|
|
764
|
+
if (caip2Id.startsWith("bip122:")) return "bitcoin";
|
|
737
765
|
throw new Error(`Cannot determine chain type from: ${caip2Id}`);
|
|
738
766
|
}
|
|
739
767
|
function toCAIP10(chainId, address) {
|
|
@@ -749,6 +777,14 @@ var SOLANA_METHODS = /* @__PURE__ */ new Set([
|
|
|
749
777
|
"wallet_signMessage"
|
|
750
778
|
// wallet_signTypedData is EVM-only — never included here
|
|
751
779
|
]);
|
|
780
|
+
var TRON_METHODS = /* @__PURE__ */ new Set([
|
|
781
|
+
"wallet_sendTransaction",
|
|
782
|
+
"wallet_signMessage"
|
|
783
|
+
]);
|
|
784
|
+
var BITCOIN_METHODS = /* @__PURE__ */ new Set([
|
|
785
|
+
"wallet_sendTransaction",
|
|
786
|
+
"wallet_signMessage"
|
|
787
|
+
]);
|
|
752
788
|
var CHAINS = {
|
|
753
789
|
// Tier-1
|
|
754
790
|
ETHEREUM: "eip155:1",
|
|
@@ -814,13 +850,17 @@ var CHAINS = {
|
|
|
814
850
|
LOCALHOST: "eip155:31337",
|
|
815
851
|
// Solana
|
|
816
852
|
SOLANA: "solana:mainnet",
|
|
817
|
-
SOLANA_DEVNET: "solana:devnet"
|
|
853
|
+
SOLANA_DEVNET: "solana:devnet",
|
|
854
|
+
// Tron
|
|
855
|
+
TRON: "tron:mainnet",
|
|
856
|
+
// Bitcoin
|
|
857
|
+
BITCOIN: "bip122:mainnet"
|
|
818
858
|
};
|
|
819
859
|
function validateCustomChain(chain) {
|
|
820
860
|
if (!chain || typeof chain !== "object") return false;
|
|
821
861
|
const c = chain;
|
|
822
862
|
if (typeof c.id !== "string" || !c.id) return false;
|
|
823
|
-
if (c.type !== "evm" && c.type !== "solana") return false;
|
|
863
|
+
if (c.type !== "evm" && c.type !== "solana" && c.type !== "tron" && c.type !== "bitcoin") return false;
|
|
824
864
|
if (typeof c.name !== "string" || !c.name) return false;
|
|
825
865
|
if (!c.nativeCurrency || typeof c.nativeCurrency !== "object") return false;
|
|
826
866
|
if (c.type === "evm" && (typeof c.chainId !== "number" || !c.id.startsWith("eip155:")))
|
|
@@ -1039,7 +1079,12 @@ async function walletStandardRequest(wallet, method, payload, account) {
|
|
|
1039
1079
|
);
|
|
1040
1080
|
}
|
|
1041
1081
|
}
|
|
1082
|
+
function isSolanaAccount(a) {
|
|
1083
|
+
return !a.chains?.length || a.chains.some((c) => c.startsWith("solana:"));
|
|
1084
|
+
}
|
|
1042
1085
|
async function getSolanaAddress(wallet) {
|
|
1086
|
+
const pre = wallet.accounts.find(isSolanaAccount);
|
|
1087
|
+
if (pre) return import_base.base58.encode(pre.publicKey);
|
|
1043
1088
|
const connectFeature = wallet.features["standard:connect"];
|
|
1044
1089
|
if (!connectFeature) {
|
|
1045
1090
|
throw new DecaneError(
|
|
@@ -1048,13 +1093,81 @@ async function getSolanaAddress(wallet) {
|
|
|
1048
1093
|
);
|
|
1049
1094
|
}
|
|
1050
1095
|
const { accounts } = await connectFeature.connect();
|
|
1051
|
-
|
|
1096
|
+
const solanaAccount = accounts.find(isSolanaAccount);
|
|
1097
|
+
if (!solanaAccount) {
|
|
1052
1098
|
throw new DecaneError(
|
|
1053
1099
|
4001 /* USER_REJECTED */,
|
|
1054
1100
|
"No Solana accounts returned"
|
|
1055
1101
|
);
|
|
1056
1102
|
}
|
|
1057
|
-
return import_base.base58.encode(
|
|
1103
|
+
return import_base.base58.encode(solanaAccount.publicKey);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// src/tron/adapter.ts
|
|
1107
|
+
async function getTronAddress(provider) {
|
|
1108
|
+
try {
|
|
1109
|
+
const result = await provider.request({ method: "tron_requestAccounts" });
|
|
1110
|
+
const accounts = result;
|
|
1111
|
+
if (accounts?.[0]) return accounts[0];
|
|
1112
|
+
} catch {
|
|
1113
|
+
}
|
|
1114
|
+
const result2 = await provider.request({ method: "tron_accounts" }).catch(() => null);
|
|
1115
|
+
const accounts2 = result2;
|
|
1116
|
+
if (accounts2?.[0]) return accounts2[0];
|
|
1117
|
+
throw new DecaneError(4001 /* USER_REJECTED */, "No Tron accounts returned");
|
|
1118
|
+
}
|
|
1119
|
+
async function tronRequest(provider, method, payload, account) {
|
|
1120
|
+
switch (method) {
|
|
1121
|
+
case "wallet_signMessage":
|
|
1122
|
+
return provider.request({
|
|
1123
|
+
method: "tron_signMessage",
|
|
1124
|
+
params: { message: payload }
|
|
1125
|
+
});
|
|
1126
|
+
case "wallet_sendTransaction":
|
|
1127
|
+
return provider.request({
|
|
1128
|
+
method: "tron_sendTransaction",
|
|
1129
|
+
params: { ...payload, from: account }
|
|
1130
|
+
});
|
|
1131
|
+
default:
|
|
1132
|
+
throw new DecaneError(
|
|
1133
|
+
5030 /* METHOD_NOT_SUPPORTED */,
|
|
1134
|
+
`Tron adapter: unsupported method ${method}`
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// src/bitcoin/adapter.ts
|
|
1140
|
+
async function getBitcoinAddress(provider) {
|
|
1141
|
+
const result = await provider.requestAccounts();
|
|
1142
|
+
if (!result || result.length === 0) {
|
|
1143
|
+
throw new DecaneError(4001 /* USER_REJECTED */, "No Bitcoin accounts returned");
|
|
1144
|
+
}
|
|
1145
|
+
const first = result[0];
|
|
1146
|
+
return typeof first === "string" ? first : first.address;
|
|
1147
|
+
}
|
|
1148
|
+
async function bitcoinRequest(provider, method, payload, account) {
|
|
1149
|
+
switch (method) {
|
|
1150
|
+
case "wallet_signMessage":
|
|
1151
|
+
return provider.signMessage(payload);
|
|
1152
|
+
case "wallet_sendTransaction": {
|
|
1153
|
+
const { to, value } = payload;
|
|
1154
|
+
if (provider.sendBitcoin) {
|
|
1155
|
+
return provider.sendBitcoin(to, value);
|
|
1156
|
+
}
|
|
1157
|
+
if (provider.send) {
|
|
1158
|
+
return provider.send({ to, value, from: account });
|
|
1159
|
+
}
|
|
1160
|
+
throw new DecaneError(
|
|
1161
|
+
5030 /* METHOD_NOT_SUPPORTED */,
|
|
1162
|
+
"Bitcoin wallet does not support sendBitcoin"
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
default:
|
|
1166
|
+
throw new DecaneError(
|
|
1167
|
+
5030 /* METHOD_NOT_SUPPORTED */,
|
|
1168
|
+
`Bitcoin adapter: unsupported method ${method}`
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1058
1171
|
}
|
|
1059
1172
|
|
|
1060
1173
|
// src/core/router.ts
|
|
@@ -1105,20 +1218,23 @@ function createRouter(opts) {
|
|
|
1105
1218
|
const chainType = getChainType(chainId);
|
|
1106
1219
|
if (chainType === "evm" && !connectedWallet.evmProvider) continue;
|
|
1107
1220
|
if (chainType === "solana" && !connectedWallet.solanaProvider) continue;
|
|
1221
|
+
if (chainType === "tron" && !connectedWallet.tronProvider) continue;
|
|
1222
|
+
if (chainType === "bitcoin" && !connectedWallet.bitcoinProvider) continue;
|
|
1108
1223
|
let address;
|
|
1109
1224
|
if (chainType === "evm") {
|
|
1110
1225
|
address = await getEvmAddress(connectedWallet.evmProvider);
|
|
1111
1226
|
if (chain.isCustom) {
|
|
1112
|
-
await addEthereumChain(
|
|
1113
|
-
connectedWallet.evmProvider,
|
|
1114
|
-
chain
|
|
1115
|
-
).catch(() => {
|
|
1227
|
+
await addEthereumChain(connectedWallet.evmProvider, chain).catch(() => {
|
|
1116
1228
|
});
|
|
1117
1229
|
}
|
|
1118
|
-
} else {
|
|
1230
|
+
} else if (chainType === "solana") {
|
|
1119
1231
|
address = await getSolanaAddress(connectedWallet.solanaProvider);
|
|
1232
|
+
} else if (chainType === "tron") {
|
|
1233
|
+
address = await getTronAddress(connectedWallet.tronProvider);
|
|
1234
|
+
} else {
|
|
1235
|
+
address = await getBitcoinAddress(connectedWallet.bitcoinProvider);
|
|
1120
1236
|
}
|
|
1121
|
-
const methodSet = chainType === "evm" ? EVM_METHODS : SOLANA_METHODS;
|
|
1237
|
+
const methodSet = chainType === "evm" ? EVM_METHODS : chainType === "solana" ? SOLANA_METHODS : chainType === "tron" ? TRON_METHODS : BITCOIN_METHODS;
|
|
1122
1238
|
const grantedMethods = (scope?.methods ?? []).filter(
|
|
1123
1239
|
(m) => methodSet.has(m)
|
|
1124
1240
|
);
|
|
@@ -1197,19 +1313,13 @@ function createRouter(opts) {
|
|
|
1197
1313
|
);
|
|
1198
1314
|
}
|
|
1199
1315
|
if (chainType === "evm") {
|
|
1200
|
-
return eip1193Request(
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
);
|
|
1316
|
+
return eip1193Request(wallet.evmProvider, method, payload, account);
|
|
1317
|
+
} else if (chainType === "solana") {
|
|
1318
|
+
return walletStandardRequest(wallet.solanaProvider, method, payload, account);
|
|
1319
|
+
} else if (chainType === "tron") {
|
|
1320
|
+
return tronRequest(wallet.tronProvider, method, payload, account);
|
|
1206
1321
|
} else {
|
|
1207
|
-
return
|
|
1208
|
-
wallet.solanaProvider,
|
|
1209
|
-
method,
|
|
1210
|
-
payload,
|
|
1211
|
-
account
|
|
1212
|
-
);
|
|
1322
|
+
return bitcoinRequest(wallet.bitcoinProvider, method, payload, account);
|
|
1213
1323
|
}
|
|
1214
1324
|
}
|
|
1215
1325
|
return { request };
|
|
@@ -1264,6 +1374,12 @@ function createProvider(opts) {
|
|
|
1264
1374
|
get multiChainWallets() {
|
|
1265
1375
|
return registry.get.multiChain();
|
|
1266
1376
|
},
|
|
1377
|
+
get tronWallets() {
|
|
1378
|
+
return registry.get.tron();
|
|
1379
|
+
},
|
|
1380
|
+
get bitcoinWallets() {
|
|
1381
|
+
return registry.get.bitcoin();
|
|
1382
|
+
},
|
|
1267
1383
|
// ── Connection ──────────────────────────────────────────────────────────
|
|
1268
1384
|
async connect(wallet, preferredChain) {
|
|
1269
1385
|
if (session.get()) {
|
|
@@ -1272,13 +1388,19 @@ function createProvider(opts) {
|
|
|
1272
1388
|
}
|
|
1273
1389
|
_connectedWallet = wallet;
|
|
1274
1390
|
const support = wallet.chainSupport;
|
|
1275
|
-
|
|
1391
|
+
const hasEvm = support.includes("evm") && preferredChain !== "solana" && preferredChain !== "tron" && preferredChain !== "bitcoin";
|
|
1392
|
+
const hasSol = support.includes("solana") && preferredChain !== "evm" && preferredChain !== "tron" && preferredChain !== "bitcoin";
|
|
1393
|
+
const hasTron = support.includes("tron") && preferredChain !== "evm" && preferredChain !== "solana" && preferredChain !== "bitcoin";
|
|
1394
|
+
const hasBitcoin = support.includes("bitcoin") && preferredChain !== "evm" && preferredChain !== "solana" && preferredChain !== "tron";
|
|
1395
|
+
if (hasEvm) {
|
|
1276
1396
|
_activeChain = config.defaultChain?.startsWith("eip155:") ? config.defaultChain : "eip155:1";
|
|
1277
|
-
} else {
|
|
1397
|
+
} else if (hasSol) {
|
|
1278
1398
|
_activeChain = "solana:mainnet";
|
|
1399
|
+
} else if (hasTron) {
|
|
1400
|
+
_activeChain = "tron:mainnet";
|
|
1401
|
+
} else if (hasBitcoin) {
|
|
1402
|
+
_activeChain = "bip122:mainnet";
|
|
1279
1403
|
}
|
|
1280
|
-
const hasEvm = support.includes("evm") && preferredChain !== "solana";
|
|
1281
|
-
const hasSol = support.includes("solana") && preferredChain !== "evm";
|
|
1282
1404
|
const required = {};
|
|
1283
1405
|
const optional = {};
|
|
1284
1406
|
if (hasEvm) {
|
|
@@ -1302,6 +1424,34 @@ function createProvider(opts) {
|
|
|
1302
1424
|
_activeChain = solChain;
|
|
1303
1425
|
}
|
|
1304
1426
|
}
|
|
1427
|
+
if (hasTron) {
|
|
1428
|
+
const tronChain = "tron:mainnet";
|
|
1429
|
+
const scope = {
|
|
1430
|
+
methods: ["wallet_sendTransaction", "wallet_signMessage"],
|
|
1431
|
+
accounts: [],
|
|
1432
|
+
events: []
|
|
1433
|
+
};
|
|
1434
|
+
if (hasEvm || hasSol) {
|
|
1435
|
+
optional[tronChain] = scope;
|
|
1436
|
+
} else {
|
|
1437
|
+
required[tronChain] = scope;
|
|
1438
|
+
_activeChain = tronChain;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
if (hasBitcoin) {
|
|
1442
|
+
const btcChain = "bip122:mainnet";
|
|
1443
|
+
const scope = {
|
|
1444
|
+
methods: ["wallet_sendTransaction", "wallet_signMessage"],
|
|
1445
|
+
accounts: [],
|
|
1446
|
+
events: []
|
|
1447
|
+
};
|
|
1448
|
+
if (hasEvm || hasSol || hasTron) {
|
|
1449
|
+
optional[btcChain] = scope;
|
|
1450
|
+
} else {
|
|
1451
|
+
required[btcChain] = scope;
|
|
1452
|
+
_activeChain = btcChain;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1305
1455
|
await router.request({
|
|
1306
1456
|
method: "wallet_requestPermissions",
|
|
1307
1457
|
params: [{ requiredScopes: required, optionalScopes: optional }, wallet.id]
|
|
@@ -1369,6 +1519,58 @@ function createProvider(opts) {
|
|
|
1369
1519
|
return provider;
|
|
1370
1520
|
}
|
|
1371
1521
|
|
|
1522
|
+
// src/evm/bitcoinSnap.ts
|
|
1523
|
+
var BITCOIN_SNAP_IDS = [
|
|
1524
|
+
"npm:@metamask/bitcoin-snap",
|
|
1525
|
+
"npm:@consensys/btc-snap"
|
|
1526
|
+
];
|
|
1527
|
+
async function detectBitcoinSnap(provider) {
|
|
1528
|
+
try {
|
|
1529
|
+
const snaps = await provider.request({ method: "wallet_getSnaps" });
|
|
1530
|
+
if (!snaps) return null;
|
|
1531
|
+
for (const id of BITCOIN_SNAP_IDS) {
|
|
1532
|
+
const snap = snaps[id];
|
|
1533
|
+
if (snap && snap.blocked !== true) return id;
|
|
1534
|
+
}
|
|
1535
|
+
return null;
|
|
1536
|
+
} catch {
|
|
1537
|
+
return null;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
function makeBitcoinSnapProvider(snapId, evmProvider) {
|
|
1541
|
+
function invoke(method, params) {
|
|
1542
|
+
return evmProvider.request({
|
|
1543
|
+
method: "wallet_invokeSnap",
|
|
1544
|
+
params: [{ snapId, request: { method, params } }]
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
return {
|
|
1548
|
+
async requestAccounts() {
|
|
1549
|
+
const result = await invoke("btc_getAddress").catch(() => invoke("btc_getPublicKey"));
|
|
1550
|
+
if (typeof result === "string") return [result];
|
|
1551
|
+
if (Array.isArray(result)) return result;
|
|
1552
|
+
return [];
|
|
1553
|
+
},
|
|
1554
|
+
async signMessage(message) {
|
|
1555
|
+
return invoke("btc_signMessage", [message]);
|
|
1556
|
+
},
|
|
1557
|
+
async sendBitcoin(to, value) {
|
|
1558
|
+
return invoke("btc_sendBitcoin", [{ to, satoshis: value }]);
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
async function tryRegisterBitcoinSnap(registry, name, icon, rdns, evmProvider) {
|
|
1563
|
+
const snapId = await detectBitcoinSnap(evmProvider);
|
|
1564
|
+
if (!snapId) return;
|
|
1565
|
+
registry.registerOrMerge({
|
|
1566
|
+
chain: "bitcoin",
|
|
1567
|
+
name,
|
|
1568
|
+
icon,
|
|
1569
|
+
rdns,
|
|
1570
|
+
provider: makeBitcoinSnapProvider(snapId, evmProvider)
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1372
1574
|
// src/evm/discovery.ts
|
|
1373
1575
|
function startEvmDiscovery(registry) {
|
|
1374
1576
|
if (typeof window === "undefined") return;
|
|
@@ -1388,6 +1590,14 @@ function startEvmDiscovery(registry) {
|
|
|
1388
1590
|
uuid: info.uuid,
|
|
1389
1591
|
provider
|
|
1390
1592
|
});
|
|
1593
|
+
tryRegisterBitcoinSnap(
|
|
1594
|
+
registry,
|
|
1595
|
+
info.name,
|
|
1596
|
+
info.icon,
|
|
1597
|
+
info.rdns,
|
|
1598
|
+
provider
|
|
1599
|
+
).catch(() => {
|
|
1600
|
+
});
|
|
1391
1601
|
}
|
|
1392
1602
|
);
|
|
1393
1603
|
window.dispatchEvent(new CustomEvent("eip6963:requestProvider"));
|
|
@@ -1428,6 +1638,53 @@ function startSolanaDiscovery(registry) {
|
|
|
1428
1638
|
);
|
|
1429
1639
|
}
|
|
1430
1640
|
|
|
1641
|
+
// src/tron/discovery.ts
|
|
1642
|
+
var TRONLINK_RDNS = "link.tron.tronlink";
|
|
1643
|
+
var TRONLINK_ICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTYiIGZpbGw9IiNGRjAwMTMiLz48cG9seWdvbiBwb2ludHM9IjEyLDkgMjMsMTYgMTIsMjMiIGZpbGw9IndoaXRlIi8+PC9zdmc+";
|
|
1644
|
+
function startTronDiscovery(registry) {
|
|
1645
|
+
let registered = false;
|
|
1646
|
+
function tryRegister() {
|
|
1647
|
+
if (registered || !window.tronLink) return;
|
|
1648
|
+
registered = true;
|
|
1649
|
+
registry.registerOrMerge({
|
|
1650
|
+
chain: "tron",
|
|
1651
|
+
name: "TronLink",
|
|
1652
|
+
icon: TRONLINK_ICON,
|
|
1653
|
+
rdns: TRONLINK_RDNS,
|
|
1654
|
+
provider: window.tronLink
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
tryRegister();
|
|
1658
|
+
window.addEventListener("tronLink#initialized", tryRegister, { once: true });
|
|
1659
|
+
const start = Date.now();
|
|
1660
|
+
const poll = setInterval(() => {
|
|
1661
|
+
tryRegister();
|
|
1662
|
+
if (registered || Date.now() - start > 3e3) clearInterval(poll);
|
|
1663
|
+
}, 200);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
// src/bitcoin/discovery.ts
|
|
1667
|
+
var BTC_ICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTYiIGZpbGw9IiNGNzkzMUEiLz48dGV4dCB4PSIxNi41IiB5PSIyMiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1zaXplPSIxNiIgZm9udC13ZWlnaHQ9IjcwMCIgZmlsbD0id2hpdGUiIGZvbnQtZmFtaWx5PSJBcmlhbCxzeXN0ZW0tdWkiPuKmojwvdGV4dD48L3N2Zz4=";
|
|
1668
|
+
function startBitcoinDiscovery(registry) {
|
|
1669
|
+
setTimeout(() => {
|
|
1670
|
+
const candidates = [
|
|
1671
|
+
{ name: "Unisat", rdns: "io.unisat.wallet", provider: window.unisat },
|
|
1672
|
+
// OKX shares rdns with its EVM provider — merges into the EVM entry automatically
|
|
1673
|
+
{ name: "OKX Wallet", rdns: "com.okex.okxwallet", provider: window.okxwallet?.bitcoin }
|
|
1674
|
+
];
|
|
1675
|
+
for (const { name, rdns, provider } of candidates) {
|
|
1676
|
+
if (!provider) continue;
|
|
1677
|
+
registry.registerOrMerge({
|
|
1678
|
+
chain: "bitcoin",
|
|
1679
|
+
name,
|
|
1680
|
+
icon: BTC_ICON,
|
|
1681
|
+
rdns,
|
|
1682
|
+
provider
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1685
|
+
}, 150);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1431
1688
|
// src/factory.ts
|
|
1432
1689
|
function createDecane(config = {}) {
|
|
1433
1690
|
const emitter = createEmitter();
|
|
@@ -1441,6 +1698,8 @@ function createDecane(config = {}) {
|
|
|
1441
1698
|
const router = createRouter({ registry, session, chainStore });
|
|
1442
1699
|
startEvmDiscovery(registry);
|
|
1443
1700
|
startSolanaDiscovery(registry);
|
|
1701
|
+
startTronDiscovery(registry);
|
|
1702
|
+
startBitcoinDiscovery(registry);
|
|
1444
1703
|
return createProvider({ config, registry, session, chainStore, router, emitter });
|
|
1445
1704
|
}
|
|
1446
1705
|
|
|
@@ -1608,6 +1867,67 @@ function WalletIcon({ src, name, size = 36 }) {
|
|
|
1608
1867
|
initial
|
|
1609
1868
|
);
|
|
1610
1869
|
}
|
|
1870
|
+
function EthCircle({ size }) {
|
|
1871
|
+
const s = size;
|
|
1872
|
+
return /* @__PURE__ */ import_react.default.createElement("svg", { width: s, height: s, viewBox: "0 0 16 16", fill: "none" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "8", cy: "8", r: "8", fill: "#627EEA" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: "8,2.5 11.5,8 8,9.8 4.5,8", fill: "white", fillOpacity: "0.9" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: "8,9.8 11.5,8 8,13.5", fill: "white", fillOpacity: "0.6" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: "8,9.8 4.5,8 8,13.5", fill: "white", fillOpacity: "0.8" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: "8,2.5 8,9.8 4.5,8", fill: "white", fillOpacity: "0.6" }));
|
|
1873
|
+
}
|
|
1874
|
+
function SolCircle({ size }) {
|
|
1875
|
+
const s = size;
|
|
1876
|
+
return /* @__PURE__ */ import_react.default.createElement("svg", { width: s, height: s, viewBox: "0 0 16 16", fill: "none" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "8", cy: "8", r: "8", fill: "#9945FF" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "4", y: "4.5", width: "7", height: "1.5", rx: "0.75", fill: "white", fillOpacity: "0.95" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "4", y: "7.25", width: "7", height: "1.5", rx: "0.75", fill: "white", fillOpacity: "0.95" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "4", y: "10", width: "5.5", height: "1.5", rx: "0.75", fill: "white", fillOpacity: "0.95" }));
|
|
1877
|
+
}
|
|
1878
|
+
function TronCircle({ size }) {
|
|
1879
|
+
const s = size;
|
|
1880
|
+
return /* @__PURE__ */ import_react.default.createElement("svg", { width: s, height: s, viewBox: "0 0 16 16", fill: "none" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "8", cy: "8", r: "8", fill: "#FF0013" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: "6,4.5 12,8 6,11.5", fill: "white", fillOpacity: "0.95" }));
|
|
1881
|
+
}
|
|
1882
|
+
function BitcoinCircle({ size }) {
|
|
1883
|
+
const s = size;
|
|
1884
|
+
return /* @__PURE__ */ import_react.default.createElement("svg", { width: s, height: s, viewBox: "0 0 16 16", fill: "none" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "8", cy: "8", r: "8", fill: "#F7931A" }), /* @__PURE__ */ import_react.default.createElement(
|
|
1885
|
+
"text",
|
|
1886
|
+
{
|
|
1887
|
+
x: "8.3",
|
|
1888
|
+
y: "11.5",
|
|
1889
|
+
textAnchor: "middle",
|
|
1890
|
+
fontSize: "8",
|
|
1891
|
+
fontWeight: "700",
|
|
1892
|
+
fill: "white",
|
|
1893
|
+
fontFamily: "Arial, system-ui"
|
|
1894
|
+
},
|
|
1895
|
+
"\u20BF"
|
|
1896
|
+
));
|
|
1897
|
+
}
|
|
1898
|
+
function ChainCircleIcon({ chain, size }) {
|
|
1899
|
+
switch (chain) {
|
|
1900
|
+
case "evm":
|
|
1901
|
+
return /* @__PURE__ */ import_react.default.createElement(EthCircle, { size });
|
|
1902
|
+
case "solana":
|
|
1903
|
+
return /* @__PURE__ */ import_react.default.createElement(SolCircle, { size });
|
|
1904
|
+
case "tron":
|
|
1905
|
+
return /* @__PURE__ */ import_react.default.createElement(TronCircle, { size });
|
|
1906
|
+
case "bitcoin":
|
|
1907
|
+
return /* @__PURE__ */ import_react.default.createElement(BitcoinCircle, { size });
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
var CHAIN_ORDER = ["evm", "solana", "tron", "bitcoin"];
|
|
1911
|
+
function ChainIconStack({ support, size = 16 }) {
|
|
1912
|
+
const ordered = CHAIN_ORDER.filter((c) => support.includes(c));
|
|
1913
|
+
if (ordered.length === 0) return null;
|
|
1914
|
+
const overlap = Math.round(size * 0.35);
|
|
1915
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", alignItems: "center", flexShrink: 0 } }, ordered.map((chain, i) => /* @__PURE__ */ import_react.default.createElement(
|
|
1916
|
+
"div",
|
|
1917
|
+
{
|
|
1918
|
+
key: chain,
|
|
1919
|
+
style: {
|
|
1920
|
+
marginLeft: i === 0 ? 0 : `-${overlap}px`,
|
|
1921
|
+
zIndex: ordered.length - i,
|
|
1922
|
+
position: "relative",
|
|
1923
|
+
borderRadius: "50%",
|
|
1924
|
+
lineHeight: 0,
|
|
1925
|
+
boxShadow: i > 0 ? `0 0 0 1.5px var(--dc-bg, #fff)` : void 0
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
/* @__PURE__ */ import_react.default.createElement(ChainCircleIcon, { chain, size })
|
|
1929
|
+
)));
|
|
1930
|
+
}
|
|
1611
1931
|
|
|
1612
1932
|
// src/ui/WalletSelector.tsx
|
|
1613
1933
|
var FONT_URL = "https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap";
|
|
@@ -1634,21 +1954,6 @@ function injectFont() {
|
|
|
1634
1954
|
link.href = FONT_URL;
|
|
1635
1955
|
document.head.appendChild(link);
|
|
1636
1956
|
}
|
|
1637
|
-
var badgeBase = {
|
|
1638
|
-
display: "inline-flex",
|
|
1639
|
-
alignItems: "center",
|
|
1640
|
-
padding: "3px 8px",
|
|
1641
|
-
borderRadius: 20,
|
|
1642
|
-
fontSize: 10,
|
|
1643
|
-
fontWeight: 700,
|
|
1644
|
-
letterSpacing: "0.04em",
|
|
1645
|
-
textTransform: "uppercase"
|
|
1646
|
-
};
|
|
1647
|
-
function ChainBadges({ chainSupport }) {
|
|
1648
|
-
const hasEvm = chainSupport.includes("evm");
|
|
1649
|
-
const hasSol = chainSupport.includes("solana");
|
|
1650
|
-
return /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", gap: 4 } }, hasEvm && /* @__PURE__ */ import_react2.default.createElement("span", { style: { ...badgeBase, background: "var(--dc-badge-evm)", color: "var(--dc-badge-evm-text)" } }, "EVM"), hasSol && /* @__PURE__ */ import_react2.default.createElement("span", { style: { ...badgeBase, background: "var(--dc-badge-sol)", color: "var(--dc-badge-sol-text)", border: "1px solid var(--dc-border)" } }, "SVM"));
|
|
1651
|
-
}
|
|
1652
1957
|
function WalletRow({ wallet, onClick }) {
|
|
1653
1958
|
const [hovered, setHovered] = (0, import_react2.useState)(false);
|
|
1654
1959
|
const [focused, setFocused] = (0, import_react2.useState)(false);
|
|
@@ -1678,7 +1983,7 @@ function WalletRow({ wallet, onClick }) {
|
|
|
1678
1983
|
},
|
|
1679
1984
|
/* @__PURE__ */ import_react2.default.createElement(WalletIcon, { src: wallet.icon || void 0, name: wallet.name, size: 38 }),
|
|
1680
1985
|
/* @__PURE__ */ import_react2.default.createElement("span", { style: { flex: 1, fontSize: 14, fontWeight: 600, color: "var(--dc-text)", letterSpacing: "-0.01em" } }, wallet.name),
|
|
1681
|
-
/* @__PURE__ */ import_react2.default.createElement(
|
|
1986
|
+
/* @__PURE__ */ import_react2.default.createElement(ChainIconStack, { support: wallet.chainSupport, size: 16 }),
|
|
1682
1987
|
/* @__PURE__ */ import_react2.default.createElement(
|
|
1683
1988
|
"svg",
|
|
1684
1989
|
{
|
|
@@ -1805,17 +2110,19 @@ function WalletSelector({
|
|
|
1805
2110
|
const cs = w.chainSupport;
|
|
1806
2111
|
if (networks === "evm") return cs.includes("evm");
|
|
1807
2112
|
if (networks === "solana") return cs.includes("solana");
|
|
2113
|
+
if (networks === "tron") return cs.includes("tron");
|
|
2114
|
+
if (networks === "bitcoin") return cs.includes("bitcoin");
|
|
1808
2115
|
return true;
|
|
1809
2116
|
});
|
|
1810
|
-
const baseWallets = filter === "evm" ? networkWallets.filter((w) => w.chainSupport.includes("evm")) : filter === "solana" ? networkWallets.filter((w) => w.chainSupport.includes("solana")) : networkWallets;
|
|
2117
|
+
const baseWallets = filter === "evm" ? networkWallets.filter((w) => w.chainSupport.includes("evm")) : filter === "solana" ? networkWallets.filter((w) => w.chainSupport.includes("solana")) : filter === "tron" ? networkWallets.filter((w) => w.chainSupport.includes("tron")) : filter === "bitcoin" ? networkWallets.filter((w) => w.chainSupport.includes("bitcoin")) : networkWallets;
|
|
1811
2118
|
const filtered = q ? baseWallets.filter((w) => w.name.toLowerCase().includes(q)) : baseWallets;
|
|
1812
2119
|
function handleWalletClick(wallet) {
|
|
1813
2120
|
const cs = wallet.chainSupport;
|
|
1814
|
-
const isMulti = cs.
|
|
2121
|
+
const isMulti = cs.length >= 2;
|
|
1815
2122
|
if (isMulti && networks === "all") {
|
|
1816
2123
|
setPendingWallet(wallet);
|
|
1817
2124
|
} else {
|
|
1818
|
-
const preference = networks === "evm" ? "evm" : networks === "solana" ? "solana" : void 0;
|
|
2125
|
+
const preference = networks === "evm" ? "evm" : networks === "solana" ? "solana" : networks === "tron" ? "tron" : networks === "bitcoin" ? "bitcoin" : void 0;
|
|
1819
2126
|
onConnect(wallet, preference);
|
|
1820
2127
|
onClose();
|
|
1821
2128
|
}
|
|
@@ -1950,28 +2257,44 @@ function WalletSelector({
|
|
|
1950
2257
|
},
|
|
1951
2258
|
/* @__PURE__ */ import_react2.default.createElement(WalletIcon, { src: pendingWallet.icon || void 0, name: pendingWallet.name, size: 36 }),
|
|
1952
2259
|
/* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("div", { style: { fontSize: 14, fontWeight: 700, color: "var(--dc-text)" } }, pendingWallet.name), /* @__PURE__ */ import_react2.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 2 } }, "Multi-chain wallet detected"))
|
|
1953
|
-
), /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: "0 12px 20px", display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react2.default.createElement(
|
|
2260
|
+
), /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: "0 12px 20px", display: "flex", flexDirection: "column", gap: 8 } }, pendingWallet.chainSupport.includes("evm") && /* @__PURE__ */ import_react2.default.createElement(
|
|
1954
2261
|
ChainOption,
|
|
1955
2262
|
{
|
|
1956
2263
|
label: "EVM networks",
|
|
1957
2264
|
description: "Connect your Ethereum-compatible address only",
|
|
1958
|
-
badges: /* @__PURE__ */ import_react2.default.createElement(
|
|
2265
|
+
badges: /* @__PURE__ */ import_react2.default.createElement(ChainIconStack, { support: ["evm"], size: 18 }),
|
|
1959
2266
|
onClick: () => handleChainChoice("evm")
|
|
1960
2267
|
}
|
|
1961
|
-
), /* @__PURE__ */ import_react2.default.createElement(
|
|
2268
|
+
), pendingWallet.chainSupport.includes("solana") && /* @__PURE__ */ import_react2.default.createElement(
|
|
1962
2269
|
ChainOption,
|
|
1963
2270
|
{
|
|
1964
2271
|
label: "Solana network",
|
|
1965
2272
|
description: "Connect your Solana address only",
|
|
1966
|
-
badges: /* @__PURE__ */ import_react2.default.createElement(
|
|
2273
|
+
badges: /* @__PURE__ */ import_react2.default.createElement(ChainIconStack, { support: ["solana"], size: 18 }),
|
|
1967
2274
|
onClick: () => handleChainChoice("solana")
|
|
1968
2275
|
}
|
|
2276
|
+
), pendingWallet.chainSupport.includes("tron") && /* @__PURE__ */ import_react2.default.createElement(
|
|
2277
|
+
ChainOption,
|
|
2278
|
+
{
|
|
2279
|
+
label: "Tron network",
|
|
2280
|
+
description: "Connect your Tron address only",
|
|
2281
|
+
badges: /* @__PURE__ */ import_react2.default.createElement(ChainIconStack, { support: ["tron"], size: 18 }),
|
|
2282
|
+
onClick: () => handleChainChoice("tron")
|
|
2283
|
+
}
|
|
2284
|
+
), pendingWallet.chainSupport.includes("bitcoin") && /* @__PURE__ */ import_react2.default.createElement(
|
|
2285
|
+
ChainOption,
|
|
2286
|
+
{
|
|
2287
|
+
label: "Bitcoin network",
|
|
2288
|
+
description: "Connect your Bitcoin address only",
|
|
2289
|
+
badges: /* @__PURE__ */ import_react2.default.createElement(ChainIconStack, { support: ["bitcoin"], size: 18 }),
|
|
2290
|
+
onClick: () => handleChainChoice("bitcoin")
|
|
2291
|
+
}
|
|
1969
2292
|
), /* @__PURE__ */ import_react2.default.createElement(
|
|
1970
2293
|
ChainOption,
|
|
1971
2294
|
{
|
|
1972
|
-
label: "
|
|
1973
|
-
description: "Connect
|
|
1974
|
-
badges: /* @__PURE__ */ import_react2.default.createElement(
|
|
2295
|
+
label: "All networks",
|
|
2296
|
+
description: "Connect all supported addresses together",
|
|
2297
|
+
badges: /* @__PURE__ */ import_react2.default.createElement(ChainIconStack, { support: pendingWallet.chainSupport, size: 18 }),
|
|
1975
2298
|
onClick: () => handleChainChoice(void 0)
|
|
1976
2299
|
}
|
|
1977
2300
|
)))
|
|
@@ -2046,7 +2369,7 @@ function WalletSelector({
|
|
|
2046
2369
|
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
2047
2370
|
}
|
|
2048
2371
|
}
|
|
2049
|
-
)), networks === "all" && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", gap: 4, marginBottom: 10 } }, /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "All", active: filter === "all", onClick: () => setFilter("all") }), /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "EVM", active: filter === "evm", onClick: () => setFilter("evm") }), /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "Solana", active: filter === "solana", onClick: () => setFilter("solana") }))), /* @__PURE__ */ import_react2.default.createElement("div", { style: { overflowY: "auto", flex: 1, padding: "0 12px 20px" } }, filtered.length > 0 ? /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((w) => /* @__PURE__ */ import_react2.default.createElement(WalletRow, { key: w.id, wallet: w, onClick: () => handleWalletClick(w) }))) : /* @__PURE__ */ import_react2.default.createElement("div", { style: { textAlign: "center", padding: "32px 16px", color: "var(--dc-text-muted)", fontSize: 13 } }, q ? `No wallets matching "${q}"` : "No wallets detected")), /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: "10px 20px 14px", borderTop: "1px solid var(--dc-border)", textAlign: "center", fontSize: 11, color: "var(--dc-text-muted)" } }, "Don't see your wallet? Make sure it's installed and unlocked"))
|
|
2372
|
+
)), networks === "all" && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", gap: 4, marginBottom: 10 } }, /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "All", active: filter === "all", onClick: () => setFilter("all") }), /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "EVM", active: filter === "evm", onClick: () => setFilter("evm") }), /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "Solana", active: filter === "solana", onClick: () => setFilter("solana") }), provider.tronWallets && provider.tronWallets.length > 0 && /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "Tron", active: filter === "tron", onClick: () => setFilter("tron") }), provider.bitcoinWallets && provider.bitcoinWallets.length > 0 && /* @__PURE__ */ import_react2.default.createElement(FilterTab, { label: "Bitcoin", active: filter === "bitcoin", onClick: () => setFilter("bitcoin") }))), /* @__PURE__ */ import_react2.default.createElement("div", { style: { overflowY: "auto", flex: 1, padding: "0 12px 20px" } }, filtered.length > 0 ? /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((w) => /* @__PURE__ */ import_react2.default.createElement(WalletRow, { key: w.id, wallet: w, onClick: () => handleWalletClick(w) }))) : /* @__PURE__ */ import_react2.default.createElement("div", { style: { textAlign: "center", padding: "32px 16px", color: "var(--dc-text-muted)", fontSize: 13 } }, q ? `No wallets matching "${q}"` : "No wallets detected")), /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: "10px 20px 14px", borderTop: "1px solid var(--dc-border)", textAlign: "center", fontSize: 11, color: "var(--dc-text-muted)" } }, "Don't see your wallet? Make sure it's installed and unlocked"))
|
|
2050
2373
|
)
|
|
2051
2374
|
)
|
|
2052
2375
|
);
|