Chainlink Core Adapter Path Issue: httpGet uint256 returning 0 from treasury.gov API - ethereum

I am trying to connect to an API with Chainlink to get a uint from the URL in the request bellow. Problem is, every time the "volume" value comes back 0. I have a feeling the issue is one of two things:
The oracle doesn't like accessing arrays. I've tried "data[0]" as well as "data.0". Both work jsonPath which is on the Docs page.
The API is returning a string instead of a number (as the number is wrapped in quotes). I've tried a bytes32 job as well to only get back 0x0. Also other StackOverflow posts show oracles reading string numbers as numbers.
The following snippets of code are the only changes made to the "deploy on remix" code shown here in Chainlink Docs: https://docs.chain.link/docs/make-a-http-get-request.
request.add("get", "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/accounting/od/avg_interest_rates?sort=-record_date");
request.add("path", "data.0.avg_interest_rate_amt");
The contracts are being deployed on Kovan through Remix/Metamask with plenty of link funding the contract. What could I be doing wrong?

There are a couple of issues:
The response is too large so the node just stops at the HttpGet task. I've tested it on my node and here's the exact error I'm getting: HTTP response too large, must be less than 32768 bytes. If you can influence this, that would be great. Otherwise, you'll need to have your own node that will return a shorter response that matches the above limitations.
The result should have only whole numbers, Solidity doesn't understand decimal points, instead, it uses WEI. That's why you need to multiply the result by at least 100, 10^18 is a standard so I'd go with that. The following piece should work for you:
function requestData(string memory _id, string memory _field) public {
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfillData.selector);
request.add("get", "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/accounting/od/avg_interest_rates?sort=-record_date");
string[] memory path = new string[](3);
path[0] = "data";
path[1] = _id;
path[2] = _field;
request.addStringArray("path", path);
int timesAmount = 10**18;
request.addInt("times", timesAmount);
sendChainlinkRequestTo(oracle, request, fee);
}
I also added _id and _field as function arguments to query any field of any object. Note, this will only work if you can figure out how to get a shorter response.

Related

Can I attach a piece of text to a transaction record?

According to the docs for web3.eth.sendTransaction and the docs for eth_sendTransaction:
The transaction object can contain an optional data parameter which should be a String that consists of:
either an ABI byte string containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code.
I want to assign a string to data and have the string be stored along with the record of the transaction on the blockchain, so that I can retrieve that string when I retrieve the record of that transaction later.
const [testAccount] = await window.ethereum.request({ method: "eth_requestAccounts" })
const web3 = new Web3(window.ethereum)
if (!testAccount) {
return
}
let transactionHash = await web3.eth.sendTransaction({
from: testAccount,
to: testAccount,
value: web3.utils.toWei('0.0003'),
data: web3.utils.utf8ToHex(JSON.stringify({ a: 1, b: 2 }))
})
let transaction = await web3.eth.getTransaction(transactionHash)
let data = JSON.parse(web3.utils.hexToUtf8(transaction.data))
console.log(data.a) // should log 1
When I execute sendTransaction (using Metamask, while connected to the Ropsten network), I get the following error:
Error: Error: TxGasUtil - Trying to call a function on a non-contract address
{
"originalError": {
"errorKey": "transactionErrorNoContract",
"getCodeResponse": "0x"
}
}
Apparently, you cannot assign any string to data and expect the string to be incorporated in the record of the transaction on the blockchain, out-of-the-box, simply by assigning a value to it. Is this correct?
Question: Do I need to write a custom smart-contract in order to achieve this ?
This is a feature/limitation specific to MetaMask. Possibly to protect their users who want to interact with a smart contract but are connected to a different network where the contract is not deployed.
However, it is technically possible to send a valid transaction with non-empty data field to a non-contract address. You just need to use a different node provider to broadcast the transaction. Unfortunately the node provider in MetaMask is hardcoded so it's not possible using this wallet.
Example: This transaction on the Ropsten testnet to the 0xdac1... address that has the USDT token contract deployed on the mainnet, but is a non-contract address on the testnet. It is a valid transaction, successfully bought gas from the sender address to cover the transaction fees, mined in a block, just didn't execute any smart contract code (as there is no smart contract on the recipient address).
Do I need to write a custom smart-contract in order to achieve this ?
You can also write a smart contract function in Solidity that receives data as a function argument, but does nothing on this. Thus, GoEthereum node stores this data as calldata of the transaction and it can be later retrieved.
I am pretty sure some cross-chain bridges operate in this manner. Transactions only write data as the part of calldata (cheaper than Solidity storage) and then other clients read it from there.

What information are visible in transaction after a call to a payable function?

I was wondering what information are publicly visible and intelligible when an EOA (external ownable address) calls a payable function on a smart contract, with some parameters and a return value.
Let us say I have the smart contract function below, the question is: 'is the return value visible somewhere on the blockchain?'. I am using Solidity 0.8.12.
function askForSecretCode(uint time) external payable returns (bytes32) {
require(msg.value == 42, 'Need to pay 42 wei.');
secretCodes[secretCodesNum] = keccak256(abi.encodePacked(msg.sender, time);
return keccak256(abi.encodePacked(msg.sender, time);
}
Anyone can see the input time param value as a part of a transaction invoking the askForSecretCode function.
Even though if you don't publish the contract source code, the bytecode is public, and there are decompilers that can (with some error rate) help generate source code back from the bytecode. So let's assume that the source code is available as well.
From the source code (or usually even from the pseudocode generated by the decompiler), anyone can determine the storage slot of secretCodesNum (which from the context seems to be a property of the contract) and retrieve its value using the eth_getStorageAt RPC method, including historical values.
Using these secretCodesNum values, they can use the same method to determine storage slots of any secretCodes[secretCodesNum] and their values.
TLDR: Never ever store private data on the blockchain.

How do I send ether and data from a smart contract to an EOA?

I'm trying to create a "real" transaction from inside a smart contract to an EOA. This is so that I can attach data/input_data to send to it.
I've read several resources on this but I've come to contradictory information: some say it's impossible, some say that call() can achieve this. I've been testing multiple methods and have not come to see that it is possible.
Here's a simple example of what I'm trying to achieve:
pragma solidity 0.8.6;
contract Simple {
uint32 value;
constructor() payable {
// Contract is initialized with 0.5 ether
value = 22;
}
function foo() public {
require(address(this).balance >= 0.1 ether);
// Along with transfering ether, I want to send some data to the EOA,
// for example, whichever value is in the variable "value"
payable(msg.sender).transfer(0.1 ether);
}
}
On a "normal" transaction, it is possible to set the field "input data" (normally used to make function calls when sending a transaction to a smart contract), which allows us to send data on a transaction from an EOA to another EOA. I was able to achieve this already.
But, from my understanding, contracts "can't" create transactions; they only create "internal transactions" (informal name) that are associated with the "parent transaction" (transaction that called the contract in the first place) and therefore don't have the data field. But they're able to call another contract on the network, so I assume they're able to send some data along the network, right?
Furthermore, this question seems to imply that the low level call() method is able to achieve this. I've tried multiple approaches but have not been able to reproduce the wanted behaviour.
msg.sender.call{value: 0.1 ether}("data", value); // Doesn't work
msg.sender.call{value: 0.1 ether}(value); // Doesn't work
msg.sender.call{value: 0.1 ether}(abi.encodeWithSignature(value)) // Doesn't work
At some point, I did find my message on a block's "extra data", but from my understanding, this was written there by the miner for some reason.
So, to sum it up, is it possible to, from a contract, send ether + message to an EOA account? How would I achieve this?
Edit: Fixed the function name, which was a reserved keyword.
function msg() public {
This function name is a bit problematic, because you're overriding the global msg variable, and can't use the msg.sender.
So I changed the function name to generic foo().
function foo() public {
msg.sender.call{value: 0.1 ether}
Since Solidity 0.8, an address is not payable by default (source: docs). So if you want to send them the native currency (in case of Ethereum, that's ETH), you need to cast the address to payable first.
payable(msg.sender).call{value: 0.1 ether}
Finally to the data sending part.
At some point, I did find my message on a block's "extra data", but from my understanding, this was written there by the miner for some reason.
I'm not exactly sure, but it seems like you stumbled upon the correct field, which is simply the data field of the raw transaction, and the blockchain explorer probably named it "extra data". The data field is not filled by the miner, but by the transaction creator.
Since you're sending an integer, and the data field is bytes (array of bytes), you need to encode it to bytes. In your case:
abi.encode(value)
To you put it all together:
pragma solidity 0.8.6;
contract Simple {
uint value;
constructor() payable {
value = 22;
}
function foo() public {
require(address(this).balance >= 0.1 ether);
payable(msg.sender).call{value: 0.1 ether}(abi.encode(value));
}
}
When you execute the foo() function (and the contract has enough funds), it will create an internal transaction (some blockchain explorers might use a different name) to the msg.sender with value 0.1 ether and the decimal 22 encoded as hex 16 in the data field.

How the input data of smart contract function is packed in hex string before sending to ethereum network

I want to understand this to parse data from the private chain transaction and get the input data that was sent for a particular transaction, I have tried many decoders but at some point, they fail.
This is the simple smart contract I tried using remix
contract simple{
uint256 deliveryID;
string status;
function stringAndUint(string _status,uint256 _deliveryID){
status=_status;
deliveryID=_deliveryID;
}
}
Input data generated:- 0x3c38b7fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000067374617475730000000000000000000000000000000000000000000000000000
I can interpret the following from the above.
function signature:0x3c38b7fd
_status value:737461747573,
_deliveryID:0c but i dont know why 4 is coming and extra 6 before 737461747573 .
The input to function "stringAndUint " is: "status",12
Can some one help me understand how the input data is generated and packet in a long hex string
Try taking a look here http://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#argument-encoding and here http://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#use-of-dynamic-types
Splitting up the encoding into 32 byte chunks gives:
3c38b7fd (function signature)
0000000000000000000000000000000000000000000000000000000000000040 (the location of the data part of the first parameter, measured in bytes from the start of the arguments block)
000000000000000000000000000000000000000000000000000000000000000c (12)
0000000000000000000000000000000000000000000000000000000000000006 (length of "status". the earlier 0..040 points here)
7374617475730000000000000000000000000000000000000000000000000000 ("status" then zeros padded out to the next multiple of 32 bytes)
What is the encoding used?
Solidity uses a "Contract ABI" spec for encoding.
What's the deal with the extra (hex) 40 and 6?
#Brendan's answer about these values is better than mine, so I'll delete this section. I'll leave the answer posted because the below section is still useful.
Reproducing programatically
There is an ABI-decoding tool in python, called eth-abi, which you can use like so:
from eth_utils import to_bytes
encoded = to_bytes(hexstr="0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000067374617475730000000000000000000000000000000000000000000000000000")
from eth_abi import decode_abi
decoded = decode_abi(['string', 'uint256'], encoded)
assert decoded == (b'status', 12)

Read-only Functions Iteration Cost

I am developing smart contracts for some use-cases and currently I'm working on optimization of smart contracts. I am confused with something that I found interesting on Hitchiker's Guide. In the section 4- Iterating the contract code
// returns true if proof is stored
// *read-only function*
function hasProof(bytes32 proof) constant returns (bool) {
for (uint256 i = 0; i < proofs.length; i++) {
if (proofs[i] == proof) {
return true;
}
}
return false;
}
For this code above, He states that "Note that every time we want to check if a document was notarized, we need to iterate through all existing proofs. This makes the contract spend more and more gas on each check as more documents are added. "
There is no doubt that the proper way of implementing it is to use mapping instead of array structure. Here is the point that makes me confused. It's read-only function and it is not a transaction that affects blockchain. When I observed my netstats, it does not show any transaction when this function is called(Actually, it is what I expected before calling this function).
I don't think that he misunderstood the mechanism, could someone clean my mind about this comment?
Roman’s answer is not correct. Constant functions still consume gas. However, you don’t pay for the gas usage when it runs in the local EVM. If a constant function is called from a transaction, it is not free. Either way, you are still consuming gas and loops are a good way to consume a lot.
EDIT - Here is an example to illustrate the point
pragma solidity ^0.4.19;
contract LoopExample {
bytes32[] proofs;
function addProof(bytes32 proof) public {
if (!hasProof(proof))
proofs.push(proof);
}
function hasProof(bytes32 proof) public constant returns (bool) {
for (uint256 i = 0; i < proofs.length; i++) {
if (proofs[i] == proof) {
return true;
}
}
return false;
}
}
And here are the gas consumption results for calling addProof 4 times:
addProof("a"): 41226
addProof("b"): 27023
addProof("c"): 27820
addProof("d"): 28617
You kind of have to ignore the very first call. The reason that one is more expense than the rest is because the very first push to proofs will cost more (no storage slot is used before the 1st call, so the push will cost 20000 gas). So, the relevant part for this question is to look at the cost of addProof("b") and then the increase with each call afterwards. The more items you add, the more gas the loop will use and eventually you will hit an out of gas exception.
Here is another example where you are only calling a constant function from the client:
pragma solidity ^0.4.19;
contract LoopExample {
function constantLoop(uint256 iterations) public constant {
uint256 someVal;
for (uint256 i = 0; i < iterations; i++) {
someVal = uint256(keccak256(now, i));
}
}
}
Here, if you call this through Remix, you'll see something like this in the output (Notice the comment on gas usage):
Finally, if you try to run this constant method from a client using too many iterations, you will get an error:
$ truffle console
truffle(development)> let contract;
undefined
truffle(development)> LoopExample.deployed().then(function(i) { contract = i; });
undefined
truffle(development)> contract.constantLoop.call(999);
[]
truffle(development)> contract.constantLoop.call(9999);
[]
truffle(development)> contract.constantLoop.call(99999);
Error: VM Exception while processing transaction: out of gas
at Object.InvalidResponse (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\errors.js:38:1)
at C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\requestmanager.js:86:1
at C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-provider\wrapper.js:134:1
at XMLHttpRequest.request.onreadystatechange (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\httpprovider.js:128:1)
at XMLHttpRequestEventTarget.dispatchEvent (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:64:1)
at XMLHttpRequest._setReadyState (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:354:1)
at XMLHttpRequest._onHttpResponseEnd (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:509:1)
at IncomingMessage.<anonymous> (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:469:1)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
Most of the people will say constant functions will not consume gas. That will not correct because, constant functions execute on the local node's hardware using it's own copy of the blockchain. This makes the actions inherently read-only because they are never actually broadcast to the network.
Lets assume I've contract having isEmp constant function, when I call estimateGas() it should return 0 if constant method's are not consuming gas. But its returning 23301.
truffle> contractObj.isEmp.estimateGas(web3.eth.accounts[0])
23301
Here is my solidity code
function isEmp(address employee) public constant returns(bool) {
return emps[employee];
}
Hence above experiment is proved that it will consume gas.
The thing is that constant (now it's called view) functions are getting the information from previously executed normal functions. Why? Because view functions are accessing the storage of the contract that created in creation of the contract and changed with functions that changes it if you write the function that way. For example:
contract calculateTotal{
uint256 balance;
constructor(uint256 _initialBalance){
balance=_initialBalance;
}
function purchaseSmth(uint256 _cost) external {
balance=balance-_cost;
}
function getBalance() external view returns(uint256){
return balance;
}
}
Now when you create this contract you set the balance, that way balance already calculated and you don't need to be recalculated because it will be the same. When you change that balance value with purchaseSmth the balance will be recalculated and storage value of balance is going to change. That means that function will change the blockchain's storage. But again you are paying for these executions because the blockchain must be changed. But view functions are not changing any storage value. They are just getting the previously calculated value that standing in blockchain already. When you make some calculations in the view functions like: return balance*10; the execution does not affects blockchain. The calculation of it will be done by your device. Not by any miner.
If we look at the answer of #AdamKipnis we see that constant/view function is not consuming any gas by itself if you call it rightaway. Because it will be always calculated before. First the constructor will create it as empty array. Then when you call the hasProof you will see an empty array. Then when you use addProof it will change the proofArray. But the price is going bigger because it uses the hasProof function in it. If it wasn't there then the price would not go up forever. However If you call the hasProof function manually then your computer(if it is a node) will execute that loop locally eitherway if that function has it or not. But any storage, status changing execution will be directed to miners because of the blockchain logic. Someone else should execute that code and verify it If that change is possible in that transaction and If there is no error in the code.
When you use a wallet like metamask wallet in some cases you can see the errors before making any transactions(executions). But that is not a verified error until you make the transaction and a miner executes that code then finds that this code has some errors or it is doing, changing something in a way that it shouldnt be possible. Like trying to transferring to yourself some bnb from another person's wallet. That execution can't happen because It is not your wallet to transfer the bnb from. It sounds obvious but random miners should validate that execution to making a block that includes your transaction in it with other executions in per block transaction limit boundary in that time.
EDIT: The device, computer, hardware is the node. Node can be you or if you use a remote node for your executions than the node will do everything your device will not. Like cloud computing. Because you would'nt have a ledger if you were not a node.
It will only cost gas if the constant (view or pure) function is executed or called by another external smart contract, that is not the owner of that function. But if it is called from within the smart contract that declared the constant (view or pure) function, then no gas will be used.
Just like when you use a class member function in another class in other programming languages by creating an object of that class. But in solidity this will cost you regardless of the fact that it's a constant function or not.
So when Jitendra Kumar. Balla did an experiment that showed it will cost gas, the gas shown there is the estimated gas cost if it is called by another smart contract but not from within the smart contract.