feat(dapp-v2): integrates solana + RPC methods
This commit is contained in:
parent
86ef897b4c
commit
863e0f8bf8
@ -35,6 +35,7 @@
|
|||||||
"@walletconnect/utils": "2.0.0-beta.23",
|
"@walletconnect/utils": "2.0.0-beta.23",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"blockies-ts": "^1.0.0",
|
"blockies-ts": "^1.0.0",
|
||||||
|
"bs58": "^5.0.0",
|
||||||
"caip-api": "^2.0.0-beta.1",
|
"caip-api": "^2.0.0-beta.1",
|
||||||
"cosmos-wallet": "^1.1.0",
|
"cosmos-wallet": "^1.1.0",
|
||||||
"eth-sig-util": "^2.5.3",
|
"eth-sig-util": "^2.5.3",
|
||||||
@ -45,6 +46,7 @@
|
|||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "^4.0.3",
|
"react-scripts": "^4.0.3",
|
||||||
|
"solana-wallet": "^1.0.1",
|
||||||
"styled-components": "^5.2.0",
|
"styled-components": "^5.2.0",
|
||||||
"typescript": "^4.3.2",
|
"typescript": "^4.3.2",
|
||||||
"web-vitals": "^0.2.4"
|
"web-vitals": "^0.2.4"
|
||||||
|
@ -6,8 +6,8 @@ import Blockchain from "./components/Blockchain";
|
|||||||
import Column from "./components/Column";
|
import Column from "./components/Column";
|
||||||
import Header from "./components/Header";
|
import Header from "./components/Header";
|
||||||
import Modal from "./components/Modal";
|
import Modal from "./components/Modal";
|
||||||
import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants";
|
import { DEFAULT_MAIN_CHAINS, DEFAULT_SOLANA_METHODS, DEFAULT_TEST_CHAINS } from "./constants";
|
||||||
import { AccountAction, getLocalStorageTestnetFlag, setLocaleStorageTestnetFlag } from "./helpers";
|
import { AccountAction, setLocaleStorageTestnetFlag } from "./helpers";
|
||||||
import Toggle from "./components/Toggle";
|
import Toggle from "./components/Toggle";
|
||||||
import RequestModal from "./modals/RequestModal";
|
import RequestModal from "./modals/RequestModal";
|
||||||
import PairingModal from "./modals/PairingModal";
|
import PairingModal from "./modals/PairingModal";
|
||||||
@ -26,8 +26,6 @@ import { useWalletConnectClient } from "./contexts/ClientContext";
|
|||||||
import { useJsonRpc } from "./contexts/JsonRpcContext";
|
import { useJsonRpc } from "./contexts/JsonRpcContext";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag());
|
|
||||||
|
|
||||||
const [modal, setModal] = useState("");
|
const [modal, setModal] = useState("");
|
||||||
|
|
||||||
const closeModal = () => setModal("");
|
const closeModal = () => setModal("");
|
||||||
@ -50,7 +48,17 @@ export default function App() {
|
|||||||
} = useWalletConnectClient();
|
} = useWalletConnectClient();
|
||||||
|
|
||||||
// Use `JsonRpcContext` to provide us with relevant RPC methods and states.
|
// Use `JsonRpcContext` to provide us with relevant RPC methods and states.
|
||||||
const { chainData, ping, ethereumRpc, cosmosRpc, isRpcRequestPending, rpcResult } = useJsonRpc();
|
const {
|
||||||
|
chainData,
|
||||||
|
ping,
|
||||||
|
ethereumRpc,
|
||||||
|
cosmosRpc,
|
||||||
|
solanaRpc,
|
||||||
|
isRpcRequestPending,
|
||||||
|
rpcResult,
|
||||||
|
isTestnet,
|
||||||
|
setIsTestnet,
|
||||||
|
} = useJsonRpc();
|
||||||
|
|
||||||
// Close the pairing modal after a session is established.
|
// Close the pairing modal after a session is established.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -122,6 +130,21 @@ export default function App() {
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getSolanaActions = (): AccountAction[] => {
|
||||||
|
const onSignTransaction = async (chainId: string, address: string) => {
|
||||||
|
openRequestModal();
|
||||||
|
await solanaRpc.testSignTransaction(chainId, address);
|
||||||
|
};
|
||||||
|
const onSignMessage = async (chainId: string, address: string) => {
|
||||||
|
openRequestModal();
|
||||||
|
await solanaRpc.testSignMessage(chainId, address);
|
||||||
|
};
|
||||||
|
return [
|
||||||
|
{ method: DEFAULT_SOLANA_METHODS.SOL_SIGN_TRANSACTION, callback: onSignTransaction },
|
||||||
|
{ method: DEFAULT_SOLANA_METHODS.SOL_SIGN_MESSAGE, callback: onSignMessage },
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
const getBlockchainActions = (chainId: string) => {
|
const getBlockchainActions = (chainId: string) => {
|
||||||
const [namespace] = chainId.split(":");
|
const [namespace] = chainId.split(":");
|
||||||
switch (namespace) {
|
switch (namespace) {
|
||||||
@ -129,6 +152,8 @@ export default function App() {
|
|||||||
return getEthereumActions();
|
return getEthereumActions();
|
||||||
case "cosmos":
|
case "cosmos":
|
||||||
return getCosmosActions();
|
return getCosmosActions();
|
||||||
|
case "solana":
|
||||||
|
return getSolanaActions();
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,24 @@
|
|||||||
|
import { ChainsMap } from "caip-api";
|
||||||
import { NamespaceMetadata, ChainMetadata } from "../helpers";
|
import { NamespaceMetadata, ChainMetadata } from "../helpers";
|
||||||
|
|
||||||
|
// TODO: add `solana` namespace to `caip-api` package to avoid manual specification here.
|
||||||
|
export const SolanaChainData: ChainsMap = {
|
||||||
|
"4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ": {
|
||||||
|
id: "solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ",
|
||||||
|
name: "Solana Mainnet",
|
||||||
|
rpc: ["https://api.mainnet-beta.solana.com", "https://solana-api.projectserum.com"],
|
||||||
|
slip44: 501,
|
||||||
|
testnet: false,
|
||||||
|
},
|
||||||
|
"8E9rvCKLFQia2Y35HXjjpWzj8weVo44K": {
|
||||||
|
id: "solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K",
|
||||||
|
name: "Solana Devnet",
|
||||||
|
rpc: ["https://api.devnet.solana.com"],
|
||||||
|
slip44: 501,
|
||||||
|
testnet: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const SolanaMetadata: NamespaceMetadata = {
|
export const SolanaMetadata: NamespaceMetadata = {
|
||||||
// Solana Mainnet
|
// Solana Mainnet
|
||||||
"4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ": {
|
"4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ": {
|
||||||
|
@ -10,6 +10,8 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_APP_METADATA,
|
DEFAULT_APP_METADATA,
|
||||||
DEFAULT_COSMOS_METHODS,
|
DEFAULT_COSMOS_METHODS,
|
||||||
@ -17,9 +19,11 @@ import {
|
|||||||
DEFAULT_LOGGER,
|
DEFAULT_LOGGER,
|
||||||
DEFAULT_PROJECT_ID,
|
DEFAULT_PROJECT_ID,
|
||||||
DEFAULT_RELAY_URL,
|
DEFAULT_RELAY_URL,
|
||||||
|
DEFAULT_SOLANA_METHODS,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import { AccountBalances, apiGetAccountBalance } from "../helpers";
|
import { AccountBalances, apiGetAccountBalance } from "../helpers";
|
||||||
import { ERROR, getAppMetadata } from "@walletconnect/utils";
|
import { ERROR, getAppMetadata } from "@walletconnect/utils";
|
||||||
|
import { getPublicKeysFromAccounts } from "../helpers/solana";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
@ -33,6 +37,7 @@ interface IContext {
|
|||||||
chains: string[];
|
chains: string[];
|
||||||
pairings: string[];
|
pairings: string[];
|
||||||
accounts: string[];
|
accounts: string[];
|
||||||
|
solanaPublicKeys?: Record<string, PublicKey>;
|
||||||
balances: AccountBalances;
|
balances: AccountBalances;
|
||||||
isFetchingBalances: boolean;
|
isFetchingBalances: boolean;
|
||||||
setChains: any;
|
setChains: any;
|
||||||
@ -56,6 +61,7 @@ export function ClientContextProvider({ children }: { children: ReactNode | Reac
|
|||||||
|
|
||||||
const [balances, setBalances] = useState<AccountBalances>({});
|
const [balances, setBalances] = useState<AccountBalances>({});
|
||||||
const [accounts, setAccounts] = useState<string[]>([]);
|
const [accounts, setAccounts] = useState<string[]>([]);
|
||||||
|
const [solanaPublicKeys, setSolanaPublicKeys] = useState<Record<string, PublicKey>>();
|
||||||
const [chains, setChains] = useState<string[]>([]);
|
const [chains, setChains] = useState<string[]>([]);
|
||||||
|
|
||||||
const resetApp = () => {
|
const resetApp = () => {
|
||||||
@ -110,6 +116,8 @@ export function ClientContextProvider({ children }: { children: ReactNode | Reac
|
|||||||
return DEFAULT_EIP155_METHODS;
|
return DEFAULT_EIP155_METHODS;
|
||||||
case "cosmos":
|
case "cosmos":
|
||||||
return DEFAULT_COSMOS_METHODS;
|
return DEFAULT_COSMOS_METHODS;
|
||||||
|
case "solana":
|
||||||
|
return Object.values(DEFAULT_SOLANA_METHODS);
|
||||||
default:
|
default:
|
||||||
throw new Error(`No default methods for namespace: ${namespace}`);
|
throw new Error(`No default methods for namespace: ${namespace}`);
|
||||||
}
|
}
|
||||||
@ -119,11 +127,12 @@ export function ClientContextProvider({ children }: { children: ReactNode | Reac
|
|||||||
return supportedMethods;
|
return supportedMethods;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSessionConnected = useCallback(async (incomingSession: SessionTypes.Settled) => {
|
const onSessionConnected = useCallback(async (_session: SessionTypes.Settled) => {
|
||||||
setSession(incomingSession);
|
setSession(_session);
|
||||||
setChains(incomingSession.permissions.blockchain.chains);
|
setChains(_session.permissions.blockchain.chains);
|
||||||
setAccounts(incomingSession.state.accounts);
|
setAccounts(_session.state.accounts);
|
||||||
await getAccountBalances(incomingSession.state.accounts);
|
setSolanaPublicKeys(getPublicKeysFromAccounts(_session.state.accounts));
|
||||||
|
await getAccountBalances(_session.state.accounts);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const connect = useCallback(
|
const connect = useCallback(
|
||||||
@ -135,6 +144,7 @@ export function ClientContextProvider({ children }: { children: ReactNode | Reac
|
|||||||
try {
|
try {
|
||||||
const supportedNamespaces = getSupportedNamespaces();
|
const supportedNamespaces = getSupportedNamespaces();
|
||||||
const methods = getSupportedMethods(supportedNamespaces);
|
const methods = getSupportedMethods(supportedNamespaces);
|
||||||
|
|
||||||
const session = await client.connect({
|
const session = await client.connect({
|
||||||
metadata: getAppMetadata() || DEFAULT_APP_METADATA,
|
metadata: getAppMetadata() || DEFAULT_APP_METADATA,
|
||||||
pairing,
|
pairing,
|
||||||
@ -254,6 +264,7 @@ export function ClientContextProvider({ children }: { children: ReactNode | Reac
|
|||||||
balances,
|
balances,
|
||||||
isFetchingBalances,
|
isFetchingBalances,
|
||||||
accounts,
|
accounts,
|
||||||
|
solanaPublicKeys,
|
||||||
chains,
|
chains,
|
||||||
client,
|
client,
|
||||||
session,
|
session,
|
||||||
@ -267,6 +278,7 @@ export function ClientContextProvider({ children }: { children: ReactNode | Reac
|
|||||||
balances,
|
balances,
|
||||||
isFetchingBalances,
|
isFetchingBalances,
|
||||||
accounts,
|
accounts,
|
||||||
|
solanaPublicKeys,
|
||||||
chains,
|
chains,
|
||||||
client,
|
client,
|
||||||
session,
|
session,
|
||||||
|
@ -2,18 +2,24 @@ import { BigNumber, utils } from "ethers";
|
|||||||
import { createContext, ReactNode, useContext, useEffect, useState } from "react";
|
import { createContext, ReactNode, useContext, useEffect, useState } from "react";
|
||||||
import * as encoding from "@walletconnect/encoding";
|
import * as encoding from "@walletconnect/encoding";
|
||||||
import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet";
|
import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet";
|
||||||
|
import bs58 from "bs58";
|
||||||
|
import { verifyMessageSignature } from "solana-wallet";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChainNamespaces,
|
ChainNamespaces,
|
||||||
eip712,
|
eip712,
|
||||||
formatTestTransaction,
|
formatTestTransaction,
|
||||||
getAllChainNamespaces,
|
getAllChainNamespaces,
|
||||||
|
getLocalStorageTestnetFlag,
|
||||||
hashPersonalMessage,
|
hashPersonalMessage,
|
||||||
verifySignature,
|
verifySignature,
|
||||||
} from "../helpers";
|
} from "../helpers";
|
||||||
import { useWalletConnectClient } from "./ClientContext";
|
import { useWalletConnectClient } from "./ClientContext";
|
||||||
import { apiGetChainNamespace, ChainsMap } from "caip-api";
|
import { apiGetChainNamespace, ChainsMap } from "caip-api";
|
||||||
import { TypedDataField } from "@ethersproject/abstract-signer";
|
import { TypedDataField } from "@ethersproject/abstract-signer";
|
||||||
|
import { DEFAULT_SOLANA_METHODS } from "../constants";
|
||||||
|
import { clusterApiUrl, Connection, Keypair, SystemProgram, Transaction } from "@solana/web3.js";
|
||||||
|
import { SolanaChainData } from "../chains/solana";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
@ -45,9 +51,15 @@ interface IContext {
|
|||||||
testSignDirect: TRpcRequestCallback;
|
testSignDirect: TRpcRequestCallback;
|
||||||
testSignAmino: TRpcRequestCallback;
|
testSignAmino: TRpcRequestCallback;
|
||||||
};
|
};
|
||||||
|
solanaRpc: {
|
||||||
|
testSignMessage: TRpcRequestCallback;
|
||||||
|
testSignTransaction: TRpcRequestCallback;
|
||||||
|
};
|
||||||
chainData: ChainNamespaces;
|
chainData: ChainNamespaces;
|
||||||
rpcResult?: IRpcResult | null;
|
rpcResult?: IRpcResult | null;
|
||||||
isRpcRequestPending: boolean;
|
isRpcRequestPending: boolean;
|
||||||
|
isTestnet: boolean;
|
||||||
|
setIsTestnet: (isTestnet: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,8 +74,9 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
|
|||||||
const [pending, setPending] = useState(false);
|
const [pending, setPending] = useState(false);
|
||||||
const [result, setResult] = useState<IRpcResult | null>();
|
const [result, setResult] = useState<IRpcResult | null>();
|
||||||
const [chainData, setChainData] = useState<ChainNamespaces>({});
|
const [chainData, setChainData] = useState<ChainNamespaces>({});
|
||||||
|
const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag());
|
||||||
|
|
||||||
const { client, session, accounts, balances } = useWalletConnectClient();
|
const { client, session, accounts, balances, solanaPublicKeys } = useWalletConnectClient();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadChainData();
|
loadChainData();
|
||||||
@ -76,7 +89,11 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
|
|||||||
namespaces.map(async namespace => {
|
namespaces.map(async namespace => {
|
||||||
let chains: ChainsMap | undefined;
|
let chains: ChainsMap | undefined;
|
||||||
try {
|
try {
|
||||||
chains = await apiGetChainNamespace(namespace);
|
if (namespace === "solana") {
|
||||||
|
chains = SolanaChainData;
|
||||||
|
} else {
|
||||||
|
chains = await apiGetChainNamespace(namespace);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore error
|
// ignore error
|
||||||
}
|
}
|
||||||
@ -85,6 +102,7 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
setChainData(chainData);
|
setChainData(chainData);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -437,6 +455,112 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -------- SOLANA RPC METHODS --------
|
||||||
|
|
||||||
|
const solanaRpc = {
|
||||||
|
testSignTransaction: _createJsonRpcRequestHandler(
|
||||||
|
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
|
||||||
|
if (!solanaPublicKeys) {
|
||||||
|
throw new Error("Could not find Solana PublicKeys.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const senderPublicKey = solanaPublicKeys[address];
|
||||||
|
|
||||||
|
const connection = new Connection(clusterApiUrl(isTestnet ? "testnet" : "mainnet-beta"));
|
||||||
|
|
||||||
|
// Using deprecated `getRecentBlockhash` over `getLatestBlockhash` here, since `mainnet-beta`
|
||||||
|
// cluster only seems to support `connection.getRecentBlockhash` currently.
|
||||||
|
const { blockhash } = await connection.getRecentBlockhash();
|
||||||
|
|
||||||
|
const transaction = new Transaction({
|
||||||
|
feePayer: senderPublicKey,
|
||||||
|
recentBlockhash: blockhash,
|
||||||
|
}).add(
|
||||||
|
SystemProgram.transfer({
|
||||||
|
fromPubkey: senderPublicKey,
|
||||||
|
toPubkey: Keypair.generate().publicKey,
|
||||||
|
lamports: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { signature } = await client!.request({
|
||||||
|
topic: session!.topic,
|
||||||
|
request: {
|
||||||
|
method: DEFAULT_SOLANA_METHODS.SOL_SIGN_TRANSACTION,
|
||||||
|
params: {
|
||||||
|
feePayer: transaction.feePayer!.toBase58(),
|
||||||
|
recentBlockhash: transaction.recentBlockhash,
|
||||||
|
instructions: transaction.instructions.map(i => ({
|
||||||
|
programId: i.programId.toBase58(),
|
||||||
|
data: bs58.encode(i.data),
|
||||||
|
keys: i.keys.map(k => ({
|
||||||
|
isSigner: k.isSigner,
|
||||||
|
isWritable: k.isWritable,
|
||||||
|
pubkey: k.pubkey.toBase58(),
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// We only need `Buffer.from` here to satisfy the `Buffer` param type for `addSignature`.
|
||||||
|
// The resulting `UInt8Array` is equivalent to just `bs58.decode(...)`.
|
||||||
|
transaction.addSignature(senderPublicKey, Buffer.from(bs58.decode(signature)));
|
||||||
|
|
||||||
|
const valid = transaction.verifySignatures();
|
||||||
|
|
||||||
|
return {
|
||||||
|
method: DEFAULT_SOLANA_METHODS.SOL_SIGN_TRANSACTION,
|
||||||
|
address,
|
||||||
|
valid,
|
||||||
|
result: signature,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
testSignMessage: _createJsonRpcRequestHandler(
|
||||||
|
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
|
||||||
|
if (!solanaPublicKeys) {
|
||||||
|
throw new Error("Could not find Solana PublicKeys.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const senderPublicKey = solanaPublicKeys[address];
|
||||||
|
|
||||||
|
// Encode message to `UInt8Array` first via `TextEncoder` so we can pass it to `bs58.encode`.
|
||||||
|
const message = bs58.encode(
|
||||||
|
new TextEncoder().encode(`This is an example message to be signed - ${Date.now()}`),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { signature } = await client!.request({
|
||||||
|
topic: session!.topic,
|
||||||
|
request: {
|
||||||
|
method: DEFAULT_SOLANA_METHODS.SOL_SIGN_MESSAGE,
|
||||||
|
params: {
|
||||||
|
pubkey: senderPublicKey.toBase58(),
|
||||||
|
message,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const valid = verifyMessageSignature(senderPublicKey.toBase58(), signature, message);
|
||||||
|
|
||||||
|
return {
|
||||||
|
method: DEFAULT_SOLANA_METHODS.SOL_SIGN_MESSAGE,
|
||||||
|
address,
|
||||||
|
valid,
|
||||||
|
result: signature,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JsonRpcContext.Provider
|
<JsonRpcContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@ -444,8 +568,11 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
|
|||||||
ping,
|
ping,
|
||||||
ethereumRpc,
|
ethereumRpc,
|
||||||
cosmosRpc,
|
cosmosRpc,
|
||||||
|
solanaRpc,
|
||||||
rpcResult: result,
|
rpcResult: result,
|
||||||
isRpcRequestPending: pending,
|
isRpcRequestPending: pending,
|
||||||
|
isTestnet,
|
||||||
|
setIsTestnet,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
18
dapps/react-dapp-v2/src/helpers/solana.ts
Normal file
18
dapps/react-dapp-v2/src/helpers/solana.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
|
export function getPublicKeysFromAccounts(accounts: string[]) {
|
||||||
|
return (
|
||||||
|
accounts
|
||||||
|
// Filter out any non-solana accounts.
|
||||||
|
.filter(account => account.startsWith("solana:"))
|
||||||
|
// Create a map of Solana address -> publicKey.
|
||||||
|
.reduce((map: Record<string, PublicKey>, account) => {
|
||||||
|
const address = account.split(":").pop();
|
||||||
|
if (!address) {
|
||||||
|
throw new Error(`Could not derive Solana address from CAIP account: ${account}`);
|
||||||
|
}
|
||||||
|
map[address] = new PublicKey(address);
|
||||||
|
return map;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
}
|
@ -1960,7 +1960,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
buffer "~6.0.3"
|
buffer "~6.0.3"
|
||||||
|
|
||||||
"@solana/web3.js@^1.36.0":
|
"@solana/web3.js@^1.35.1", "@solana/web3.js@^1.36.0":
|
||||||
version "1.36.0"
|
version "1.36.0"
|
||||||
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.36.0.tgz#79d7d5217b49b80139f4de68953adc5b9a9a264f"
|
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.36.0.tgz#79d7d5217b49b80139f4de68953adc5b9a9a264f"
|
||||||
integrity sha512-RNT1451iRR7TyW7EJKMCrH/0OXawIe4zVm0DWQASwXlR/u1jmW6FrmH0lujIh7cGTlfOVbH+2ZU9AVUPLBFzwA==
|
integrity sha512-RNT1451iRR7TyW7EJKMCrH/0OXawIe4zVm0DWQASwXlR/u1jmW6FrmH0lujIh7cGTlfOVbH+2ZU9AVUPLBFzwA==
|
||||||
@ -3639,6 +3639,11 @@ base-x@^3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
|
base-x@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a"
|
||||||
|
integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==
|
||||||
|
|
||||||
base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1:
|
base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1:
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
@ -3924,6 +3929,13 @@ bs58@^4.0.0, bs58@^4.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
base-x "^3.0.2"
|
base-x "^3.0.2"
|
||||||
|
|
||||||
|
bs58@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279"
|
||||||
|
integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==
|
||||||
|
dependencies:
|
||||||
|
base-x "^4.0.0"
|
||||||
|
|
||||||
bs58check@^2.1.2:
|
bs58check@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
|
resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
|
||||||
@ -11651,6 +11663,15 @@ sockjs@^0.3.21:
|
|||||||
uuid "^8.3.2"
|
uuid "^8.3.2"
|
||||||
websocket-driver "^0.7.4"
|
websocket-driver "^0.7.4"
|
||||||
|
|
||||||
|
solana-wallet@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/solana-wallet/-/solana-wallet-1.0.1.tgz#4e1bfebbb99640105ed42abd1445baab4f6e0b57"
|
||||||
|
integrity sha512-rkYu9gwayAdVMhWGdZSz6a+IaOJXs3TNtYXWuSQsdMJUndkQ+puy7cB9/u5pwZTjqzxtd1DN9cbAFKFH5648xQ==
|
||||||
|
dependencies:
|
||||||
|
"@solana/web3.js" "^1.35.1"
|
||||||
|
bs58 "^5.0.0"
|
||||||
|
tweetnacl "^1.0.3"
|
||||||
|
|
||||||
sonic-boom@^1.0.2:
|
sonic-boom@^1.0.2:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e"
|
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e"
|
||||||
|
Loading…
Reference in New Issue
Block a user