how to actually make an auction functionality into my daap? - ethereum

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],
});

Related

What is the difference between a Wallet and a JsonRpcSigner?

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.

Is it possible to provide access to the smart contract only from the application and block direct access?

For example, I have a game, and I want the players to interact, only through the application. But they can call functions if they just copy the ABI and contact address.
Is there any case to allow call public contract functions only through the application, using some kind of secret token? But I don’t know how to make such a secret token in the public blockchain.
If secret token related logic is included in contract, that can be visible to anyone who runs node, so it seems to be difficult.
Normal web server can use cookie and domain name checking etc to protect api, but smart contract cannot access data outside contract, and data inside contracts are visible, so password protection is difficult.
Only possible solution seems using cryptographic digital signature, and use proxy server.
Proxy server control request from application, and create signed request to smart contract which permits request only from proxy server.
(1) One way to handle this is to sign the transactions yourself instead of having the user do it. You can add a modifier to the function like onlyAdmin and designate your app's account address as the admin. Then those functions will revert if called by anyone else.
The problem with this is you will have to pay gas and have mechanisms in your game to ensure that users can not exploit usage of your signing key.
function doSomething(bytes32 userId) public onlyAdmin {
// ...
}
(2)
The other thing you can do is set a value that gets hashed in the function, then verify that hash. In the game you can give the user the value that will pass verification, downside is you will have to make sure to update the hash after each use.
To do this you can emit an Event and listen for it then send a tx to update the appHash, but this costs you gas and may expose you to a timing attack depending on what the rest of your implementation is like.
You could also set the function to a locked state which you then unlock by resetting the appHash, but again this requires work and gas on your end.
bytes32 public appHash = '1s2a3d4g';
function doSomething(appSecret bytes32) public {
require(keccak256(appSecret) == appHash);
// ...
emit didSomething(msg.sender, appSecret);
}
With lock
bytes32 public appHash = '1s2a3d4g';
bool public locked = false;
function doSomething(bytes32 appSecret) public {
require(keccak256(appSecret) == appHash);
require(locked == false);
// ...
locked = true;
}
function unlock(bytes32 nextAppHash) public onlyAdmin {
appHash = nextAppHash;
locked = false;
}

Sender account not recognized on private ethereum network

I'm currently developing a dApp in Solidity and am working on a web3 library to handle communication with it.
I struggle with the process of new account creation and transaction signing in web3. Before I continue it worth noting that I'm running my own local, private blockchain (currently with Ganache).
My code looks as follows:
try{
let a = web3.eth.accounts.create()
let dataTx = someContract.methods.someMethod().encodeABI()
let rawTx = {
to: someContract._address,
from: account.address,
data: dataTx,
gas: 10000000000
}
const transaction = web3.eth.accounts.signTransaction(rawTx, util.toBuffer(account.privateKey))
web3.eth.sendTransaction(rawTx).then(console.log)
}
catch(e){
console.log(e)
}
The problem here is that the web3.eth.sendTransaction() method raises the following exception: Error: Returned error: sender account not recognized.
My understanding is that web3.eth.accounts is used for managing local accounts and web3.eth.personal is used to communicate with a client (e.g. Geth). I wish to keep the private keys of accounts my app creates locally on the device of the web3 client, but it raises this exception.
Where am I going wrong? Should I register the newly created accounts somewhere before running transactions with it? Is there some vital information I'm missing here?
Thanks!
If you want to use an account other than Ganache provided you, you have to start Ganache providing your accounts data in the form private_key,initial_balance:
Example command: ganache-cli --account 0xf38b5679751228eab7d9f3aa02bd0b0c0f7b44e448c0cfd410a1d7053efb6c56,123456789
And it's output:
Ganache CLI v6.1.8 (ganache-core: 2.2.1)
Available Accounts
================== (0) 0x44fa41e453654ccb365a358e994c764a37eea91f (~0 ETH)
Private Keys
================== (0) 0xf38b5679751228eab7d9f3aa02bd0b0c0f7b44e448c0cfd410a1d7053efb6c56
Gas Price
================== 20000000000
Gas Limit
================== 6721975
Listening on 127.0.0.1:8545
I am having same issue in my project. The problem in my case is beacuse i am not using same web3 provider to create contract variable.
example code:
const providerEth= new Web3.providers.HttpProvider(
'HTTP://127.0.0.1:8545'
);
const web3Eth = new Web3(providerEth);
const contract= new web3Eth.eth.Contract(abi,address);
Here, we are not using metamask provider although both on same network Still it not recognize the account. So you should create contract like this
const web3Eth = new Web3(window.web3.currentProvider);
const contract= new web3Eth.eth.Contract(abi,address);
const accounts = await web3.eth.getAccounts();
var receipt=await contract.methods.transfer(receiver,amount).send({from:accounts[0]});
Now, you can able to call smart contract function with account address.
I had the same issue. It happened when I already opened my truffle console and after that I did a restart of my ganache because I wanted to start clean.
What fixed it for me was stopping the truffle console job and starting it again.
You are refering to functionality in web3 1.0.0 which is not yet fully released.
If you go to https://web3js.readthedocs.io/en/1.0/getting-started.html
you would see that they state the following:
This documentation is work in progress and web3.js 1.0 is not yet released! You can find the current documentation for web3 0.x.x at github.com/ethereum/wiki/wiki/JavaScript-API.
Most probably you are using a version 0.20.x or something like that so check this first. To check this open the dApp in the browser and type in the console the following:
web3.version.api
This should show you which version you are using.
I don't think there is a way to create accounts with web3js 0.20.x directly but you can try to update the web3js to the 1.0.0-beta and try to run your code again. You can find it in NPM here - https://www.npmjs.com/package/web3

What is the difference between web3.eth.accounts.create and web3.eth.personal.newAccount

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.

Are Ethereum contract function securable?

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.