-
Notifications
You must be signed in to change notification settings - Fork 24
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
Add Solana support to ZetaChain client and browser deposits #199
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,3 +1,6 @@ | ||||||||||||||||||||
import type { Wallet as SolanaWallet } from "@coral-xyz/anchor"; | ||||||||||||||||||||
import type { WalletContextState } from "@solana/wallet-adapter-react"; | ||||||||||||||||||||
import { PublicKey } from "@solana/web3.js"; | ||||||||||||||||||||
import { networks } from "@zetachain/networks"; | ||||||||||||||||||||
import type { Signer, Wallet } from "ethers"; | ||||||||||||||||||||
import merge from "lodash/merge"; | ||||||||||||||||||||
|
@@ -33,16 +36,45 @@ export interface ZetaChainClientParamsBase { | |||||||||||||||||||
|
||||||||||||||||||||
export type ZetaChainClientParams = ZetaChainClientParamsBase & | ||||||||||||||||||||
( | ||||||||||||||||||||
| { signer: Signer; wallet?: never } | ||||||||||||||||||||
| { signer?: never; wallet: Wallet } | ||||||||||||||||||||
| { signer?: undefined; wallet?: undefined } | ||||||||||||||||||||
| { | ||||||||||||||||||||
signer: Signer; | ||||||||||||||||||||
solanaAdapter?: never; | ||||||||||||||||||||
solanaWallet?: never; | ||||||||||||||||||||
wallet?: never; | ||||||||||||||||||||
} | ||||||||||||||||||||
| { | ||||||||||||||||||||
signer?: never; | ||||||||||||||||||||
solanaAdapter: WalletContextState; | ||||||||||||||||||||
solanaWallet?: never; | ||||||||||||||||||||
wallet?: never; | ||||||||||||||||||||
} | ||||||||||||||||||||
| { | ||||||||||||||||||||
signer?: never; | ||||||||||||||||||||
solanaAdapter?: never; | ||||||||||||||||||||
solanaWallet: SolanaWallet; | ||||||||||||||||||||
wallet?: never; | ||||||||||||||||||||
} | ||||||||||||||||||||
| { | ||||||||||||||||||||
signer?: never; | ||||||||||||||||||||
solanaAdapter?: never; | ||||||||||||||||||||
solanaWallet?: never; | ||||||||||||||||||||
wallet: Wallet; | ||||||||||||||||||||
} | ||||||||||||||||||||
| { | ||||||||||||||||||||
signer?: undefined; | ||||||||||||||||||||
solanaAdapter?: undefined; | ||||||||||||||||||||
solanaWallet?: undefined; | ||||||||||||||||||||
wallet?: undefined; | ||||||||||||||||||||
} | ||||||||||||||||||||
); | ||||||||||||||||||||
|
||||||||||||||||||||
export class ZetaChainClient { | ||||||||||||||||||||
public chains: { [key: string]: any }; | ||||||||||||||||||||
public network: string; | ||||||||||||||||||||
public wallet: Wallet | undefined; | ||||||||||||||||||||
public signer: any | undefined; | ||||||||||||||||||||
public solanaWallet: SolanaWallet | undefined; | ||||||||||||||||||||
public solanaAdapter: WalletContextState | undefined; | ||||||||||||||||||||
|
||||||||||||||||||||
/** | ||||||||||||||||||||
* Initializes ZetaChainClient instance. | ||||||||||||||||||||
|
@@ -96,6 +128,10 @@ export class ZetaChainClient { | |||||||||||||||||||
this.wallet = params.wallet; | ||||||||||||||||||||
} else if (params.signer) { | ||||||||||||||||||||
this.signer = params.signer; | ||||||||||||||||||||
} else if (params.solanaWallet) { | ||||||||||||||||||||
this.solanaWallet = params.solanaWallet; | ||||||||||||||||||||
} else if (params.solanaAdapter) { | ||||||||||||||||||||
this.solanaAdapter = params.solanaAdapter; | ||||||||||||||||||||
} | ||||||||||||||||||||
this.chains = { ...networks }; | ||||||||||||||||||||
this.network = params.network || ""; | ||||||||||||||||||||
|
@@ -115,6 +151,16 @@ export class ZetaChainClient { | |||||||||||||||||||
return this.chains; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
public isSolanaWalletConnected(): boolean { | ||||||||||||||||||||
return this.solanaAdapter?.connected || this.solanaWallet !== undefined; | ||||||||||||||||||||
} | ||||||||||||||||||||
Comment on lines
+154
to
+156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure consistent return type in The method currently returns Modify the method to ensure it always returns a boolean: public isSolanaWalletConnected(): boolean {
- return this.solanaAdapter?.connected || this.solanaWallet !== undefined;
+ return (
+ (this.solanaAdapter ? this.solanaAdapter.connected : false) ||
+ (this.solanaWallet !== undefined)
+ );
} This change guarantees that the method returns 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||
|
||||||||||||||||||||
public getSolanaPublicKey(): PublicKey | null { | ||||||||||||||||||||
return ( | ||||||||||||||||||||
this.solanaAdapter?.publicKey || this.solanaWallet?.publicKey || null | ||||||||||||||||||||
); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
getEndpoint = getEndpoint; | ||||||||||||||||||||
getBalances = getBalances; | ||||||||||||||||||||
getForeignCoins = getForeignCoins; | ||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,5 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||
import * as anchor from "@coral-xyz/anchor"; | ||||||||||||||||||||||||||||||||||||||||
import { Keypair } from "@solana/web3.js"; | ||||||||||||||||||||||||||||||||||||||||
import { TransactionMessage, VersionedTransaction } from "@solana/web3.js"; | ||||||||||||||||||||||||||||||||||||||||
import { Transaction } from "@solana/web3.js"; | ||||||||||||||||||||||||||||||||||||||||
import { getEndpoints } from "@zetachain/networks"; | ||||||||||||||||||||||||||||||||||||||||
import { ethers } from "ethers"; | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
import { ZetaChainClient } from "./client"; | ||||||||||||||||||||||||||||||||||||||||
|
@@ -11,21 +13,53 @@ export const solanaDeposit = async function ( | |||||||||||||||||||||||||||||||||||||||
this: ZetaChainClient, | ||||||||||||||||||||||||||||||||||||||||
args: { | ||||||||||||||||||||||||||||||||||||||||
amount: number; | ||||||||||||||||||||||||||||||||||||||||
api: string; | ||||||||||||||||||||||||||||||||||||||||
idPath: string; | ||||||||||||||||||||||||||||||||||||||||
params: any[]; | ||||||||||||||||||||||||||||||||||||||||
recipient: string; | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||
const keypair = await getKeypairFromFile(args.idPath); | ||||||||||||||||||||||||||||||||||||||||
const wallet = new anchor.Wallet(keypair); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const connection = new anchor.web3.Connection(args.api); | ||||||||||||||||||||||||||||||||||||||||
const provider = new anchor.AnchorProvider( | ||||||||||||||||||||||||||||||||||||||||
connection, | ||||||||||||||||||||||||||||||||||||||||
wallet, | ||||||||||||||||||||||||||||||||||||||||
anchor.AnchorProvider.defaultOptions() | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
if (!this.isSolanaWalletConnected()) { | ||||||||||||||||||||||||||||||||||||||||
throw new Error("Solana wallet not connected"); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const network = "solana_" + this.network; | ||||||||||||||||||||||||||||||||||||||||
const api = getEndpoints("solana" as any, network); | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+24
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove unsafe type assertion in The -const api = getEndpoints("solana" as any, network);
+const api = getEndpoints("solana", network); Consider updating the 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const connection = new anchor.web3.Connection(api[0].url); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
let provider; | ||||||||||||||||||||||||||||||||||||||||
if (this.solanaAdapter) { | ||||||||||||||||||||||||||||||||||||||||
const walletAdapter = { | ||||||||||||||||||||||||||||||||||||||||
publicKey: this.solanaAdapter.publicKey!, | ||||||||||||||||||||||||||||||||||||||||
signAllTransactions: async (txs: Transaction[]) => { | ||||||||||||||||||||||||||||||||||||||||
if (!this.solanaAdapter?.signAllTransactions) { | ||||||||||||||||||||||||||||||||||||||||
throw new Error( | ||||||||||||||||||||||||||||||||||||||||
"Wallet does not support signing multiple transactions" | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
return await this.solanaAdapter.signAllTransactions(txs); | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
signTransaction: async (tx: Transaction) => { | ||||||||||||||||||||||||||||||||||||||||
if (!this.solanaAdapter?.signTransaction) { | ||||||||||||||||||||||||||||||||||||||||
throw new Error("Wallet does not support transaction signing"); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
return await this.solanaAdapter.signTransaction(tx); | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
provider = new anchor.AnchorProvider( | ||||||||||||||||||||||||||||||||||||||||
connection, | ||||||||||||||||||||||||||||||||||||||||
walletAdapter as any, | ||||||||||||||||||||||||||||||||||||||||
anchor.AnchorProvider.defaultOptions() | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+49
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid using the Casting You can define an interface and use it instead of + interface WalletAdapter {
+ publicKey: anchor.web3.PublicKey;
+ signAllTransactions: (txs: Transaction[]) => Promise<Transaction[]>;
+ signTransaction: (tx: Transaction) => Promise<Transaction>;
+ }
provider = new anchor.AnchorProvider(
connection,
- walletAdapter as any,
+ walletAdapter as WalletAdapter,
anchor.AnchorProvider.defaultOptions()
);
|
||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
} else if (this.solanaWallet) { | ||||||||||||||||||||||||||||||||||||||||
provider = new anchor.AnchorProvider( | ||||||||||||||||||||||||||||||||||||||||
connection, | ||||||||||||||||||||||||||||||||||||||||
this.solanaWallet, | ||||||||||||||||||||||||||||||||||||||||
anchor.AnchorProvider.defaultOptions() | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||
throw new Error("No valid Solana wallet found"); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
anchor.setProvider(provider); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const programId = new anchor.web3.PublicKey(Gateway_IDL.address); | ||||||||||||||||||||||||||||||||||||||||
|
@@ -58,53 +92,44 @@ export const solanaDeposit = async function ( | |||||||||||||||||||||||||||||||||||||||
.deposit(depositAmount, m) | ||||||||||||||||||||||||||||||||||||||||
.accounts({ | ||||||||||||||||||||||||||||||||||||||||
pda: pdaAccount, | ||||||||||||||||||||||||||||||||||||||||
signer: wallet.publicKey, | ||||||||||||||||||||||||||||||||||||||||
signer: this.solanaAdapter | ||||||||||||||||||||||||||||||||||||||||
? this.solanaAdapter.publicKey! | ||||||||||||||||||||||||||||||||||||||||
: this.solanaWallet!.publicKey, | ||||||||||||||||||||||||||||||||||||||||
systemProgram: anchor.web3.SystemProgram.programId, | ||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||
.instruction(); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
tx.add(depositInstruction); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Send the transaction | ||||||||||||||||||||||||||||||||||||||||
const txSignature = await anchor.web3.sendAndConfirmTransaction( | ||||||||||||||||||||||||||||||||||||||||
connection, | ||||||||||||||||||||||||||||||||||||||||
tx, | ||||||||||||||||||||||||||||||||||||||||
[keypair] | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
let txSignature; | ||||||||||||||||||||||||||||||||||||||||
if (this.solanaAdapter) { | ||||||||||||||||||||||||||||||||||||||||
const { blockhash, lastValidBlockHeight } = | ||||||||||||||||||||||||||||||||||||||||
await connection.getLatestBlockhash(); | ||||||||||||||||||||||||||||||||||||||||
const messageLegacy = new TransactionMessage({ | ||||||||||||||||||||||||||||||||||||||||
instructions: tx.instructions, | ||||||||||||||||||||||||||||||||||||||||
payerKey: this.solanaAdapter.publicKey!, | ||||||||||||||||||||||||||||||||||||||||
recentBlockhash: blockhash, | ||||||||||||||||||||||||||||||||||||||||
}).compileToV0Message(); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
console.log("Transaction signature:", txSignature); | ||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||
console.error("Transaction failed:", error); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||
const versionedTransaction = new VersionedTransaction(messageLegacy); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const getKeypairFromFile = async (filepath: string) => { | ||||||||||||||||||||||||||||||||||||||||
const path = await import("path"); | ||||||||||||||||||||||||||||||||||||||||
if (filepath[0] === "~") { | ||||||||||||||||||||||||||||||||||||||||
const home = process.env.HOME || null; | ||||||||||||||||||||||||||||||||||||||||
if (home) { | ||||||||||||||||||||||||||||||||||||||||
filepath = path.join(home, filepath.slice(1)); | ||||||||||||||||||||||||||||||||||||||||
txSignature = await this.solanaAdapter.sendTransaction( | ||||||||||||||||||||||||||||||||||||||||
versionedTransaction, | ||||||||||||||||||||||||||||||||||||||||
connection | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+106
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Utilize You retrieve Apply this change to include txSignature = await this.solanaAdapter.sendTransaction(
versionedTransaction,
connection,
+ {
+ minContextSlot: lastValidBlockHeight,
+ }
); This ensures that the transaction remains valid and provides additional safeguards against blockhash-related issues.
|
||||||||||||||||||||||||||||||||||||||||
txSignature = await anchor.web3.sendAndConfirmTransaction( | ||||||||||||||||||||||||||||||||||||||||
connection, | ||||||||||||||||||||||||||||||||||||||||
tx, | ||||||||||||||||||||||||||||||||||||||||
[this.solanaWallet!.payer] | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
// Get contents of file | ||||||||||||||||||||||||||||||||||||||||
let fileContents; | ||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||
const { readFile } = await import("fs/promises"); | ||||||||||||||||||||||||||||||||||||||||
const fileContentsBuffer = await readFile(filepath); | ||||||||||||||||||||||||||||||||||||||||
fileContents = fileContentsBuffer.toString(); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
console.log("Transaction signature:", txSignature); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
return txSignature; | ||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||
throw new Error(`Could not read keypair from file at '${filepath}'`); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
// Parse contents of file | ||||||||||||||||||||||||||||||||||||||||
let parsedFileContents; | ||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||
parsedFileContents = Uint8Array.from(JSON.parse(fileContents)); | ||||||||||||||||||||||||||||||||||||||||
} catch (thrownObject) { | ||||||||||||||||||||||||||||||||||||||||
const error: any = thrownObject; | ||||||||||||||||||||||||||||||||||||||||
if (!error.message.includes("Unexpected token")) { | ||||||||||||||||||||||||||||||||||||||||
throw error; | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
throw new Error(`Invalid secret key file at '${filepath}'!`); | ||||||||||||||||||||||||||||||||||||||||
console.error("Transaction failed:", error); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
132
to
134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Properly handle errors to prevent unexpected behavior. Currently, the function logs the error but does not rethrow it or return a value, which could lead to inconsistent behavior for callers expecting a transaction signature or an error. Modify the catch block to rethrow the error: console.error("Transaction failed:", error);
+ throw error; Alternatively, ensure the function returns a consistent result or handles the error appropriately. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
return Keypair.fromSecretKey(parsedFileContents); | ||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import { Wallet } from "@coral-xyz/anchor"; | ||
import { Keypair } from "@solana/web3.js"; | ||
import bech32 from "bech32"; | ||
import { utils } from "ethers"; | ||
import { task } from "hardhat/config"; | ||
|
@@ -9,7 +11,13 @@ export const solanaDeposit = async ( | |
args: any, | ||
hre: HardhatRuntimeEnvironment | ||
) => { | ||
const client = new ZetaChainClient({ network: "testnet" }); | ||
const keypair = await getKeypairFromFile(args.idPath); | ||
const wallet = new Wallet(keypair); | ||
|
||
const client = new ZetaChainClient({ | ||
network: args.solanaNetwork, | ||
solanaWallet: wallet, | ||
}); | ||
let recipient; | ||
try { | ||
if ((bech32 as any).decode(args.recipient)) { | ||
|
@@ -21,15 +29,46 @@ export const solanaDeposit = async ( | |
} catch (e) { | ||
recipient = args.recipient; | ||
} | ||
const { amount, api, idPath } = args; | ||
const { amount, idPath } = args; | ||
const params = [JSON.parse(args.types), args.values]; | ||
await client.solanaDeposit({ amount, api, idPath, params, recipient }); | ||
await client.solanaDeposit({ amount, params, recipient }); | ||
}; | ||
|
||
task("solana-deposit", "Solana deposit", solanaDeposit) | ||
.addParam("amount", "Amount of SOL to deposit") | ||
.addParam("recipient", "Universal contract address") | ||
.addOptionalParam("api", "Solana API", "https://api.devnet.solana.com") | ||
.addOptionalParam("solanaNetwork", "Solana Network", "devnet") | ||
.addOptionalParam("idPath", "Path to id.json", "~/.config/solana/id.json") | ||
.addParam("types", "The types of the parameters (example: ['string'])") | ||
.addVariadicPositionalParam("values", "The values of the parameters"); | ||
|
||
export const getKeypairFromFile = async (filepath: string) => { | ||
const path = await import("path"); | ||
if (filepath[0] === "~") { | ||
const home = process.env.HOME || null; | ||
if (home) { | ||
filepath = path.join(home, filepath.slice(1)); | ||
Comment on lines
+48
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use 'os.homedir()' for cross-platform home directory resolution Using Apply this diff: +import os from "os";
...
- const home = process.env.HOME || null;
+ const home = os.homedir();
|
||
} | ||
} | ||
// Get contents of file | ||
let fileContents; | ||
try { | ||
const { readFile } = await import("fs/promises"); | ||
const fileContentsBuffer = await readFile(filepath); | ||
fileContents = fileContentsBuffer.toString(); | ||
} catch (error) { | ||
throw new Error(`Could not read keypair from file at '${filepath}'`); | ||
} | ||
// Parse contents of file | ||
let parsedFileContents; | ||
try { | ||
parsedFileContents = Uint8Array.from(JSON.parse(fileContents)); | ||
} catch (thrownObject) { | ||
const error: any = thrownObject; | ||
if (!error.message.includes("Unexpected token")) { | ||
throw error; | ||
} | ||
throw new Error(`Invalid secret key file at '${filepath}'!`); | ||
} | ||
return Keypair.fromSecretKey(parsedFileContents); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add checks for multiple wallet parameters in the constructor
Currently, the constructor checks for both
wallet
andsigner
being provided but doesn't handle cases where multiple Solana wallet parameters are supplied together. To prevent conflicting wallet parameters, ensure that only one wallet type is provided at a time.You can update the constructor to include these checks:
This ensures that if more than one wallet parameter is provided, an error is thrown.
📝 Committable suggestion