Skip to content

Commit

Permalink
feat: add support for phantom
Browse files Browse the repository at this point in the history
  • Loading branch information
icfor committed Mar 25, 2024
1 parent 33c21f0 commit 7f3428c
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 26 deletions.
3 changes: 2 additions & 1 deletion public/locales/en/staking.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@
"wallets": {
"keplr": "Keplr",
"leap": "Leap",
"solana": "Solana"
"phantom": "Phantom",
"solflare": "Solflare"
},
"why forbole title": "<0>Forbole <1>empowers</1> people by building decentralized infrastructure.</0>",
"why forbole?": "Why Forbole?",
Expand Down
3 changes: 2 additions & 1 deletion public/locales/zh-CN/staking.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@
"wallets": {
"keplr": "Keplr",
"leap": "Leap",
"solana": "Solana"
"phantom": "Phantom",
"solflare": "Solflare"
},
"why forbole title": "<0>Forbole<1>坚实基建,硅步千里</1></0>",
"why forbole?": "为何选择 Forbole?",
Expand Down
3 changes: 2 additions & 1 deletion public/locales/zh-HK/staking.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@
"wallets": {
"keplr": "Keplr",
"leap": "Leap",
"solana": "Solana"
"phantom": "Phantom",
"solflare": "Solflare"
},
"why forbole title": "<0>Forbole <1>堅實基建,硅步千里</1></0>",
"why forbole?": "為何選擇 Forbole?",
Expand Down
3 changes: 2 additions & 1 deletion src/screens/staking/lib/staking_sdk/core/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export type Coin = {
export enum WalletId {
Keplr = "keplr",
Leap = "leap",
SolanaGroup = "solana-group",
Phantom = "phantom",
Solflare = "solflare",
}

export enum CoinDenom {
Expand Down
2 changes: 1 addition & 1 deletion src/screens/staking/lib/staking_sdk/core/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ export const solanaNetworks = new Set(
),
);

export const solanaWallets = new Set([WalletId.SolanaGroup]);
export const solanaWallets = new Set([WalletId.Solflare, WalletId.Phantom]);
23 changes: 17 additions & 6 deletions src/screens/staking/lib/staking_sdk/wallet_operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ import {
useCosmosWalletsListeners,
} from "./wallet_operations/cosmos";
import {
disconnectSolana,
disconnectPhantom,
disconnectSolflare,
stakeAmountSolana,
tryToConnectSolana,
tryToConnectPhantom,
tryToConnectSolflare,
unstakeSolana,
} from "./wallet_operations/solana";

Expand Down Expand Up @@ -104,9 +106,14 @@ export const tryToConnectWallets = async (

break;

case WalletId.SolanaGroup:
case WalletId.Solflare:
// @TODO: Open link if missing
connected = await tryToConnectSolana(context);
connected = await tryToConnectSolflare(context);

break;

case WalletId.Phantom:
connected = await tryToConnectPhantom(context, openLinkIfMissing);

break;

Expand All @@ -125,7 +132,8 @@ export const disconnectWalletFns: Record<
> = {
[WalletId.Keplr]: disconnecKeplr,
[WalletId.Leap]: disconnectLeap,
[WalletId.SolanaGroup]: disconnectSolana,
[WalletId.Phantom]: disconnectPhantom,
[WalletId.Solflare]: disconnectSolflare,
};

export const useWalletsListeners = (contextValue: TStakingContext) => {
Expand All @@ -143,7 +151,10 @@ export const doesWalletSupportNetwork = (
case WalletId.Leap:
return leapNetworks.has(networkId as StakingNetworkId);

case WalletId.SolanaGroup:
case WalletId.Solflare:
return solanaNetworks.has(networkId as StakingNetworkId);

case WalletId.Phantom:
return solanaNetworks.has(networkId as StakingNetworkId);

default: {
Expand Down
102 changes: 91 additions & 11 deletions src/screens/staking/lib/staking_sdk/wallet_operations/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ testnetWallet.on("disconnect", () => {
let connectListenerMainnet: (() => void) | undefined;
let connectListenerTestnet: (() => void) | undefined;

export const tryToConnectSolana = async (
export const tryToConnectSolflare = async (
context: TStakingContext,
): Promise<boolean> =>
new Promise(async (resolve, reject) => {
Expand Down Expand Up @@ -73,22 +73,22 @@ export const tryToConnectSolana = async (
info: accountData.info,
networkId,
rewards: accountData.rewards,
wallet: WalletId.SolanaGroup,
wallet: WalletId.Solflare,
};

setUserWallet(context, WalletId.SolanaGroup, {
setUserWallet(context, WalletId.Solflare, {
name: "Test", // @TODO
networks: {
...context.state.wallets[WalletId.SolanaGroup]?.networks,
...context.state.wallets[WalletId.Solflare]?.networks,
[networkId]: {
accounts: [account],
networkId,
},
},
wallet: WalletId.SolanaGroup,
wallet: WalletId.Solflare,
});

addToConnectedWallets(WalletId.SolanaGroup);
addToConnectedWallets(WalletId.Solflare);

resolvedItems += 1;

Expand Down Expand Up @@ -136,13 +136,83 @@ export const tryToConnectSolana = async (
]);
});

export const tryToConnectPhantom = async (
context: TStakingContext,
openLinkIfMissing?: boolean,
) => {
const { phantom } = window as any;
const provider = phantom?.solana;

if (provider?.isPhantom) {
const resp = await provider.connect();

const publicKey = resp.publicKey.toString();

return [StakingNetworkId.Solana]
.concat(ENABLE_TESTNETS ? [StakingNetworkId.SolanaTestnet] : [])
.reduce(async (promise, networkId) => {
await promise;

const accountData = await fetchAccountData(
context,
publicKey,
networkId,
true,
);

const account: Account = {
address: publicKey,
info: accountData.info,
networkId,
rewards: accountData.rewards,
wallet: WalletId.Phantom,
};

setUserWallet(context, WalletId.Phantom, {
name: "Test", // @TODO
networks: {
...context.state.wallets[WalletId.Phantom]?.networks,
[networkId]: {
accounts: [account],
networkId,
},
},
wallet: WalletId.Phantom,
});

addToConnectedWallets(WalletId.Phantom);

return true;
}, Promise.resolve(false));
} else if (openLinkIfMissing) {
window.open("https://phantom.app/", "_blank");
}
};

const minimumStakeAmount: { [key in StakingNetworkId]?: number } = {
// In testnet it is not possible to stake less than 1 SOL, Solflare will disable the button
[StakingNetworkId.SolanaTestnet]: LAMPORTS_PER_SOL * 1,
};

const getWallet = (networkId: StakingNetworkId) =>
networkId === StakingNetworkId.SolanaTestnet ? testnetWallet : mainnetWallet;
type WalletApi = {
signAndSendTransaction: any;
};

const getWalletApi = (account: Account): WalletApi => {
if (account.wallet === WalletId.Phantom) {
const { phantom } = window as any;

return {
signAndSendTransaction: phantom.solana.signAndSendTransaction.bind(
phantom.solana,
),
};
}

return account.networkId === StakingNetworkId.SolanaTestnet
? testnetWallet
: mainnetWallet;
};

// https://solanacookbook.com/references/staking.html
export const stakeAmountSolana = async ({
Expand All @@ -155,7 +225,7 @@ export const stakeAmountSolana = async ({
const validatorAddress = (info as any).validator_address;

const accountKey = new PublicKey(account.address);
const wallet = getWallet(account.networkId);
const wallet = getWalletApi(account);

const stakeAccount = (account.info?.stakeAccounts || []).find(
(a) => a.validator_address === validatorAddress,
Expand Down Expand Up @@ -272,7 +342,7 @@ export const unstakeSolana = async ({

const accountKey = new PublicKey(account.address);

const wallet = getWallet(account.networkId);
const wallet = getWalletApi(account);

const stakeAccount = (account.info?.stakeAccounts || []).find(
(a) => a.validator_address === validatorAddress,
Expand Down Expand Up @@ -320,7 +390,17 @@ export const unstakeSolana = async ({
};
});

export const disconnectSolana = async (networks: StakingNetworkId[]) => {
export const disconnectSolflare = async (networks: StakingNetworkId[]) => {
// @TODO
// eslint-disable-next-line no-console
console.log("debug: solana.ts: disconnectSolana", networks);
};

export const disconnectPhantom = async () => {
const { phantom } = window as any;
const provider = phantom?.solana;

if (provider?.isPhantom) {
await provider.disconnect();
}
};
13 changes: 9 additions & 4 deletions src/screens/staking/lib/wallet_info.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import type { Translate } from "next-translate";
import type { FC } from "react";

import IconPhantom from "@src/components/icons/icon_search.svg";
import IconKeplr from "@src/components/icons/keplr.svg";
import IconLeap from "@src/components/icons/leap.svg";
import IconSolana from "@src/components/icons/solana_wallet.svg";
import IconSolflare from "@src/components/icons/solana_wallet.svg";

import { WalletId } from "./staking_sdk/core/base";

export const walletsIcons: Record<WalletId, FC<{ className?: string }>> = {
[WalletId.Keplr]: IconKeplr,
[WalletId.Leap]: IconLeap,
[WalletId.SolanaGroup]: IconSolana,
[WalletId.Phantom]: IconPhantom,
[WalletId.Solflare]: IconSolflare,
};

export const getWalletName = (walletId: WalletId, t: Translate) => {
Expand All @@ -21,8 +23,11 @@ export const getWalletName = (walletId: WalletId, t: Translate) => {
case WalletId.Leap:
return t("staking:wallets.leap");

case WalletId.SolanaGroup:
return t("staking:wallets.solana");
case WalletId.Solflare:
return t("staking:wallets.solflare");

case WalletId.Phantom:
return t("staking:wallets.phantom");

default: {
const exhaustiveCheck: never = walletId;
Expand Down

0 comments on commit 7f3428c

Please sign in to comment.