Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(spaceward): fix sending cosmos not using the same rpc as in assets fetch data; fix handling collapsed transactions #892

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spaceward/src/components/ui/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Portal forceMount={props.forceMount}>
<PopoverPrimitive.Content
ref={ref}
align={align}
Expand Down
5 changes: 4 additions & 1 deletion spaceward/src/config/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ export const COSMOS_PRICES: Record<string, bigint | undefined> = {
OSMO: BigInt(0.4446 * 10 ** 8),
};

const _ENABLED_ETH_CHAINS: { chainName: ChainName; testnet?: boolean }[] = [
const _ENABLED_ETH_CHAINS: {
chainName: ChainName;
testnet?: boolean;
}[] = [
{ chainName: "arbitrum" },
{ chainName: "astar" },
{ chainName: "avalanche" },
Expand Down
25 changes: 18 additions & 7 deletions spaceward/src/features/actions/StatusSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from "clsx";
import { useContext, useEffect } from "react";
import { useContext, useEffect, useRef, useState } from "react";
import { isDeliverTxSuccess } from "@cosmjs/stargate";
import { useChain, walletContext } from "@cosmos-kit/react-lite";
import { cosmos, warden } from "@wardenprotocol/wardenjs";
Expand All @@ -20,7 +20,9 @@ import { QueuedAction, QueuedActionStatus, useActionsState } from "./hooks";
import { getActionHandler, GetStatus, handleCosmos, handleEth, handleEthRaw } from "./util";
import { TEMP_KEY, useKeySettingsState } from "../keys/state";
import Assets from "../keys/assets";
import { useQueryClient } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { capitalize } from "../modals/util";
import { queryCosmosClients } from "../assets/queries";

interface ItemProps extends QueuedAction {
single?: boolean;
Expand All @@ -46,6 +48,10 @@ const waitForVisibility = () => {
function ActionItem({ single, ...item }: ItemProps) {
const queryClient = useQueryClient();
const { walletManager } = useContext(walletContext);
const cosmosClients = useQuery(queryCosmosClients(walletManager)).data;
const clientsRef = useRef(cosmosClients);
clientsRef.current = cosmosClients;

const { data: ks, setData: setKeySettings } = useKeySettingsState();
const { toast } = useToast()
const { w } = useWeb3Wallet("wss://relay.walletconnect.org");
Expand Down Expand Up @@ -311,7 +317,8 @@ function ActionItem({ single, ...item }: ItemProps) {
} else if (item.networkType === "eth") {
res = await handleEth({ action: item, w, queryClient });
} else if (item.networkType === "cosmos") {
res = await handleCosmos({ action: item, w, walletManager, queryClient });
const [, , rpcEndpoint] = clientsRef.current?.find((v) => v[1] === item?.chainName) ?? [];
res = await handleCosmos({ action: item, w, queryClient, rpcEndpoint });
}
} catch (e) {
console.error("broadcast failed", e);
Expand Down Expand Up @@ -407,7 +414,7 @@ function ActionItem({ single, ...item }: ItemProps) {
? "Action ready"
: item.status ===
QueuedActionStatus.AwaitingBroadcast
? "Awaiting broadcast"
? `Awaiting broadcast on ${capitalize(item.chainName)}`
: item.status === QueuedActionStatus.Success
? "Success"
: item.status ===
Expand Down Expand Up @@ -437,6 +444,7 @@ function ActionItem({ single, ...item }: ItemProps) {
}

export default function StatusSidebar() {
const [hide, setHide] = useState(true);
const { data } = useActionsState();
const storeIds = Object.keys(data ?? {});

Expand Down Expand Up @@ -469,7 +477,9 @@ export default function StatusSidebar() {
<ActionItem single {...data?.[filtered[0]]!} />
) : null
) : (
<Popover>
<Popover onOpenChange={open => {
setHide(!open);
}}>
<PopoverTrigger asChild>
<div className="flex flex-col relative cursor-pointer">
<p className="text-lg font-semibold">
Expand All @@ -484,9 +494,10 @@ export default function StatusSidebar() {
<PopoverContent
side="left"
sideOffset={20}
className="p-0"
className={clsx("p-0", { hidden: hide })}
forceMount={hide ? true : undefined}
>
<div className="bg-fill-quaternary max-h-80 overflow-auto">
<div className={"bg-fill-quaternary max-h-80 overflow-auto"}>
{filtered.map((id) => {
const action = data?.[id];

Expand Down
1 change: 1 addition & 0 deletions spaceward/src/features/actions/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export enum QueuedActionStatus {
Broadcast,
AwaitingApprovals,
ActionReady,
// fixme rename
AwaitingBroadcast,
Success = 0x99,
Failed = 0xff,
Expand Down
21 changes: 5 additions & 16 deletions spaceward/src/features/actions/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,12 @@ export const handleEth = async ({
export const handleCosmos = async ({
action,
w,
walletManager,
queryClient,
rpcEndpoint,
}: {
action: QueuedAction;
w: IWeb3Wallet | null;
walletManager: WalletManager;
rpcEndpoint?: string;
queryClient: QueryClient;
}) => {
const {
Expand Down Expand Up @@ -384,22 +384,11 @@ export const handleCosmos = async ({
signatures: [sig],
});

let rpc: string;
if (chain.rpc) {
[rpc] = chain.rpc;
} else {
const repo = walletManager.getWalletRepo(chainName);
repo.activate();
const endpoint = await repo.getRpcEndpoint();

rpc = endpoint
? typeof endpoint === "string"
? endpoint
: endpoint.url
: "https://rpc.cosmos.directory/" + chainName;
if (!rpcEndpoint) {
throw new Error("missing rpcEndpoint");
}

const client = await StargateClient.connect(rpc);
const client = await StargateClient.connect(rpcEndpoint);

const res = await client.broadcastTx(
cosmos.tx.v1beta1.TxRaw.encode(txRaw).finish(),
Expand Down
29 changes: 17 additions & 12 deletions spaceward/src/features/assets/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ const eip155NativeBalanceQuery = ({
throw new Error("Address is required");
}

const { provider, token } = getProvider(chainName);
const { provider, tokenSymbol: token } = getProvider(chainName);
const slinkyPrice = prices?.[token];
const priceFeed = EIP_155_NATIVE_PRICE_FEEDS[chainName];

Expand Down Expand Up @@ -427,7 +427,7 @@ const DEFAULT_BECH32_PREFIX = getCosmosChain("osmosis")!.bech32_prefix;
export const balancesQueryCosmos = (
enabled: boolean,
keys?: QueryKeyResponse[],
clients?: [CosmosQueryClient, string][],
clients?: [CosmosQueryClient, string, string][],
prices?: PriceMapSlinky,
) => {
const byAddress: Record<string, QueryKeyResponse> = {};
Expand Down Expand Up @@ -629,7 +629,10 @@ export const fiatPricesQuery = (enabled: boolean) => {
};
};

const rpcClients: Record<string, CosmosQueryClient | undefined> = {};
const rpcClients: Record<
string,
{ client: CosmosQueryClient; rpcEndpoint: string } | undefined
> = {};
const rpcRetry: Record<string, number> = {};

const checkHealth = async (
Expand Down Expand Up @@ -666,18 +669,18 @@ export const queryCosmosClients = (walletManager: WalletManager) => {
return {
queryKey: ["cosmos", "rpcClients"],
queryFn: async () => {
const clients: [CosmosQueryClient, string][] = [];
const clients: [CosmosQueryClient, string, string][] = [];

for (let i = 0; i < COSMOS_CHAINS.length; i++) {
const { chainName, rpc } = COSMOS_CHAINS[i];
const retries = (rpc?.length ?? 0) + 1;

for (let i = 0; i < retries; i++) {
let client = rpcClients[chainName];
let { client, rpcEndpoint } = rpcClients[chainName] ?? {};
const retry = (rpcRetry[chainName] ?? 0) % (retries + 1);
rpcRetry[chainName] = retry + 1;

if (!client) {
if (!client || !rpcEndpoint) {
let endpoint: ExtendedHttpEndpoint | string;

if (!rpc?.[retry]) {
Expand All @@ -694,14 +697,16 @@ export const queryCosmosClients = (walletManager: WalletManager) => {
endpoint = rpc[retry];
}

rpcEndpoint =
typeof endpoint === "string"
? endpoint
: endpoint.url;

try {
client =
await cosmos.ClientFactory.createRPCQueryClient(
{
rpcEndpoint:
typeof endpoint === "string"
? endpoint
: endpoint.url,
rpcEndpoint,
},
);
} catch (e) {
Expand All @@ -711,8 +716,8 @@ export const queryCosmosClients = (walletManager: WalletManager) => {
}

if (await checkHealth(client, chainName)) {
rpcClients[chainName] = client;
clients.push([client!, chainName]);
rpcClients[chainName] = { client, rpcEndpoint };
clients.push([client, chainName, rpcEndpoint]);
break;
} else if (rpcClients[chainName]) {
delete rpcClients[chainName];
Expand Down
17 changes: 7 additions & 10 deletions spaceward/src/features/modals/SendAssets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { validateAddress } from "../intents/AddAddressModal";
import { StargateClient } from "@cosmjs/stargate";
import { useModalState } from "./state";
import KeySelector from "./KeySelector";
import { COSMOS_CHAINS } from "@/config/tokens";
import { walletContext } from "@cosmos-kit/react-lite";
import { BalanceEntry } from "../assets/types";
import { useQuery } from "@tanstack/react-query";
import { queryCosmosClients } from "../assets/queries";

export default function SendAssetsModal({
// address,
Expand All @@ -31,6 +32,7 @@ export default function SendAssetsModal({

const { spaceId } = useSpaceId();
const { queryBalances } = useAssetQueries(spaceId);
const cosmosClients = useQuery(queryCosmosClients(walletManager)).data;

const results: (BalanceEntry & { refetch: () => void })[] = queryBalances
.filter((result) => result.data?.key?.key?.id === key?.key?.id)
Expand Down Expand Up @@ -97,17 +99,12 @@ export default function SendAssetsModal({
setModal({ type: undefined });
}
} else if (txBuild.type === "cosmos") {
const chain = COSMOS_CHAINS.find(
(item) => item.chainName === chainName,
);

let rpc = chain?.rpc?.[0];
const [, , rpc] = cosmosClients?.find((item) => {
return item[1] === chainName
}) ?? [];

if (!rpc) {
const repo = walletManager.getWalletRepo(chainName);
repo.activate();
const endpoint = await repo.getRpcEndpoint();
rpc = endpoint ? typeof endpoint === "string" ? endpoint : endpoint.url : `https://rpc.cosmos.directory/${chainName}`;
throw new Error(`unable to find rpc for ${chainName}`);
}

const client = await StargateClient.connect(rpc);
Expand Down
17 changes: 7 additions & 10 deletions spaceward/src/hooks/state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ export function createPersistantState<T>(
});

const ref = useRef(data);

useEffect(() => {
ref.current = data;
}, [data]);
ref.current = data;

const setData = useCallback(
(nextData: Partial<T>) => {
Expand All @@ -120,14 +117,14 @@ export function createPersistantState<T>(
JSON.stringify(_data, (_, v) =>
typeof v === "bigint"
? {
type: "bigint",
value: v.toString(),
}
type: "bigint",
value: v.toString(),
}
: v instanceof Uint8Array
? {
type: "Uint8Array",
value: Array.from(v)
}
type: "Uint8Array",
value: Array.from(v)
}
: v,
),
);
Expand Down
23 changes: 15 additions & 8 deletions spaceward/src/lib/eth/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// taken from https://chainlist.org
export const ETH_CHAIN_CONFIG: Record<
string,
{ rpc: string[]; token?: string }
{ rpc: string[]; token?: { symbol: string; name: string }; title?: string }
> = {
"1": { rpc: ["https://cloudflare-eth.com", "https://eth.llamarpc.com"] },
"1": {
rpc: ["https://cloudflare-eth.com", "https://eth.llamarpc.com"],
title: "Ethereum",
},
Comment on lines +6 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding the token property for consistency.

The addition of the title property improves clarity for the Ethereum chain. However, the token property is missing, which is inconsistent with other chain configurations and the type definition.

For consistency, consider adding the token property to the Ethereum configuration:

"1": {
  rpc: ["https://cloudflare-eth.com", "https://eth.llamarpc.com"],
  title: "Ethereum",
  token: { symbol: "ETH", name: "Ether" },
},

"5": { rpc: ["https://rpc.goerli.mudit.blog/"] },
"10": {
rpc: ["https://mainnet.optimism.io/", "https://optimism.llamarpc.com"],
Expand All @@ -13,30 +16,34 @@ export const ETH_CHAIN_CONFIG: Record<
"https://bsc-dataseed1.bnbchain.org",
"https://binance.llamarpc.com",
],
token: "BNB",
token: { symbol: "BNB", name: "Binance Coin" },
},
"61": {
rpc: ["https://etc.etcdesktop.com", "https://geth-at.etc-network.info"],
token: "ETC",
token: { symbol: "ETC", name: "Ethereum Classic" },
title: "Ethereum Classic",
},
"137": {
rpc: ["https://polygon-rpc.com/", "https://polygon.llamarpc.com"],
token: "MATIC",
token: { symbol: "MATIC", name: "Polygon" },
},
"324": { rpc: ["https://mainnet.era.zksync.io/"] },
"420": { rpc: ["https://goerli.optimism.io"] },
"592": {
rpc: ["https://astar-rpc.dwellir.com", "https://1rpc.io/astr"],
token: "ASTR",
token: { symbol: "ASTR", name: "Astar" },
},
"8453": {
rpc: ["https://mainnet.base.org/", "https://base.llamarpc.com"],
token: { symbol: "BASE", name: "Base" },
},
"8453": { rpc: ["https://mainnet.base.org/", "https://base.llamarpc.com"] },
"42161": {
rpc: ["https://arb1.arbitrum.io/rpc", "https://arbitrum.llamarpc.com"],
},
"42220": { rpc: ["https://forno.celo.org"] },
"43114": {
rpc: ["https://api.avax.network/ext/bc/C/rpc"],
token: "AVAX",
token: { symbol: "AVAX", name: "Avalanche" },
},
"44787": { rpc: ["https://alfajores-forno.celo-testnet.org"] },
"80001": { rpc: ["https://rpc-mumbai.maticvigil.com"] },
Expand Down
7 changes: 5 additions & 2 deletions spaceward/src/lib/eth/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ethers } from "ethers";
import { ETH_CHAINID_MAP, ETH_CHAIN_CONFIG } from "./constants";
import { capitalize } from "@/features/modals/util";

export const REVERSE_ETH_CHAINID_MAP = Object.fromEntries(
Object.entries(ETH_CHAINID_MAP).map(([k, v]) => [v, k]),
Expand All @@ -16,7 +17,9 @@ export const isSupportedNetwork = (
export const getProvider = (type: SupportedNetwork) => {
const chainId = ETH_CHAINID_MAP[type];
const config = ETH_CHAIN_CONFIG[chainId];
const token = config?.token ?? "ETH";
const tokenSymbol = config?.token?.symbol ?? "ETH";
const tokenName = config?.token?.name ?? "Ethereum";
const title = config?.title ?? capitalize(type);

if (!providers[type]) {
if (!chainId || !config) {
Expand Down Expand Up @@ -53,7 +56,7 @@ export const getProvider = (type: SupportedNetwork) => {
}

const provider = providers[type];
return { provider, token };
return { provider, tokenSymbol, tokenName, title };
};

export const getProviderByChainId = (chainId: string) => {
Expand Down
Loading