* Chore: init * chore: init * feat: added basic dapps and improved README * fix: Unified env.example and added comments with instructions * fix: better usage instruction in readme * fix: removed advanced section * fix: added dapps and wallets * fix: added web3inbox * Update basic/dapps/web3inbox/README.md Co-authored-by: Ben Kremer <ben@walletconnect.com> * Update basic/dapps/ethereum-provider/src/App.tsx Co-authored-by: Gancho Radkov <43912948+ganchoradkov@users.noreply.github.com> * chore: added detailed README for basic section * chore(deps): updated deps for universal-provider-solana * fix: multiple suggestions --------- Co-authored-by: Boidushya Bhattacharya <boidushyabhattacharya@gmail.com> Co-authored-by: Ben Kremer <ben@walletconnect.com> Co-authored-by: Gancho Radkov <43912948+ganchoradkov@users.noreply.github.com>
176 lines
4.5 KiB
TypeScript
176 lines
4.5 KiB
TypeScript
import {
|
|
Connection,
|
|
PublicKey,
|
|
SystemProgram,
|
|
Transaction,
|
|
VersionedTransaction,
|
|
clusterApiUrl,
|
|
} from "@solana/web3.js";
|
|
import UniversalProvider from "@walletconnect/universal-provider/dist/types/UniversalProvider";
|
|
import bs58 from "bs58";
|
|
import nacl from "tweetnacl";
|
|
|
|
export enum SolanaChains {
|
|
MainnetBeta = "4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ",
|
|
Devnet = "8E9rvCKLFQia2Y35HXjjpWzj8weVo44K",
|
|
}
|
|
|
|
export function verifyTransactionSignature(
|
|
address: string,
|
|
signature: string,
|
|
tx: Transaction
|
|
) {
|
|
return nacl.sign.detached.verify(
|
|
tx.serializeMessage(),
|
|
bs58.decode(signature),
|
|
bs58.decode(address)
|
|
);
|
|
}
|
|
|
|
export function verifyMessageSignature(
|
|
address: string,
|
|
signature: string,
|
|
message: string
|
|
) {
|
|
return nacl.sign.detached.verify(
|
|
bs58.decode(message),
|
|
bs58.decode(signature),
|
|
bs58.decode(address)
|
|
);
|
|
}
|
|
|
|
const isVersionedTransaction = (
|
|
transaction: Transaction | VersionedTransaction
|
|
): transaction is VersionedTransaction => "version" in transaction;
|
|
|
|
|
|
export const getProviderUrl = (chainId: string) => {
|
|
return `https://rpc.walletconnect.com/v1/?chainId=${chainId}&projectId=${
|
|
import.meta.env.VITE_PROJECT_ID
|
|
}`;
|
|
};
|
|
|
|
export const signMessage = async (
|
|
msg: string,
|
|
provider: UniversalProvider,
|
|
address: string
|
|
) => {
|
|
const senderPublicKey = new PublicKey(address);
|
|
|
|
const message = bs58.encode(new TextEncoder().encode(msg));
|
|
|
|
try {
|
|
const result = await provider!.request<{ signature: string }>({
|
|
method: "solana_signMessage",
|
|
params: {
|
|
pubkey: senderPublicKey.toBase58(),
|
|
message,
|
|
},
|
|
});
|
|
|
|
const valid = verifyMessageSignature(
|
|
senderPublicKey.toBase58(),
|
|
result.signature,
|
|
message
|
|
);
|
|
|
|
return {
|
|
method: "solana_signMessage",
|
|
address,
|
|
valid,
|
|
result: result.signature,
|
|
};
|
|
//eslint-disable-next-line
|
|
} catch (error: any) {
|
|
throw new Error(error);
|
|
}
|
|
};
|
|
|
|
export const sendTransaction = async (
|
|
to: string,
|
|
amount: number,
|
|
provider: UniversalProvider,
|
|
address: string
|
|
) => {
|
|
const isTestnet = provider.session!.namespaces.solana.chains?.includes(
|
|
`solana:${SolanaChains.Devnet}`
|
|
);
|
|
|
|
const senderPublicKey = new PublicKey(address);
|
|
|
|
const connection = new Connection(
|
|
isTestnet
|
|
? clusterApiUrl("testnet")
|
|
: getProviderUrl(`solana:${SolanaChains.MainnetBeta}`)
|
|
);
|
|
|
|
const { blockhash } = await connection.getLatestBlockhash();
|
|
|
|
const transaction:Transaction | VersionedTransaction = new Transaction({
|
|
feePayer: senderPublicKey,
|
|
recentBlockhash: blockhash,
|
|
}).add(
|
|
SystemProgram.transfer({
|
|
fromPubkey: senderPublicKey,
|
|
toPubkey: new PublicKey(to),
|
|
lamports: amount,
|
|
})
|
|
);
|
|
|
|
let rawTransaction: string;
|
|
let legacyTransaction: Transaction | VersionedTransaction | undefined;
|
|
|
|
if (isVersionedTransaction(transaction)) {
|
|
// V0 transactions are serialized and passed in the `transaction` property
|
|
rawTransaction = Buffer.from(transaction.serialize()).toString(
|
|
"base64"
|
|
);
|
|
|
|
if (transaction.version === "legacy") {
|
|
// For backwards-compatible, legacy transactions are spread in the params
|
|
legacyTransaction = Transaction.from(transaction.serialize());
|
|
}
|
|
} else {
|
|
rawTransaction = transaction
|
|
.serialize({
|
|
requireAllSignatures: false,
|
|
verifySignatures: false,
|
|
})
|
|
.toString("base64");
|
|
legacyTransaction = transaction;
|
|
}
|
|
|
|
try {
|
|
const result = await provider!.request<{ signature: string }>({
|
|
method: "solana_signTransaction",
|
|
params: {
|
|
// Passing ...legacyTransaction is deprecated.
|
|
// All new clients should rely on the `transaction` parameter.
|
|
// The future versions will stop passing ...legacyTransaction.
|
|
...legacyTransaction,
|
|
// New base64-encoded serialized transaction request parameter
|
|
transaction: rawTransaction,
|
|
},
|
|
});
|
|
|
|
// We only need `Buffer.from` here to satisfy the `Buffer` param type for `addSignature`.
|
|
// The resulting `UInt8Array` is equivalent to just `bs58.decode(...)`.
|
|
transaction.addSignature(
|
|
senderPublicKey,
|
|
Buffer.from(bs58.decode(result.signature))
|
|
);
|
|
|
|
const valid = transaction.verifySignatures();
|
|
|
|
return {
|
|
method: "solana_signTransaction",
|
|
address,
|
|
valid,
|
|
result: result.signature,
|
|
};
|
|
// eslint-disable-next-line
|
|
} catch (error: any) {
|
|
throw new Error(error);
|
|
}
|
|
};
|