How do I "unwrap SOL" using the web3 sdk? - solana

I need to unwrap some SOL using the web3 sdk. I'm wondering, Is it just a simple transfer from the wrapped account into SOL account or is it more complicated than that? Below Is just some sample code I've setup.
const emptyWSolAccount = async (amount:any) => {
const wsolAddress = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
new PublicKey("So11111111111111111111111111111111111111112"),
wallet.publicKey
);
const wsolAccount = await connection.getAccountInfo(wsolAddress);
if (wsolAccount) {
const transaction = new Transaction({
feePayer: wallet.publicKey,
});
const instructions = [];
const lamports = amount * LAMPORTS_PER_SOL;
instructions.push(
SystemProgram.transfer({
fromPubkey: wsolAddress,
toPubkey: wallet.publicKey,
lamports: lamports, // 1 sol
})
);
transaction.add(...instructions);
transaction.recentBlockhash = await (
await connection.getRecentBlockhash()
).blockhash;
transaction.partialSign(wallet.payer);
const result = await connection.sendTransaction(transaction, [
wallet.payer,
]);
console.log({ result });
return { result };
}
return ;
};

This is not really explained anywhere, but unwrapping SOL actually means closing the wrapped SOL account.
So instead of using a SystemProgram.transfer instruction, you'll do:
instructions.push(
splToken.instructions.createCloseAccountInstruction(
wsolAddress,
wallet.publicKey,
wallet.publicKey,
)
);
This closes wsolAddress and sends the contents to wallet, assuming that wallet is the owner.
You can see the CLI implementation at https://github.com/solana-labs/solana-program-library/blob/3db53e278b543a040d3c970797b6be6f9ea5aef9/token/cli/src/main.rs#L1139-L1194

Related

Why is this contract call failing (rust-counter increment)?

I am attempting to call the increment in the counter contract here, which is deployed to my account on testnet, using the following script:
const nearAPI = require("near-api-js");
require("dotenv").config();
const {parseSeedPhrase} = require("near-seed-phrase");
async function call() {
const mneumonic = process.env.nearmneumonic0?.trim() || "";
const ACCOUNT_ID = process.env.nearacct0?.trim() || "";
const keyStores = nearAPI.keyStores;
const keyPair = nearAPI.KeyPair;
const connect = nearAPI.connect;
const keyStore = new keyStores.InMemoryKeyStore();
const PRIVATE_KEY = parseSeedPhrase(mneumonic);
const keyPair_ = keyPair.fromString(PRIVATE_KEY.secretKey);
await keyStore.setKey("testnet", ACCOUNT_ID, keyPair_);
const config = {
keyStore,
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
};
const near = await connect(config);
const account = await near.account(ACCOUNT_ID);
const contract = new nearAPI.Contract(
account,
ACCOUNT_ID,
{
changeMethods: ["increment", "decrement", "reset"],
viewMethods: ["get_num"],
sender: account,
}
);
let response = await contract.increment(
{
args: {
//arg_name: "value"
},
gas: 300000000000000
}
);
console.log(response);
}
call();
However, the response thrown is al followed:
Failure [acct.testnet]: Error: Contract method is not found
...
ServerTransactionError: Contract method is not found
I have looked through some of the docs, which mention to add changeMethod/viewMethod, however it seems there is still errors thrown.
Any help much appreciated!

Retrying failed custom token transaction with '#solana/web3.js'

I want to send my deployed token other than sol using solana web3.js. My code works most of the time but sometimes the transaction fails.
I put a while loop so that when the transaction fails the client retries it with the sendRawTransaction function. The problem is that when it fails the first time it always fails after it.
const provider = await this.getProvider();
const publicKey = new web3.PublicKey(this.wallet);
const toPublicKey = new web3.PublicKey(
"the public key to send"
);
const mint = new web3.PublicKey(
"my token adress"
);
const connection = await new Connection(clusterApiUrl("mainnet-beta"));
const { signTransaction } = useWallet();
const fromTokenAccount = await this.getOrCreateAssociatedTokenAccount(
connection,
publicKey,
mint,
publicKey,
signTransaction
)
});
const toTokenAccount = await this.getOrCreateAssociatedTokenAccount(
connection,
publicKey,
mint,
toPublicKey,
signTransaction
);
const transferInstruction = await this.createTransferInstruction(
fromTokenAccount.address, // source
toTokenAccount.address, // dest
publicKey,
amount,
[],
TOKEN_PROGRAM_ID
);
const transaction = new Transaction().add(transferInstruction);
var blockHash = await connection.getLatestBlockhash('finalized');
transaction.feePayer = await publicKey;
console.log(blockHash.blockhash)
transaction.recentBlockhash = blockHash.blockhash;
// const provider = await this.getProvider();
const signed = await provider.signTransaction(transaction);
window.createEvent('openPopup', {
text: 'Your transaction is being validated by the Solana blockchain.',
loading: 30,
show: true
})
var nbRetry = 0;
while(true){
const signature = await connection.sendRawTransaction(signed.serialize())
this.post(`verifyTransaction`, {
signature,
})
.then(() => {
window.location.assign('/transaction_success')
})
.catch(async (error) => {
if (error.response.status === 403) {
if (nbRetry > 5){
window.createEvent('openPopup', {
show: true,
image: 'error.png',
text: 'The transaction failed.',
reload: true
})} else nbRetry++;
}}
})

Signature verification failed When transferring spl-token to user connected phantom wallet

bs58.decode(
"2YQDdnfxiHPKu9GypLX1yXaQTQojvDSPgFkDxrU********************************************"
)
const mintPubkey =
"A8SJfwzKJAaMrY6Lb*************************";
const getProvider = async () => {
// opens wallet to connect to
await window.solana.connect();
const provider = window.solana;
}
const network = "https://api.devnet.solana.com";
const connection = new Connection(network);
var provider = await getProvider()
console.log(provider.publicKey.toString())
const userWalletPublicKey = provider.publicKey;
var myMint = new PublicKey(mintPubkey);
var myToken = new Token(
connection,
myMint,
TOKEN_PROGRAM_ID,
alice
);
const fromTokenAccount = await myToken.getOrCreateAssociatedAccountInfo(
alice.publicKey,
);
const toTokenAccount = await myToken.getOrCreateAssociatedAccountInfo(
userWalletPublicKey,
);
// Add token transfer instructions to transaction
const transaction = new Transaction().add(
Token.createTransferInstruction(
TOKEN_PROGRAM_ID,
fromTokenAccount.address,
toTokenAccount.address,
alice.publicKey,
[],
1,
),
);
transaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
transaction.feePayer = userWalletPublicKey;
const signedTransaction = await window.solana.signTransaction(transaction);
const signature = await connection.sendRawTransaction(signedTransaction.serialize());
when I try to approve the transection it gives me signature verification failed
I am using SPL-TOKEN Library and Solana web3 js
did I implement the spl-transfer token with phantom correctly?
Your help on this will be much appreciated
basically i am trying to make when a user click on buy it transfer the nft present in my wallet to the guy's wallet who connected and clicked on buy

How to send USDC-SPL using #solana-labs/web3.js

I'm able to send SOL tokens using web3.js but have been unable to do so with USDC-SPL tokens. This is my current code for sending SOL tokens:
// .......
const connection = new Connection(network);
const transaction = new Transaction()
.add(
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: to,
lamports: Number(amount) * 1000000000,
})
);
const { blockhash } = await connection.getRecentBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
let signedTransaction: any = null;
if ("solana" in window) {
signedTransaction = await window.solana.signTransaction(transaction)
} else if ("solflare" in window) {
signedTransaction = await window.solflare.signTransaction(transaction);
}
// .......
The answers I've seen earlier are from people sending their own custom made tokens
All SPL tokens (including USDC token) on Solana are owned by spl-token program.
So you can send USDC in the same way as sending your own custom made tokens by changing the token address to
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (this is the USDC SPL token address on solana mainnet).
For example:
import * as web3 from "#solana/web3.js";
import * as splToken from "#solana/spl-token";
const DEMO_WALLET_SECRET_KEY = new Uint8Array([
...
]);
const SOLANA_MAINNET_USDC_PUBKEY = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
(async () => {
// Connect to cluster
var connection = new web3.Connection(web3.clusterApiUrl("devnet"));
// Construct wallet keypairs
var fromWallet = web3.Keypair.fromSecretKey(DEMO_WALLET_SECRET_KEY);
var toWallet = web3.Keypair.generate();
// Construct my token class
var USDC_pubkey = new web3.PublicKey(SOLANA_MAINNET_USDC_PUBKEY);
var USDC_Token = new splToken.Token(
connection,
USDC_pubkey,
splToken.TOKEN_PROGRAM_ID,
fromWallet
);
// Create associated token accounts for my token if they don't exist yet
var fromTokenAccount = await USDC_Token.getOrCreateAssociatedAccountInfo(
fromWallet.publicKey
)
var toTokenAccount = await USDC_Token.getOrCreateAssociatedAccountInfo(
toWallet.publicKey
)
// Add token transfer instructions to transaction
var transaction = new web3.Transaction()
.add(
splToken.Token.createTransferInstruction(
splToken.TOKEN_PROGRAM_ID,
fromTokenAccount.address,
toTokenAccount.address,
fromWallet.publicKey,
[],
0
)
);
// Sign transaction, broadcast, and confirm
var signature = await web3.sendAndConfirmTransaction(
connection,
transaction,
[fromWallet]
);
console.log("SIGNATURE", signature);
console.log("SUCCESS");
})();

Update Metadata of Metaplex NFT

I have some problem in updating Metaplex NFT Metadata.
I used #metaplex/js and this is my code.
import { programs } from '#metaplex/js';
export const updateMetadataV1 = async () => {
let { metadata : {Metadata, UpdateMetadata, MetadataDataData, Creator} } = programs;
let signer = loadWalletKey(keyfile);
let nftMintAccount = new PublicKey("EC8gGdtVFDoTf3vEGbLvPp7SVWta2xQrs99iWMbaFrdE");
let metadataAccount = await Metadata.getPDA(nftMintAccount);
const metadat = await Metadata.load(solConnection, metadataAccount);
let newUri = "https://arweave.net/my arweave address";
if (metadat.data.data.creators != null) {
const creators = metadat.data.data.creators.map(
(el) =>
new Creator({
...el,
}),
);
let newMetadataData = new MetadataDataData({
name: metadat.data.data.name,
symbol: metadat.data.data.symbol,
uri: newUri,
creators: [...creators],
sellerFeeBasisPoints: metadat.data.data.sellerFeeBasisPoints,
})
const updateTx = new UpdateMetadata(
{ feePayer: signer.publicKey },
{
metadata: metadataAccount,
updateAuthority: signer.publicKey,
metadataData: newMetadataData,
newUpdateAuthority: signer.publicKey,
primarySaleHappened: metadat.data.primarySaleHappened,
},
);
let result = await sendAndConfirmTransaction(solConnection, updateTx, [signer]);
console.log("result =", result);
}
}
The transaction result has no error, it means transaction success.
I checked it on Solana Explorer.
But the metadata doesn't change. What's the matter?
To Solve this issue this code can be used, This is a low-level code that uses the mpl-token-metadata npm package to call the on-chain updateMetadata Function.
import { Wallet } from "#project-serum/anchor";
import * as anchor from "#project-serum/anchor";
import {createUpdateMetadataAccountV2Instruction,DataV2,UpdateMetadataAccountV2InstructionArgs,UpdateMetadataAccountV2InstructionAccounts} from "#metaplex-foundation/mpl-token-metadata"
const fs = require("fs");
(async() => {
// This is the Update Authority Secret Key
const secretKey = fs.readFileSync(
"/Users/pratiksaria/.config/solana/id.json",
"utf8"
);
const keypair = anchor.web3.Keypair.fromSecretKey(
Buffer.from(JSON.parse(secretKey))
);
const endpoint = "https://metaplex.devnet.rpcpool.com/";
const connection = new anchor.web3.Connection(endpoint);
const wallet = new Wallet(keypair);
console.log("Connected Wallet", wallet.publicKey.toString());
const TOKEN_METADATA_PROGRAM_ID = new anchor.web3.PublicKey(
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
);
// You have to enter your NFT Mint address Over Here
const mintKey = new anchor.web3.PublicKey("5iSxT33FyHWsnb8NYSytY17TTXfkFn62FiCyFVFxYhqY");
const [metadatakey] = await anchor.web3.PublicKey.findProgramAddress(
[
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
mintKey.toBuffer(),
],
TOKEN_METADATA_PROGRAM_ID
);
// BTW DeGods is my FAV collection although i cant afford one 🥲
const updated_data: DataV2 = {
name: "DeGods",
symbol: "DG",
uri: "https://metadata.degods.com/g/4924.json",
sellerFeeBasisPoints: 1000,
creators: [
{
address: new anchor.web3.PublicKey(
"CsEYyFxVtXxezfLTUWYwpj4ia5oCAsBKznJBWiNKLyxK"
),
verified: false,
share: 0,
},
{
address: wallet.publicKey,
verified: false,
share: 100,
},
],
collection: null,
uses: null,
};
const accounts:UpdateMetadataAccountV2InstructionAccounts = {
metadata: metadatakey,
updateAuthority: wallet.publicKey,
}
const args:UpdateMetadataAccountV2InstructionArgs = {
updateMetadataAccountArgsV2: {
data: updated_data,
updateAuthority: wallet.publicKey,
primarySaleHappened: true,
isMutable: true,
}
}
const updateMetadataAccount = createUpdateMetadataAccountV2Instruction(
accounts,
args
);
const transaction = new anchor.web3.Transaction()
transaction.add(updateMetadataAccount);
const {blockhash} = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = wallet.publicKey;
const signedTx = await wallet.signTransaction(transaction);
const txid = await connection.sendRawTransaction(signedTx.serialize());
console.log("Transaction ID --",txid);
})()
let blockhashObj = await solConnection.getLatestBlockhash();
updateTx.recentBlockhash = blockhashObj.blockhash;
updateTx.sign(alice);
let endocdeTransction = updateTx.serialize({
requireAllSignatures: false,
verifySignatures: false,
});
var signature = await solConnection.sendRawTransaction(endocdeTransction, {
skipPreflight: false,
});

Resources