Am working with Solana Blockchain. Am trying to transfer Solana SOL via Phantom. To this effect I used the code below which was leveraged in stackoverflow. source link
I already have Phantom installed in my chrome browser .
when I run the code, It displays error
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'toString')
I think its this line of code that is causing the error above
console.log("Public key of the emitter: ",provider.publicKey.toString());
Here is the Code
import * as web3 from '@solana/web3.js';
import * as splToken from '@solana/spl-token';
const getProvider = async () => {
if ("solana" in window) {
const provider = window.solana;
if (provider.isPhantom) {
console.log("Is Phantom installed? ", provider.isPhantom);
return provider;
}
} else {
window.open("https://www.phantom.app/", "_blank");
}
};
async function transferSOL() {
// Detecing and storing the phantom wallet of the user (creator in this case)
var provider = await getProvider();
console.log("Public key of the emitter: ",provider.publicKey.toString());
// Establishing connection
var connection = new web3.Connection(
web3.clusterApiUrl('devnet'),
);
// I have hardcoded my secondary wallet address here. You can take this address either from user input or your DB or wherever
var recieverWallet = new web3.PublicKey("CkiKLEa9eSEoG6CoTSuaahsF2WqNgArnvoCSbNZjJ7BQ");
// Airdrop some SOL to the sender's wallet, so that it can handle the txn fee
var airdropSignature = await connection.requestAirdrop(
provider.publicKey,
web3.LAMPORTS_PER_SOL,
);
// Confirming that the airdrop went through
await connection.confirmTransaction(airdropSignature);
console.log("Airdropped");
var transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
fromPubkey: provider.publicKey,
toPubkey: recieverWallet,
lamports: web3.LAMPORTS_PER_SOL //Investing 1 SOL. Remember 1 Lamport = 10^-9 SOL.
}),
);
// Setting the variables for the transaction
transaction.feePayer = await provider.publicKey;
let blockhashObj = await connection.getRecentBlockhash();
transaction.recentBlockhash = await blockhashObj.blockhash;
// Transaction constructor initialized successfully
if(transaction) {
console.log("Txn created successfully");
}
// Request creator to sign the transaction (allow the transaction)
let signed = await provider.signTransaction(transaction);
// The signature is generated
let signature = await connection.sendRawTransaction(signed.serialize());
// Confirm whether the transaction went through or not
await connection.confirmTransaction(signature);
//Signature chhap diya idhar
console.log("Signature: ", signature);
}
I'm not sure if this is the best solution going ahead, but yours is a problem of the persistence of the phantom wallet after the user signs in. You'll have to go for front-end heavy solution for this. One of which is:
import React, { createContext, useState} from "react"; export const WalletDataContext=createContext(); export const WalletDataContextProvider=(props)=>{ const [publicKey,setPublicKey]=useState(null); const [wallet,setWallet]=useState(null); return ( <WalletDataContext.Provider value={{publicKey,setPublicKey,wallet,setWallet}} > {props.children} </WalletDataContext.Provider> ) }
Create a connectWallet function, something like this:
//import {WalletDataContext} //import other stuff: const {setPublicKey,setWallet}=useContext(WalletDataContext) const connectWallet = async() { const provider = await getProvider(); if(provider) { await provider.connect(); let publicKey = ""; provider.on("connect", async () => { setWallet(provider); publicKey = provider.pubicKey.toString(); setPublicKey(publicKey); /* // more things that you would like to do here */ }); } }
Make the following changes in your transferSOL function:
async function transferSOL() { //Changes are only here, in the beginning const phantomProvider = wallet; if(!phantomProvider){ //Urge the user to sign in(connect) again } const pubKey = await phantomProvider.publicKey; console.log("Public Key: ", pubKey); // Establishing connection var connection = new web3.Connection( web3.clusterApiUrl('devnet'), ); // I have hardcoded my secondary wallet address here. You can take this address either from user input or your DB or wherever var recieverWallet = new web3.PublicKey("CkiKLEa9eSEoG6CoTSuaahsF2WqNgArnvoCSbNZjJ7BQ"); // Airdrop some SOL to the sender's wallet, so that it can handle the txn fee var airdropSignature = await connection.requestAirdrop( provider.publicKey, web3.LAMPORTS_PER_SOL, ); // Confirming that the airdrop went through await connection.confirmTransaction(airdropSignature); console.log("Airdropped"); var transaction = new web3.Transaction().add( web3.SystemProgram.transfer({ fromPubkey: provider.publicKey, toPubkey: recieverWallet, lamports: web3.LAMPORTS_PER_SOL //Investing 1 SOL. Remember 1 Lamport = 10^-9 SOL. }), ); // Setting the variables for the transaction transaction.feePayer = await provider.publicKey; let blockhashObj = await connection.getRecentBlockhash(); transaction.recentBlockhash = await blockhashObj.blockhash; // Transaction constructor initialized successfully if(transaction) { console.log("Txn created successfully"); } // Request creator to sign the transaction (allow the transaction) let signed = await provider.signTransaction(transaction); // The signature is generated let signature = await connection.sendRawTransaction(signed.serialize()); // Confirm whether the transaction went through or not await connection.confirmTransaction(signature); //Signature or the txn hash console.log("Signature: ", signature); }
You need to connect to the wallet. That part is missing
const getProvider = async () => {
if ("solana" in window) {
// opens wallet to connect to
await window.solana.connect();
const provider = window.solana;
if (provider.isPhantom) {
console.log("Is Phantom installed? ", provider.isPhantom);
return provider;
}
} else {
window.open("https://www.phantom.app/", "_blank");
}
};
The phantom team has an example of transferring sol from the user's wallet to another address: https://codesandbox.io/s/github/phantom-labs/sandbox?file=/src/App.tsx
Note:
TLDR:
import { Connection, PublicKey, clusterApiUrl } from "@solana/web3.js";
//3
const createTransaction = async(instructions) => {
const anyTransaction = new web3.Transaction().add(instructions);
anyTransaction.feePayer = getProvider().publicKey;
console.log("Getting Recent Blockhash");
anyTransaction.recentBlockhash = (
await getConnectionProvider().connection.getRecentBlockhash()
).blockhash;
return anyTransaction;
}
//2
const createTransferTransaction = async (from, to, amount) => {
return createTransaction(
web3.SystemProgram.transfer({
fromPubkey: from,
toPubkey: to,
lamports: 100000 * amount,
}));
}
//1 The interesting part
//from and to are pubkey objects (not strings!)
const sendTransaction = async(from, to, amount) => {
try {
console.log(`sending ${amount} from: ${from}, to: ${to}`);
let { signature } = await
getProvider().signAndSendTransaction(await createTransferTransaction(from, to, amount));
console.log("Submitted transaction " + signature + ", awaiting confirmation");
await connection.confirmTransaction(signature);
console.log("Transaction " + signature + " confirmed");
} catch (err) {
console.warn(err);
console.error("Error: " + JSON.stringify(err));
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.