Skip to content

Commit

Permalink
feat: handle argentX wallet + trying to get_balance from deployed con…
Browse files Browse the repository at this point in the history
…tract
  • Loading branch information
hieu.ha committed Jan 9, 2025
1 parent 446e97e commit 6461507
Show file tree
Hide file tree
Showing 15 changed files with 1,298 additions and 28 deletions.
1 change: 1 addition & 0 deletions assets/icons/argent-x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
"redux-persist-electron-storage": "^2.1.0",
"rxjs": "^7.8.1",
"starknet": "^6.11.0",
"starknetkit": "^2.6.1",
"stream-browserify": "^3.0.0",
"text-encoding-polyfill": "^0.6.7",
"tsx": "^4.7.0",
Expand Down
87 changes: 87 additions & 0 deletions packages/components/connectWallet/ConnectArgentXButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from "react";
import { Linking } from "react-native";
import { ConnectWalletButton } from "./components/ConnectWalletButton";
import { useFeedbacks } from "../../context/FeedbacksProvider";

import argentSVG from "@/assets/icons/argent-x.svg";
import {
setIsArgentXConnected,
setSelectedNetworkId,
setSelectedWalletId,
} from "@/store/slices/settings";
import { useAppDispatch } from "@/store/store";
import { StarknetWindowObject, connect } from "starknetkit";
import {
useAccount,
InjectedConnector,
useConnect,
} from "@starknet-react/core";
import { getStarknetNetworkByChainId } from "@/networks";

export const ConnectArgentXButton: React.FC<{
onDone?: (err?: unknown) => void;
}> = ({ onDone }) => {
const { setToast } = useFeedbacks();
const dispatch = useAppDispatch();

const { address, status } = useAccount();
const { connectAsync: connectViaReact } = useConnect();

const handlePress = async () => {
// FIXME: only work with argentX for now, later we can allow to select all available wallets
const starknet = window.starknet as StarknetWindowObject;
if (!starknet) {
Linking.openURL(
"https://chromewebstore.google.com/detail/argent-x-starknet-wallet/dlcobpjiigpikoobohmabehhmhfoodbb",
);
return;
}

const connector = new InjectedConnector({
options: {
id: starknet.id,
name: starknet.name,
icon: starknet.icon,
},
});

try {
const { connectorData } = await connect({
connectors: [connector],
});
const chainId = connectorData?.chainId?.toString(16);
let network = getStarknetNetworkByChainId(chainId);
if (!network) throw Error("failed to get starknet network");

// FIXME: force to connect via react, check later to link react with normal connection
await connectViaReact({ connector });

dispatch(setIsArgentXConnected(true));
dispatch(setSelectedNetworkId(network.id));
if (connectorData?.account) {
dispatch(setSelectedWalletId("argentX-" + connectorData?.account));
}

onDone?.();
} catch (err) {
console.error(err);
if (err instanceof Error) {
setToast({
type: "error",
message: err.message,
mode: "normal",
title: "Failed to connect to ArgentX (1)",
});
}
onDone?.(err);
}
};
return (
<ConnectWalletButton
text="Argent X Wallet"
icon={argentSVG}
iconSize={20}
onPress={handlePress}
/>
);
};
7 changes: 7 additions & 0 deletions packages/components/modals/ConnectWalletModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { SeparatorGradient } from "../separators/SeparatorGradient";
import { SpacerColumn } from "../spacer";

import { ConnectGnotestButton } from "@/context/WalletsProvider/gnotest";
import { ConnectArgentXButton } from "../connectWallet/ConnectArgentXButton";

export const ConnectWalletModal: FC<{
forceNetworkFeature?: NetworkFeature;
Expand Down Expand Up @@ -66,6 +67,12 @@ export const ConnectWalletModal: FC<{
<SpacerColumn size={1.5} />
</>
)}
{canConnectWallet(NetworkKind.Starknet) && (
<>
<ConnectArgentXButton onDone={onClose} />
<SpacerColumn size={1.5} />
</>
)}
<ConnectWalletButton
text="Wallet Connect"
isComingSoon
Expand Down
17 changes: 16 additions & 1 deletion packages/context/WalletsProvider/WalletsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useGnotest } from "./gnotest";
import { useKeplr } from "./keplr";
import { useLeap } from "./leap";
import { useMetamask } from "./metamask";
import { useArgentX } from "./argentX";
import { Wallet } from "./wallet";
import { WalletProvider } from "../../utils/walletProvider";

Expand Down Expand Up @@ -34,6 +35,7 @@ export const WalletsProvider: React.FC<{ children: ReactNode }> = React.memo(
const [hasLeap, leapIsReady, leapWallets] = useLeap();
const [hasMetamask, metamaskIsReady, metamaskWallets] = useMetamask();
const [hasAdena, adenaIsReady, adenaWallets] = useAdena();
const [hasArgentX, argentXIsReady, argentXWallets] = useArgentX();
const [hasGnotest, , gnotestWallets] = useGnotest();
const selectedNativeWallet = useSelectedNativeWallet();
const hasNative = !!selectedNativeWallet;
Expand Down Expand Up @@ -124,6 +126,13 @@ export const WalletsProvider: React.FC<{ children: ReactNode }> = React.memo(
}
}

if (hasArgentX) {
walletProviders.push(WalletProvider.ArgentX);
if (argentXWallets?.[0]?.connected) {
wallets.push(argentXWallets[0]);
}
}

if (hasNative) {
walletProviders.push(WalletProvider.Native);
if (selectedNativeWallet) {
Expand All @@ -149,9 +158,15 @@ export const WalletsProvider: React.FC<{ children: ReactNode }> = React.memo(
return {
wallets,
walletProviders,
ready: keplrIsReady && metamaskIsReady && adenaIsReady && leapIsReady,
ready:
keplrIsReady &&
metamaskIsReady &&
adenaIsReady &&
leapIsReady &&
argentXIsReady,
};
}, [
argentXIsReady,
adenaIsReady,
adenaWallets,
gnotestWallets,
Expand Down
58 changes: 58 additions & 0 deletions packages/context/WalletsProvider/argentX.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useMemo, useEffect } from "react";

import { Wallet } from "./wallet";
import { useSelectedNetworkInfo } from "../../hooks/useSelectedNetwork";
import { NetworkKind, getUserId } from "../../networks";
import { setSelectedWalletId } from "../../store/slices/settings";
import { useAppDispatch } from "../../store/store";
import { WalletProvider } from "../../utils/walletProvider";
import { useAccount } from "@starknet-react/core";
import { starknetNetwork } from "@/networks/starknet";

type UseArgentXResult = [true, boolean, Wallet[]] | [false, boolean, undefined];

export const useArgentX: () => UseArgentXResult = () => {
const selectedNetworkInfo = useSelectedNetworkInfo();
const { address, status } = useAccount();
const dispatch = useAppDispatch();

const isConnected = status === "connected";

const wallet: Wallet | undefined = useMemo(() => {
if (!address || !isConnected) return;
let targetNetworkId = starknetNetwork.id;

if (selectedNetworkInfo?.kind === NetworkKind.Starknet) {
targetNetworkId = selectedNetworkInfo.id;
}
const userId = getUserId(targetNetworkId, address);
const walletId = `argentX-${address}`;
const wallet: Wallet = {
id: walletId,
address,
provider: WalletProvider.ArgentX,
networkKind: NetworkKind.Starknet,
networkId: targetNetworkId,
userId,
connected: isConnected,
};
return wallet;
}, [address, isConnected, selectedNetworkInfo]);

useEffect(() => {
if (
wallet?.connected &&
selectedNetworkInfo?.kind === NetworkKind.Starknet
) {
dispatch(setSelectedWalletId(wallet.id));
}
}, [dispatch, selectedNetworkInfo, wallet]);

const hasArgentX = useMemo(() => {
return typeof (window as any).ethereum !== "undefined";
}, []);

return hasArgentX
? [true, true, wallet ? [wallet] : []]
: [false, true, undefined];
};
30 changes: 30 additions & 0 deletions packages/networks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
NativeCurrencyInfo,
NetworkInfo,
NetworkKind,
StarknetNetworkInfo,
} from "./types";
import { starknetNetwork } from "./starknet";
import { starknetSepoliaNetwork } from "./starknet-sepolia";
Expand Down Expand Up @@ -303,6 +304,35 @@ export const mustGetCosmosNetwork = (
return network;
};

export const getStarknetNetwork = (
networkId: string | undefined,
): StarknetNetworkInfo | undefined => {
const network = getNetwork(networkId);
if (network?.kind !== NetworkKind.Starknet) {
return undefined;
}
return network;
};

export const getStarknetNetworkByChainId = (chainId: string | undefined) => {
return allNetworks.find((n): n is StarknetNetworkInfo => {
if (n.kind === NetworkKind.Starknet && n.chainId === chainId) {
return true;
}
return false;
});
};

export const mustGetStarknetNetwork = (
networkId: string | undefined,
): StarknetNetworkInfo => {
const network = mustGetNetwork(networkId);
if (network.kind !== NetworkKind.Starknet) {
throw new Error(`'${networkId}' is not a starknet network`);
}
return network;
};

export const getGnoNetwork = (
networkId: string | undefined,
): GnoNetworkInfo | undefined => {
Expand Down
5 changes: 4 additions & 1 deletion packages/networks/starknet-sepolia/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { NetworkKind, StarknetNetworkInfo } from "../types";
export const starknetSepoliaNetwork: StarknetNetworkInfo = {
id: "starknet-sepolia",
kind: NetworkKind.Starknet,
chainId: "SN_SEPOLIA", // 0x534e5f5345504f4c4941
chainId: "534e5f5345504f4c4941", // SN_SEPOLIA
displayName: "Starknet Sepolia",
icon: "starknet.svg",
features: [],
Expand All @@ -18,4 +18,7 @@ export const starknetSepoliaNetwork: StarknetNetworkInfo = {
addressPrefix: "starknet",
restEndpoint: "https://alpha-sepolia.starknet.io",
rpcEndpoint: "https://rpc.sepolia.starknet.io",

defaultContract:
"0x024068475e88548b0d6d06c6fbc5c691ce223ac611ca32a0a1b1c08a439d752a",
};
4 changes: 2 additions & 2 deletions packages/networks/starknet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { NetworkKind, StarknetNetworkInfo } from "../types";
export const starknetNetwork: StarknetNetworkInfo = {
id: "starknet",
kind: NetworkKind.Starknet,
chainId: "SN_MAIN",
displayName: "Starknet",
chainId: "534e5f4d41494e", // SN_MAIN
displayName: "Starknet",
icon: "starknet.svg",
features: [],
currencies: starknetCurrencies,
Expand Down
2 changes: 2 additions & 0 deletions packages/networks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export type StarknetNetworkInfo = NetworkInfoBase & {
addressPrefix: string;
restEndpoint: string;
rpcEndpoint: string;

defaultContract?: string;
};

export type CosmosNetworkInfo = NetworkInfoBase & {
Expand Down
26 changes: 26 additions & 0 deletions packages/screens/CairoPOC/CairoPOCScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,35 @@ import { useCairoTodos } from "./useCairoTodos";
import { TertiaryBox } from "@/components/boxes/TertiaryBox";
import { BrandText } from "@/components/BrandText";
import { Todo } from "./types";
import { useBalance, useNetwork, useReadContract } from "@starknet-react/core";
import {
useSelectedNetworkId,
useSelectedNetworkInfo,
} from "@/hooks/useSelectedNetwork";
import { StarknetNetworkInfo } from "@/networks";
import abi from "./abi.json";

export const CairoPOCScreen = () => {
const { data: todos, isLoading } = useCairoTodos();
const selectedNetwork = useSelectedNetworkInfo();

const {
data,
error,
isLoading: isReadingContract,
} = useReadContract({
abi,
functionName: "get_balance",
address: (selectedNetwork as StarknetNetworkInfo).defaultContract,
args: [],
});

console.log({
data,
error,
isReadingContract,
address: (selectedNetwork as StarknetNetworkInfo).defaultContract,
});

return (
<ScreenContainer>
Expand Down
33 changes: 33 additions & 0 deletions packages/screens/CairoPOC/abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{
"type": "impl",
"name": "HelloStarknetImpl",
"interface_name": "todo_list::IHelloStarknet"
},
{
"type": "interface",
"name": "todo_list::IHelloStarknet",
"items": [
{
"type": "function",
"name": "increase_balance",
"inputs": [{ "name": "amount", "type": "core::felt252" }],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "get_balance",
"inputs": [],
"outputs": [{ "type": "core::felt252" }],
"state_mutability": "view"
}
]
},
{
"type": "event",
"name": "todo_list::HelloStarknet::Event",
"kind": "enum",
"variants": []
}
]
Loading

0 comments on commit 6461507

Please sign in to comment.