Im training to write on Solidity and when I try download ERC20 example in blockchain I need choose gas limit and gas price. How to calculate optimal?
https://www.ethgasstation.info says that with 5 gwei gas price confirmation time will be 0.46 mins, is it true? I read forums and I think this is too few
How much gas limit I need for ERC20 transfer?
you can calculate like this
const gasPrice = await web3.eth.getGasPrice();
const gasPriceLimit = await web3.eth.estimateGas({
"from" : walletbase,
"nonce" : value,
"to" : contractAddr,
"data" : data
})
Related
I am trying to build a smart contract that would give a fixed price in USD for each NFT to be minted by others, which they will need to pay in ETH. But I found a problem that the price of ETH is always changing, and each update of the NFT price in ETH would need some gas fee, which could cost a lot in long term for maintenance. Is there a way to periodically update ETH price inside the smart contract, or is manual updating the only way to do it?
Or I might have to remove the NFT price limit and completely rely on the frontend to handle the pricing part. But I think that's too risky.
You can use a Chainlink datafeed that returns the price of ETH in USD.
There are no datafeeds in emulators (e.g. Ganache or the Remix IDE built-in network), so you can test this snippet on your local fork of the Ethereum mainnet.
pragma solidity 0.8;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract MyContract {
AggregatorV3Interface priceFeed;
// 18 decimals
uint256 requiredPriceInUsd = 1000 * 1e18;
constructor() {
// https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419#code
// Chainlink ETH/USD Price Feed for Ethereum Mainnet
priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
}
// returns amount of wei
function getRequiredPriceInWei() public view returns (uint256) {
(,int answer,,,) = priceFeed.latestRoundData();
// returned price is 8 decimals, convert to 18 decimals
uint256 ethUsdPrice = uint256(answer) * 1e10;
// 36 decimals / 18 decimals = 18 decimals
return (requiredPriceInUsd * 1e18) / ethUsdPrice;
}
}
Output from my test:
answer is 122884000000 (1228 USD and 8 decimals)
returned value from getRequiredPriceInWei() is 813775593242407473 (of wei, that's ~0.8 ETH for 1,000 USD)
I have some math on frontend, which works good, but when math calculate big Numbers like this 1.1350120633522164e+23
I get error
Unhandled Rejection (Error): invalid number value
(arg="minDestinationAmount", coderType="uint256",
value="1.1350120633522164e+23", version=4.0.44)
I used BN
const minDestBN = new BigNumber(input)
const minDestinationAmount = minDestBN.multipliedBy(99).dividedBy(100)
res minDestinationAmoun = 1.1350120633522164e+23
How to convert such numbers 1.1350120633522164e+23 to uint256 on frontend side ?
This help me
BigNumber.config({ EXPONENTIAL_AT: 1e+9 })
let minDestinationAmount = minDestBN.multipliedBy(99).dividedBy(100)
minDestinationAmount = String(minDestinationAmount)
But would be great to hear best practice
I have spent the last hour trying to look for a solution to rate limit my api.
I want to limit a path /users for example. But most rate limits work on 1 rate limit for everyone. I want to use api keys that can be generated by a user. People can generate free api let's say 1000 requests per day. Then if they pay some money they can get 5000 requests per day.
I would like to store these api keys in a mysql database.
Does anyone have any solution for this?
One way to structure your project would be:
user_keys table, includes the api key, the user, time of creation and number of uses so far.
When a user tries to generate a key, check that one doesn't exist yet, and add it to the DB.
When a request arrives, check if the key exists, if it does, do the following:
1: if it has been 24 hours since creation date, set number of uses to 0
2: increment the uses count
if you find the API key and it's at 1k the user reached his limit.
This is a basic implementation, and isn't very efficient, you'll want to cache the API keys in memory, either just in a hashmap in nodejs or using memcached/redis. But, get it working first before trying to optimize it.
EDIT: some code examples
//overly simple in memory cache
const apiKeys = {}
//one day's worth in milliseconds, used later on
const oneDayTime = 1000 * 60 * 60 * 24
//function to generate new API keys
function generateKey(user) {
if (apiKeys[user]) {
throw Error("user already has a key")
}
let key = makeRandomHash(); // just some function that creates a random string like "H#4/&DA23#$X/"
//share object so it can be reached by either key or user
//terrible idea, but when you save this in mysql you can just do a normal search query
apiKeys[user] = {
key: key,
user: user,
checked: Date.Now(),
uses: 0
}
apiKeys[key] = apiKeys[user]
}
// a function that does all the key verification for us
function isValid(key) {
//check if key even exists first
if (!apiKeys[key]) throw Error("invalid key")
//if it's been a whole day since it was last checked, reset its uses
if (Date.now() - apiKeys[key].checked >= oneDayTime) {
apiKeys[key].uses = 0
apiKeys[key].checked = Date.now()
}
//check if the user limit cap is reached
if (apiKeys[key].uses >= 1000) throw error("User daily qouta reached");
//increment the user's count and exit the function without errors
apiKeys[key].uses++;
}
//express middleware function
function limiter(req, res, next) {
try {
// get the API key, can be anywhere, part of json or in the header or even get query
let key = req.body["api_key"]
// if key is not valid, it will error out
isValid(key)
// pass on to the next function if there were no errors
next()
} catch (e) {
req.send(e)
}
}
this is an overly simplified implementation of a simpler idea, but I hope it gets the idea across.
the main thing you want to change here is how the API keys are saved and retrieved
In my contract, I have a function that returns the sha3 hash of a certain set of values. While running some tests I found that the value returned from this function differs from the hash value generated by web3.utils.sha3() (with identical arguments).
Here is the code:
Solidity
function hashInfo() public onlyOwner view returns (bytes32) {
bytes32 hash = sha3(
'0x969A70A4fa9F69D2D655E4B743abb9cA297E5328',
'0x496AAFA2960f3Ff530716B5334c9aFf4612e3c27',
'jdiojd',
'oidjoidj',
'idjodj',
12345
)
return hash;
}
JS (web3)
async function testHash(instance){
const contractHash = await instance.methods.hashInfo().call({from: '0x969A70A4fa9F69D2D655E4B743abb9cA297E5328'});
const localHash = web3.utils.sha3(
'0x969A70A4fa9F69D2D655E4B743abb9cA297E5328',
'0x496AAFA2960f3Ff530716B5334c9aFf4612e3c27',
'jdiojd',
'oidjoidj',
'idjodj',
12345
)
console.log(contractHash);
console.log(localHash);
console.log('local == contract: ' + (contractHash == localHash));
}
The resulting console output is:
0xe65757c5a99964b72d217493c192c073b9a580ec4b477f40a6c1f4bc537be076
0x3c23cebfe35b4da6f6592d38876bdb93f548085baf9000d538a1beb31558fc6d
local == contract: false
Any ideas? Does this have something to do with passing multiple arguments to the functions? I have also tried to convert everything to a string and concatenate them into one single string, but also without success.
Thanks in advance!
UPDATE
I found out there also if a web3 method called web3.utils.soliditySha3(). This too did not work and gave the following result:
0xe65757c5a99964b72d217493c192c073b9a580ec4b477f40a6c1f4bc537be076
0x0cf65f7c81dab0a5d414539b0e2f3807526fd9c15e197eaa6c7706d27aa7a0f8
local == contract: false
I'm happy I came after your update as I was just gonna suggest solditySHA3. Now that you've got the right function your problem is most likely with Soldity packing it's parameters.
As you can see here, sha3 is an alias to keccak256 which tightly packs it's arguments. Following the link on that page takes you here which fully explains how it's handled. Basically just take the inputs to soliditySHA3 and pack the bits as if they were the sizes of the variables you used. So if you hashed two uint32s (32 bits each, 64 total) you need to take the 2 64 bit Javascript numbers and compress them into 1 Javascript number.
For cases where more than 64 bits are needed I believe you can pass sequential ints (sets of 64 bits) to soliditySHA3 or you could use a BigInt. Personally, I usually try to only hash 256 bit variables together to avoid having to manually pack my bits on the JS end, but we all know that space constraints are huge in Solidity. I hope I helped, and let me know if you have further questions.
Aloha.
Web3 version is 0.20, and, according to documentation:
web3.eth.sendTransaction
web3.eth.sendTransaction(transactionObject [, callback])
Sends a transaction to the network.
Parameters
Object - The transaction object to send:
from: String - The address for the sending account. Uses the web3.eth.defaultAccount property, if not specified.
to: String - (optional) The destination address of the message, left undefined for a contract-creation transaction.
value: Number|String|BigNumber - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction.
gas: Number|String|BigNumber - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded).
gasPrice: Number|String|BigNumber - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price.
data: String - (optional) Either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code.
nonce: Number - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
Number|String - (optional) If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.
Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
I have function placeBet() which accepts multiple parameters:
function placeBet(uint8 _outcome, uint desiredMatchIndex, uint _amount) public payable{
// find a way to store a bid in order to be easily searchable, in order to easily send money to winners;
// require(!roundEnd, "Interactions with contract are locked, be careful next time!");
// require(state == State.Active, "Betting is over, game have already started!");
require(msg.value > 0, "It isn't possible to place a bet without a money ");
if(!isDuplicate(msg.sender)) addressIndices.push(msg.sender);
testina(msg.sender, _outcome, desiredMatchIndex);
existingBets[msg.sender].push(Bet({
bettor: msg.sender,
// name: name,
amount: _amount,
bet: desiredMatchIndex,
outcome: _outcome
}));
//emit event, finally;
}
, so my question is how should I include needed additional parameters (outcome, desiredMatchIndex, amount ) [maybe last one is reduntant ] alongside
transactionObject using web3.js?
Thanks : )
Oh, i am sorry, there was an example in documentation, just not adequately referenced.
/ Explicitly sending a transaction to this method
myContractInstance.myMethod.sendTransaction(param1 [, param2, ...] [, transactionObject] [, callback])