On the ethers documentation, it says that the two most commons signers are:
Wallet, which is a class which knows its private key and can execute any operations with it.
JsonRpcSigner, which is connected to a JsonRpcProvider (or sub-class) and is acquired using getSigner
What I'm having trouble understanding is how a JsonRpcSigner is created when the provider is a web3provider (i.e., MetaMask). Doesn't a web3provider know its private key and should therefore return a Wallet when provider.getSigner() is run?
The Wallet singer is used when your ethers.js instance knows the private key directly.
Since MetaMask doesn't share the key with other applications, ethers.js uses the JsonRpcSigner to be able to request the local MetaMask instance over its API to sign the transaction when needed, and then receive the signed transaction back, without ethers.js ever knowing the key.
I think the Wallet subclass of abstract signer has both the sign and signMessage methods, but JsonRpcSigner (what you get from provider.getSigner()) does not. The use case is I'm trying to sign a transaction using sign from metamask for instance and then submit it later.
Related
Have you used the ethers signMessage and/or _signTypedData ?
I'm doing a LazyMint to a NFT platform, and I see some examples using the _signTypedData with some OpenZeppellin contracts. But with this method, there are a lot of problems happening with recovering the signer. There's a problem of use signMessage and not the _signTypedData? It's not clear in the documentation but appears that the address of the singer that returns is the address from the Provider.
I've been trying to make an NFT marketplace with the functionality of auctioning an item. But I don't know how to achieve this via signing transaction.
I have tried to use almost every method of signing from web3.js, but it requires the private key of the user.
However there's the function web3.eth.signTransaction which doesn't require any private key to sign the transaction, but it gives an error on the console. saying : Error: The method 'eth_signTransaction' does not exist / is not available.
Can someone give me an overview of how this signing and sending transaction can be done implementing the functionality of auctioning an nft like nft marketplaces: opensea or foundation.
From the docs:
Signs a transaction. This account needs to be unlocked.
It doesn't require the private key, but it requires the account (that is used for signing the transaction) to be unlocked on the node. Which means the node needs to hold the private key to unlock the account.
It's usually allowed on local nodes such as Ganache or private nodes.
And public nodes such as Infura usually disable this functionality (hence the error message "eth_signTransaction is not available") since they don't store your private keys.
You can ask the user to sign the transaction using their wallet. For example using MetaMask (or any other wallet implementing the Ethereum provider API):
const transactionParameters = {
from: ethereum.selectedAddress, // must match user's active address
to: 'your address'
};
await ethereum.request({
method: 'eth_sendTransaction',
params: [transactionParameters],
});
Glad to see blockchain development support on Stack Overflow as resources as very scarce nowadays.
I'm a new kid trying to learn this ecosystem.
How can I add an image logo to a token that I've already created and deployed on remix.ethereum.org?
Should I have done this before deploying it?
Newbie question: Once deployed the same code can never modified?
I'm currently interacting with the token on BSC - seems that all BSC tokens are created as a fork of Solidity and the ETH ERC20 paradigm. (?)
This is my code
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract Foobar is ERC20 {
constructor(uint256 initialSupply) public ERC20("Foobar", "FOO") {
_mint(msg.sender, initialSupply);
}
}
Short answer: No, once you deploy a contract to the mainnet, you can't modify nor delete it, it'll be in the blockchain forever (unless you're using a testnet or a private blockchain network to test the contract).
Long answer:
Once a contract is deployed, it can never be modified nor deleted, the only thing you can modify is it's storage (variables that the contract uses) by calling it's defined functions, but you can't modify the logic behind it. If you messed up, you'll need to fix your contract, and re-deploy.
Take in mind that heavy tests and thoughtful inspections are advised before you deploy a contract to the mainnet and set an app into production (and even more if you'r contract will handle sensitive values), mainly because even if you screw up and re-deploy, if you had said contract work in production, its extremly difficult to fix.
For example: You make you'r own tiny bank, the contract recives eth, and it stores it a variable a mapping of addresses with a variable that keeps a count of how much eth from the total eth that the contract is holding is for each user.
contract Bank {
// mapping of address with current money value.
mapping (address user => uint money) balance;
constructor(){}
function withdraw(uint memory money) public {
// Require money parameter is not empty.
require(money != 0, "Can't withdraw 0 eth");
// Big issue here, if we send the money, and then update the balance,
// the user will be able to withdraw money even if hi's balance turns
// to 0 if he spams the withdraw function before he runs out of money.
// The good way would be the other way around, first update balance, and then send.
// Check if the user has enough money.
if (balance[msg.sender].money >= money) {
// Send money
address(msg.sender).transfer(money);
// Update balance.
balance[msg.sender].money -= money;
}
}
...
}
Now this has a critical issue, if someone withdraws money twice very fast, it skips a check iteration that checks if the user has enough money in it's balance to withdraw.
Now to fix this, you'll need to quickly withdraw all the money that the contract has and it's mapping(address user => uint money) ... mapping data, fix and re-deploy the contract, manually send all the money to the new contract, and also set the previous data that it had, and if that wasn't enough you'll need to change you'r front-end app to connect with the new contract.
I know its a long example, but when you start coding contracts from 0, you have to understand that testing and revising the contract is a must.
Once a contract is deployed, it cannot be modified nor deleted, it's there forever, alteast in the mainned, that's why you use private blockchains such as Ganache, or use a public testnet (Ropsten, Kovan, Rinkeby, Goerli).
Also about the logo, most tokens don't have their "logo" in their contract ( unless you're making a NFT [ ERC721 ] ), yet, if you still want to add a logo that anyone can access from your contract, i'd suggest to make a state variable that holds its value (string mainly).
The value can be a IPFS hash (IPFS is a decentralized file system that allows you to upload files of any kind, it will return a hash once it's uploaded, and you can access you'r file via https://HASHTOKEN.ipfs.infura-ipfs.io/, for example:
https://bafybeibctnxu7zpatp3caj2gevofs2oirdvdyo6yulxk2hfyaewxib3pj4.ipfs.infura-ipfs.io/
soo in you'r case, you can upload the logo there, grab the hash, and store it in you'r contract, then in your frontend app you'll only need to add the hash to the url.
A second way of adding you'r logo would be to turn you'r image into base64 and paste the whole thing into you'r contract, that way you have literally the image in the contract, yet, i don't recommend this last solution since base64 strings can get very large depending on how heavy is the file, and the heavier you'r contract is, the more gas it will use when you deploy it, and more expensive for the users when they try to use it.
Yet, if what you mean is to add a logo on sites such as BscScan, you can find a guide here.
As I understand when using web3.eth.accounts.create(), it doesn't add the account to chain (I'm using ganache-cli for testing), but web3.eth.personal.newAccount() does.
Is it the main purpose or is it a bug?
Is there other differences?
web3.js version: 1.0.0-beta.34
Both versions create a new account on the blockchain. The difference is how you interact with the node and having access to the private key. If you have a local node, you can use web3.eth.accounts.create which will create the account and provide you access to the private key generate so it can be stored locally. However, since returning the private key over a connection isn’t secure, you should never use this approach to create an account if you connect through a provider like Infura.
On the other hand, you can use web3.eth.personal to create a new account on a remote node. In this case, the private key will not be returned to you, so you lose some flexibility with accessing your account. When you don’t have the private key, you can’t sign transactions locally. In order to run transactions, you have to call unlockAccount on the remote node. Note that you have to send your password to create/unlock your account using web3.eth.personal, so you still need to make sure you using a secure connection.
Review this Medium blog post for additional info.
I am using testrpc and web3.
I used the idiom below to ensure that only a previously defined user should be able to do something:
function doSomethingProtected() {
if ( msg.sender != authorizedUser )
throw;
flagSomething = true;
}
When calling the function on an instantiated contract with web3 as follows:
myContract.doSomethingProtected( { from: "0x..." } );
it worked. At first I was pleased but then I realized the web3 API had not required me to provide any passphrase for a private key or such like.
Can anyone with the simple knowledge of someones public key/address call this function?
The use of this idiom in the examples led me to believe a benefit of the Ethereum contracts was that it ensured msg.sender was cryptographically assured.
The reason is that you are using testRPC, which doesn't lock it's accounts, so you don't need a password.
If you were to do this with geth, you would need to unlock the account before sending from it.
Without the private key, that function will throw an error, so you are correct in using that authorization method.
It's difficult to be certain without seeing more of your code, but it seems likely that you were calling the contract on your local node, rather than sending a transaction. Transactions can only be signed by someone with the account's private key, meaning you can rely on msg.sender to be accurate, but messages executed on your local node won't enforce that. Any changes they make are rolled back and not applied to state, though, so it doesn't matter what your local call does.
In general, there are two ways to call a function from web3.js: Using a transaction or just using a "call". Only in transactions you can actually modify the blockchain content (reading is always possible). Transactions always require a valid signature and thus access to a private key.
The reason you were not asked for a password might be that you already unlocked the account. Furthermore, users other than the authorized user can call the function, only the changes will be thrown away.
My guess is that your account was already unlocked when calling the function. I don't remember the exact period that your account is unlocked after unlocking it in web3. I might be wrong though. Would have added this as a comment, but I am not allowed right now.