web3.eth.sendTransaction passing paramaters along with mandatory transactionObject - ethereum

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])

Related

Uniswap v2 swap() function. What are balance0 & balance1?

I'm learning how the Uniswapv2 contracts work but I can't seem to wrap my mind around the swap() function.
Reference: https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L173
Lines 173-174 contain:
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
My question is, when & whose balances are these?
A. These are the same as _reserve0 & _reserve1 after the most recent swap and will be used to synchronize reserves.
B. These are the quantities of each token the user making the swap currently possesses.
C. None of the above. It's something else. Please explain the flow of this function. I cannot find a clear and concise definition anywhere.
answer is "C" :)
balanceOf is a mapping in ERC20 implementation to return the amount that given address holds:
// address => holds uint amount
mapping(address => uint) public balanceOf;
Since current contract is inheriting from UniswapV2ERC20:
contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20{}
it can access to UniswapV2ERC20.sol
Since the mapping balanceOf is public, solidity assigns getters to the public variables
In the functions:
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
address(this) refers to the current contract which is UniswapV2Pair. So balance0 is how much the current contract owns _token0 and balance1 is how much the current contract address owns _token1. token0 and token1 are contract addresses and each ERC20 token contract, keeps track of addresses and their balances. so you are visiting each token contract and getting how much balance the current contract has.
Think ERC20 contract like a bank. you have token0 bank and token1 bank. Each bank keeps track of the balances of their users. balancesOf is where ERC20 tokens store those balances. Your current contract also owns some of those tokens so you just want to get how much tokens the current contract holds
swap function will be called by the user. Before executing the swap, contract checks if it has enough funds
uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');

The transaction has been reverted to the initial state. The called function should be payable if you send value

the Error being specified is
revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.
//SPDX-License-Identifier:MIT
pragma solidity 0.8.8;
contract Giftcard{
event UniqueCardId(uint indexed Id,address indexed owner);
//Enter The Giftcard amount
//Pay the gift card by making multiple transations
//require(giftcard owner should approve the withdrawl )
address[] Giftcardowners;
mapping(address => uint) amountUploaded;
function Addamount() external payable{
require(msg.value >= 1 ether,"Gift card amount to small");
amountUploaded[msg.sender] = msg.value;
Giftcardowners.push(msg.sender);
emit UniqueCardId(Giftcardowners.length-1,msg.sender);
}
function GetGiftcard(uint _cardId) payable external {
require(Giftcardowners.length > _cardId,"Id doesnot exits");
address owner = Giftcardowners[_cardId-1];
uint amount = amountUploaded[owner];
require(amount >= 1 ether,"transfered is less than 1 ether");
// (bool successs,) = payable(msg.sender).call{value:amount}("");
//require(successs,"transaction reverted");
payable(msg.sender).transfer(1 ether);
}
function getBalance() external view returns(uint balance){
return address(this).balance;
}
}
Firstly I called the Addamount function by paying more than 1 ether to the smart contract
now after that when the GetGiftcard function is called the transaction is reverted. I am unable to find a solution
unable to understand the concept
Error is here
address owner = Giftcardowners[_cardId-1];
should be
address owner = Giftcardowners[_cardId];
When you call addAmount, this line executes
Giftcardowners.push(msg.sender);
in the Giftcardowners array you have only 1 item
Giftcardowners=[0x7EF2e0048f5bAeDe046f6BF797943daF4ED8CB47]
when you call the GetGiftcard, you need to pass _cardId=0, you are actually assigning the index of the array as the id. when you pass 0, index will be -1 here
address owner = Giftcardowners[_cardId-1];
You cannot pass 1 to get 1-1=0, because you have this condition
require(Giftcardowners.length > _cardId,"Id doesnot exits");

yubihsm2 signatures are invalid when signing ETH transactions

I am trying to figure out how to get this yubihsm2 to work with signing eth transactions. I have been using the python lib and so far i have had some basic setup. Below is an abbreviation of what i have
web3_endpoint = ''
web3 = Web3(HTTPProvider(web3_endpoint))
hsm = YubiHsm.connect("http://localhost:12345")
session = hsm.create_session_derived(1, "password")
key = session.get_object(1,OBJECT.ASYMMETRIC_KEY)
#key = AsymmetricKey.generate(session, 1, "EC Key", 1, CAPABILITY.SIGN_ECDSA, ALGORITHM.EC_K256)
pub_key = key.get_public_key()
#raw_pub = pub_key.public_bytes(
# encoding=serialization.Encoding.DER,
# format=serialization.PublicFormat.SubjectPublicKeyInfo
# )
raw_pub = pub_key.public_bytes(
encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.UncompressedPoint
)
print ("Public key (Uncompressed):\n",binascii.b2a_hex(raw_pub))
unindexPub = raw_pub[1:]
public_key_hash = Web3.keccak(unindexPub)
address_bytes = public_key_hash[-20:]
address = address_bytes.hex()
print(address)
Now so far i can consistently get the same public key and it looks correct. I then get the same public key each time. When i say correct, the formatting looks correct and is the correct number of bytes.
1). should i be using the commented out public key formatting or the uncompressed X962 encoding that i have above.
From there, this is where things get a bit weird
transaction = {
'to': Web3.toChecksumAddress('0x785AB1daE1b0Ee3f2412aCF55e4153A9517b07e1'),
'gas': 21000,
'gasPrice': Web3.toWei(5, 'gwei'),
'value': 1,
'nonce': 1,
'chainId': 4,
}
serializable_transaction = serializable_unsigned_transaction_from_dict(transaction)
transaction_hash = serializable_transaction.hash()
print(transaction_hash.hex())
# sign the transaction hash and calculate v value
signature = key.sign_ecdsa(transaction_hash,hashes.SHA3_256())
r, s = ecdsa.util.sigdecode_der(signature, ecdsa.SECP256k1.generator.order())
print("r: "+str(r)+"\ns: "+str(s))
v = 28
# encode the transaction along with the full signature and send it
encoded_transaction = encode_transaction(serializable_transaction, vrs=(v, r, s))
web3.eth.sendRawTransaction(encoded_transaction)
I am settings v to 28.. i also test it with 27.. I could use the correct amount with the chainid.. but it's not necessary right from the perspective of trying to get a valid signature (recoverable to get the same public key each time). Sometimes i am getting the error "invalid sender" and other times i am getting the error "insufficient gas." If i take the signature output and use a javascript lib to try to find the public key, each time i am getting a different public key. But i keep consistently generating the same public key from the yubihsm2 in this python app.
I have also commented out in sign_ecdsa the hashing function as i am passing in the data already hashed (in order to use keccak256).
Is there something i am missing? Why are these transactions not signing correctly for eth?
i am getting some of those serialization helpers from enter link description here
helper serialization functions
Thanks

In what slots are variables stored that are defined after an array in Solidity?

So I know how arrays are stored in storage. If I understand it correctly it first stores the number of items in an array in the first slot, and then in the next slots, it stores the hashed values.
My question is what if I define uint after the array and the array during deployment has only 2 values. So it should take up 3 slots. Then in the fourth slot is the uint I defined.
What if there is a function that will push something to the array? How is it stored?
Will it be stored in the next free slot? Or will it push the uint to the next slot and replace it with the new value?
I hope the question is clear if not I will try to rephrase it.
Also if there is some good resource where I can learn all about storage in solidity please share the link.
Thanks a lot!
Fixed-size array stores its values in sequential order, starting with the 0th index. There's no prepended slot that would show the total length. Any unset values use the default value of 0.
pragma solidity ^0.8;
contract MyContract {
address[3] addresses; // storage slots 0, 1, 2
uint256 number; // storage slot 3
constructor(address[2] memory _addresses, uint256 _number) {
addresses = _addresses;
number = _number;
}
}
Passing 2 addresses to the constructor, storage slot values in this case:
0: _addresses[0]
1: _addresses[1]
2: default value of zero (third address was not defined)
3: _number
Dynamic-size array stores its values in keys that are hash of the property storage slot (in example below that's 0, as that's the first storage property), and immediately following slots. In the property storage slot, it stores the array length.
pragma solidity ^0.8;
contract MyContract {
/*
* storage slots:
* p (in this case value 0, as this is the first storage property) = length of the array
* keccak256(p) = value of index 0
* keccak256(p) + 1 = value of index 1
* etc.
*/
address[] addresses;
// storage slot 1
uint256 number;
constructor(address[] memory _addresses, uint256 _number) {
addresses = _addresses;
number = _number;
}
}
Passing 2 addresses to the constructor, storage slot values in this case:
0: value 2 (length of the array)
1: _number
0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563 (hash of uint 0): _addresses[0]
0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564 (hash of uint 0, plus 1): _addresses[1]
Docs: https://docs.soliditylang.org/en/v0.8.13/internals/layout_in_storage.html#mappings-and-dynamic-arrays
So to answer your questions:
What if there is a function that will push something to the array? How is it stored?
Will it be stored in the next free slot? Or will it push the uint to the next slot and replace it with the new value?
Fixed-size arrays cannot be resized. You can only rewrite its values, while the default value of each item is 0.
In case of dynamic-size arrays, it pushes the new value right after the last one. Since they are stored in slots which indexes are based on a hash, the probability of rewriting another value is practically 0 (i.e. that would mean a hash collision).
In both cases, it doesn't affect how other storage properties are stored.

Solidity and Web3 sha3() methods return something else

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.