@layerswap/wallet-starknet 1.1.0 → 1.1.2

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/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @layerswap/wallet-starknet
2
+
3
+ Starknet wallet provider for the Layerswap Widget. Enables Starknet wallet connections and transactions.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @layerswap/wallet-starknet
9
+ # or
10
+ yarn add @layerswap/wallet-starknet
11
+ # or
12
+ pnpm add @layerswap/wallet-starknet
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```tsx
18
+ import { LayerswapProvider, Swap } from "@layerswap/widget";
19
+ import { createStarknetProvider } from "@layerswap/wallet-starknet";
20
+
21
+ export default function Page() {
22
+ const starknetProvider = createStarknetProvider({
23
+ walletConnectConfigs: {
24
+ projectId: "your-project-id",
25
+ name: "Your App",
26
+ description: "Your app description",
27
+ url: "https://your-app.com",
28
+ icons: ["https://your-app.com/icon.png"]
29
+ }
30
+ });
31
+
32
+ return (
33
+ <LayerswapProvider walletProviders={[starknetProvider]}>
34
+ <Swap />
35
+ </LayerswapProvider>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Use `createStarknetProvider()` to create a Starknet wallet provider:
43
+
44
+ ```tsx
45
+ import { createStarknetProvider } from "@layerswap/wallet-starknet";
46
+
47
+ const starknetProvider = createStarknetProvider({
48
+ walletConnectConfigs: {
49
+ projectId: "your-project-id",
50
+ name: "Your App",
51
+ description: "Your app description",
52
+ url: "https://your-app.com",
53
+ icons: ["https://your-app.com/icon.png"]
54
+ }
55
+ });
56
+ ```
57
+
58
+ ## Documentation
59
+
60
+ For detailed setup instructions, configuration options, and usage examples, see the [Starknet Wallet Provider documentation](https://docs.layerswap.io/integration/UI/Widget/WalletManagement/StarknetProvider).
61
+
62
+ ## Features
63
+
64
+ - Starknet wallet connection via StarknetKit
65
+ - Balance checking
66
+ - Gas estimation
67
+ - NFT provider support
68
+ - Address validation and utilities
69
+ - Starknet transaction support
70
+
71
+ ## Supported Wallets
72
+
73
+ - Ready Wallet
74
+ - Ready
75
+ - Web wallet
76
+ - Braavos
77
+ - Keplr
78
+ - Xverse
79
+ - Cartridge Controller
80
+
81
+ ## TypeScript
82
+
83
+ This package includes TypeScript definitions. All types are exported from the main entry point.
84
+
85
+ ## License
86
+
87
+ MIT
88
+
89
+ ## Repository
90
+
91
+ [GitHub](https://github.com/layerswap/layerswapapp/tree/main/packages/wallets/starknet)
92
+
@@ -21,6 +21,8 @@ import { ArgentMobileConnector } from "starknetkit/argentMobile";
21
21
  import { InjectedConnector } from "starknetkit/injected";
22
22
  // @ts-ignore
23
23
  import { WebWalletConnector } from "starknetkit/webwallet";
24
+ // @ts-ignore
25
+ import { ControllerConnector } from "starknetkit/controller";
24
26
  import useStarknetConnection, { resolveStarknetWallet } from "./useStarknetConnection";
25
27
  import { useStarknetStore } from "./starknetWalletStore";
26
28
  class DiscoveryConnector extends Connector {
@@ -105,6 +107,7 @@ const StarknetProvider = ({ children, walletConnectConfigs }) => {
105
107
  description: walletConnectConfig?.description || 'Move crypto across exchanges, blockchains, and wallets.',
106
108
  }
107
109
  }));
110
+ defaultConnectors.push(new ControllerConnector());
108
111
  defaultConnectors.push(new WebWalletConnector());
109
112
  return defaultConnectors;
110
113
  };
@@ -19,7 +19,7 @@ export class StarknetBalanceProvider extends BalanceProvider {
19
19
  const tokens = insertIfNotExists(network.tokens || [], network.token);
20
20
  for (const token of tokens) {
21
21
  try {
22
- const erc20 = new Contract(Erc20Abi, token.contract, provider);
22
+ const erc20 = new Contract({ abi: Erc20Abi, address: token.contract, providerOrAccount: provider });
23
23
  const balanceResult = await erc20.balanceOf(address);
24
24
  const balanceInWei = BigNumber.from(uint256.uint256ToBN(balanceResult.balance).toString()).toString();
25
25
  const balance = {
@@ -28,11 +28,11 @@ export class StarknetGasProvider {
28
28
  calldata: ["69420"],
29
29
  };
30
30
  const resp = await starknetWalletAccount.estimateInvokeFee([transferCall, watch], { skipValidate: true });
31
- if (!resp?.suggestedMaxFee) {
31
+ if (!resp?.overall_fee) {
32
32
  throw new Error(`Couldn't get fee estimation for the transfer. Response: ${JSON.stringify(resp)}`);
33
33
  }
34
34
  ;
35
- const feeInWei = resp.suggestedMaxFee.toString();
35
+ const feeInWei = resp.overall_fee.toString();
36
36
  const gas = Number(formatUnits(BigInt(feeInWei), network.token.decimals));
37
37
  return { gas, token: network.token };
38
38
  };
@@ -29,7 +29,7 @@ export class StarknetNftProvider {
29
29
  nodeUrl: network.node_url
30
30
  });
31
31
  try {
32
- const contract = new Contract(NFT_ABI, contractAddress, provider);
32
+ const contract = new Contract({ abi: NFT_ABI, address: contractAddress, providerOrAccount: provider });
33
33
  const response = await contract.balanceOf(address);
34
34
  if (!response || typeof response.balance === 'undefined') {
35
35
  throw new Error("Invalid response from NFT contract");
@@ -1,8 +1,8 @@
1
1
  import { useConnect, useDisconnect } from "@starknet-react/core";
2
- import { KnownInternalNames } from "@layerswap/widget/internal";
3
- import { resolveStarknetWalletConnectorIcon } from "./utils";
2
+ import { KnownInternalNames, walletIconResolver } from "@layerswap/widget/internal";
4
3
  import { useStarknetStore } from "./starknetWalletStore";
5
4
  import { useStarknetTransfer } from "./useStarknetTransfer";
5
+ import { resolveStarknetWalletIcon } from "./utils";
6
6
  const starknetNames = [KnownInternalNames.Networks.StarkNetGoerli, KnownInternalNames.Networks.StarkNetMainnet, KnownInternalNames.Networks.StarkNetSepolia];
7
7
  export default function useStarknetConnection({ networks }) {
8
8
  const commonSupportedNetworks = [
@@ -28,20 +28,38 @@ export default function useStarknetConnection({ networks }) {
28
28
  const connectWallet = async ({ connector }) => {
29
29
  try {
30
30
  const starknetConnector = connectors.find(c => c.id === connector.id);
31
- const result = await starknetConnector?.connect({});
31
+ let result = await starknetConnector?.connect({});
32
32
  const walletChain = `0x${result?.chainId?.toString(16)}`;
33
- const wrongChanin = walletChain == '0x534e5f4d41494e' ? !isMainnet : isMainnet;
34
- const starkent = networks.find(n => n.name === KnownInternalNames.Networks.StarkNetMainnet || n.name === KnownInternalNames.Networks.StarkNetSepolia);
35
- if (result?.account && wrongChanin) {
36
- disconnectWallets(connector?.name, result?.account);
37
- const errorMessage = `Please switch the network in your wallet to ${isMainnet ? 'Mainnet' : 'Sepolia'} and click connect again`;
38
- throw new Error(errorMessage);
33
+ const isWalletOnMainnet = walletChain === '0x534e5f4d41494e';
34
+ const wrongChain = isWalletOnMainnet !== isMainnet;
35
+ const starknetNetwork = networks.find(n => n.name === KnownInternalNames.Networks.StarkNetMainnet || n.name === KnownInternalNames.Networks.StarkNetSepolia);
36
+ if (result?.account && wrongChain) {
37
+ const wallet = starknetConnector?._wallet || starknetConnector?.wallet;
38
+ if (wallet?.request) {
39
+ const targetChainId = isMainnet ? 'SN_MAIN' : 'SN_SEPOLIA';
40
+ try {
41
+ await wallet.request({
42
+ type: "wallet_switchStarknetChain",
43
+ params: { chainId: targetChainId }
44
+ });
45
+ result = await starknetConnector?.connect({});
46
+ }
47
+ catch (switchError) {
48
+ console.log('Chain switch failed:', switchError);
49
+ disconnectWallets(connector?.name, result?.account);
50
+ throw new Error(`Failed to switch network. Please switch manually to ${isMainnet ? 'Mainnet' : 'Sepolia'} in your wallet.`);
51
+ }
52
+ }
53
+ else {
54
+ disconnectWallets(connector?.name, result?.account);
55
+ throw new Error(`Please switch the network in your wallet to ${isMainnet ? 'Mainnet' : 'Sepolia'} and connect again.`);
56
+ }
39
57
  }
40
58
  if (result?.account && starknetConnector) {
41
- const wallet = await resolveStarknetWallet({
59
+ const resolvedWallet = await resolveStarknetWallet({
42
60
  name,
43
61
  connector: starknetConnector,
44
- network: starkent,
62
+ network: starknetNetwork,
45
63
  disconnectWallets: () => disconnectWallets(starknetConnector.id, result?.account),
46
64
  address: result?.account,
47
65
  withdrawalSupportedNetworks,
@@ -49,15 +67,15 @@ export default function useStarknetConnection({ networks }) {
49
67
  asSourceSupportedNetworks: commonSupportedNetworks,
50
68
  });
51
69
  addAccount(starknetConnector.id, result.account);
52
- if (wallet) {
53
- addWallet(wallet);
54
- setActiveWallet(wallet.address);
55
- return wallet;
70
+ if (resolvedWallet) {
71
+ addWallet(resolvedWallet);
72
+ setActiveWallet(resolvedWallet.address);
73
+ return resolvedWallet;
56
74
  }
57
75
  }
58
76
  }
59
77
  catch (e) {
60
- throw new Error(e);
78
+ throw e;
61
79
  }
62
80
  };
63
81
  const disconnectWallets = async (connectorName, address) => {
@@ -76,7 +94,7 @@ export default function useStarknetConnection({ networks }) {
76
94
  return {
77
95
  name: name,
78
96
  id: connector.id,
79
- icon: typeof connector.icon === 'string' ? connector.icon : (connector.icon.light.startsWith('data:') ? connector.icon.light : `data:image/svg+xml;base64,${btoa(connector.icon.light.replaceAll('currentColor', '#FFFFFF'))}`),
97
+ icon: resolveStarknetWalletIcon({ icon: connector.icon }),
80
98
  type: connector?.["_wallet"] ? 'injected' : 'other',
81
99
  installUrl: connector?.["_wallet"] ? undefined : connectorsConfigs.find(c => c.id === connector.id)?.installLink,
82
100
  };
@@ -108,7 +126,7 @@ export async function resolveStarknetWallet(props) {
108
126
  const walletChain = network?.chain_id;
109
127
  const { RpcProvider, WalletAccount } = await import('starknet');
110
128
  const rpcProvider = new RpcProvider({ nodeUrl: network?.node_url });
111
- const walletAccount = new WalletAccount(rpcProvider, connector.wallet, address);
129
+ const walletAccount = new WalletAccount({ provider: rpcProvider, walletProvider: connector.wallet, address });
112
130
  const accounts = await walletAccount.requestAccounts(true);
113
131
  const account = accounts?.[0];
114
132
  const wallet = {
@@ -117,7 +135,7 @@ export async function resolveStarknetWallet(props) {
117
135
  address: account,
118
136
  addresses: [account],
119
137
  chainId: walletChain || '',
120
- icon: resolveStarknetWalletConnectorIcon({ connector: connector.name, address: account }),
138
+ icon: walletIconResolver(address, resolveStarknetWalletIcon({ icon: connector.icon })),
121
139
  providerName: name,
122
140
  metadata: {
123
141
  starknetAccount: walletAccount,
@@ -1,3 +1,2 @@
1
1
  export * from "./starkNetAddressValidator";
2
- export * from "./KnownStarknetConnectors";
3
- export * from "./resolveIcon";
2
+ export * from "./resolveStarknetWalletIcon";
@@ -0,0 +1,3 @@
1
+ export const resolveStarknetWalletIcon = ({ icon }) => {
2
+ return typeof icon === 'string' ? icon : (icon.light.startsWith('data:') ? icon.light : `data:image/svg+xml;base64,${btoa(icon.light.replaceAll('currentColor', '#FFFFFF'))}`);
3
+ };