method: "hardhat_impersonateAccount" - What happens when you call this method with an address that doesn't exist? - fork

async function impersonateAccount(acctAddress) {
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [acctAddress],
});
return await ethers.getSigner(acctAddress);
}
When forking the blockchain locally on Hardhat, the function above allows developers to impersonate the address passed as argument to it.
So you can create transactions as if you're the owner of the account.
What happens when forking the mainnet, and you pass an address that does not exist on the mainnet as an argument?
Would it throw an error?
Does it create the account for you locally and give you access?

It will create the account locally with a balance of 0 ETH.
I tried this with the Ropsten address 0xFD391b604E9456c0Ec4aC13Cc881FbAF68868eB2, which currently has 210 testnet ETH and does not exist on the mainnet.
With your code example it will return a valid signer, and if you check the balance of the signer's address it will have 0 ETH.

Related

Solana: Check if deposit is finalized?

How can we check if a deposit is finalized using solana/web3.js? I've tried using getTransaction with commitment parameter finalized and I did get a response with slot number. However, it took a few more seconds for Solana Explorer to show status Finalized. This probably means receiving slot number in a response to getTransaction doesn't necessarily mean a deposit is finalized?
Have you tried using 'confirmed' instead?
https://solana-labs.github.io/solana-web3.js/modules.html#Finality
You can use Connection.confirmTransaction with the finalized commitment to check that a transaction has landed. For example:
const signature = await connection.sendTransaction(transaction, signers);
const status = await connection.confirmTransaction(
{
signature: signature,
blockhash: transaction.recentBlockhash,
lastValidBlockHeight: transaction.lastValidBlockHeight,
},
)
).value;
if (status.err) {
throw new Error(
`Transaction ${signature} failed (${JSON.stringify(status)})`,
);
}
This was lifted from https://github.com/solana-labs/solana/blob/master/web3.js/src/util/send-and-confirm-transaction.ts

Could not create program address with signer seeds when creating a token account

I have a PDA and I'm trying to create a token account for it, using Solana Spl Associated Token Account(https://spl.solana.com/associated-token-account):
let (token_account_key, token_account_key_bump_seed) = Pubkey::find_program_address(&[&stake_info_bytes, &token_program_bytes, &mint_address_bytes], spl_associated_token_program.key);
Now I'm trying to create the account:
let account_rent = rent.minimum_balance(Account::LEN);
let authority_signature_seeds = [&stake_info_bytes[..32], &token_program_bytes[..32], &mint_address_bytes[..32], &[token_account_key_bump_seed]];
let signers = &[&authority_signature_seeds[..]];
let create_ix = create_account(
feepayer.key,
token_account.key,
account_rent,
Account::LEN as u64,
spl_associated_token_program.key
);
invoke_signed(&create_ix, &[
spl_associated_token_program.clone(),
feepayer.clone(),
token_account.clone()
], signers);
But I'm getting this error:
> Program returned error: Could not create program address with signer seeds: Provided seeds do not result in a valid address
With PDAs, your program can only "sign" for PDAs generated using its program id. In this case, your program is using the associated token account program as the program id, when it should be using itself. So this should become:
let (token_account_key, token_account_key_bump_seed) = Pubkey::find_program_address(&[&stake_info_bytes, &token_program_bytes, &mint_address_bytes], my_program_id);
Using your program's id as my_program_id, and then you would actually use this as:
let create_ix = create_account(
feepayer.key,
token_account.key,
account_rent,
Account::LEN as u64,
spl_token_program.key
);
invoke_signed(&create_ix, &[
feepayer.clone(),
token_account.clone()
], signers);
Note: I'm assuming that you're trying to create a token account, which must be owned by the token program.
Otherwise, it would be possible to fake "signatures" for another program, which would be a huge security risk. For example, associated token accounts must be signed and created by the associated token account program.

How to check instruction in Solana on-chain program?

I am developing game, which guesses number and get reward if they success.
This is summary of my program.
First, user send amount of sol and his guessing number.
Second, Program get random number and store user's sol to vault.
Third, Program make random number, if user is right, gives him reward.
Here, how can I check if the user sent correct amount of sol in program?
This is test code for calling program.
const result = await program.rpc.play(
new anchor.BN(40),
new anchor.BN(0),
new anchor.BN(20000000),
_nonce, {
accounts: {
vault: vaultPDA,
user: provider.wallet.publicKey, // User wallet
storage: storageAccount.publicKey,
systemProgram: systemProgram
},
instructions: [
SystemProgram.transfer({
fromPubkey: provider.wallet.publicKey,
toPubkey: vaultPDA,`enter code here`
lamports: 20000000`enter code here`
})
],
signers: [storageAccount]`enter code here`
}
)
The best solution would be to directly transfer the lamports inside of your program using a cross-program invocation, like this program: Cross-program invocation with unauthorized signer or writable account
Otherwise, from within your program, you can check the lamports on the AccountInfo passed, and make sure it's the proper number, similar to this example: https://solanacookbook.com/references/programs.html#transferring-lamports
The difference there is that you don't need to move the lamports.

My Token.createMintToInstruction is throwing "Error processing instruction 0: invalid account data for instruction"

I'm trying to mint some tokens on the frontend like this:
let transaction = new Transaction();
let mintToInstruction = Token.createMintToInstruction(
splToken.TOKEN_PROGRAM_ID,
myTokenMint.publicKey,
userAccount.publicKey,
airdropAdmin.publicKey,
[],
sendAmount.toNumber()
)
transaction.add(mintToInstruction);
let conn: Connection = ctx.connection;
const tx1 = await conn.sendTransaction(
transaction,
[airdropAdmin]
);
But I get an obscure error:
Error processing Instruction 0: invalid account data for instruction
What's happening?
One of the accounts you're passing in is not the account the Token Program expected.
Either:
The userAccount is incorrect. This must be a Token Account, did you use the user's System Account instead?
The myMintAccount is incorrect. Is this a real token mint?
Consider logging those public keys and putting them into the explorer. Does the userAccount say "Token Account" at the top? Does the myMintAccount say "Token Mint"?
The invalid account data for instruction typically happens when a program can't run unpack on the data inside the account you're passing in.
So either the Account::unpack is failing, or the the Mint::unpack is failing.

decorator still calls function after failing

I understand why the error check is printed, but I don't understand why despite the fact that the user calling does not have the mod label, it runs the function anyway, maybe I don't really understand decorators (user also has a token role but I commented that part out for this test)
# token check
#bot.command(name='wallet', help='display if a token is available for user')
#commands.has_role('mod') # remove later
# #commands.has_any_role('PBToken 3', 'PBToken 6')
async def token_check(ctx):
name = ctx.author.name
response = name + ', You have a token available!'
await ctx.send(response)
# error message if user has no token currently
#bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.errors.MissingRole):
name = ctx.author.name
# await ctx.send(name + ', you currently do not have a token, keep leveling up!')
await ctx.send('error check')
Here is the output:
Intead of using the mod role, why don't you run it using the check for whether the user has server administrator. To do that, all you do would be to replace:
#commands.has_role('mod')
with:
#commands.has_guild_permissions(administrator=True)
This would make the command only run if the specified user has server admin.
Please feel free to reply if you need any more help! :)

Resources