Ethereum eth_call returns padded address - ethereum

This is my Contract ABI
abi:[{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function",
"constant": true
}]
when I try get the address of the owner using eth_call method of ethereum.request(...) its giving me the padded address instead of the real address,
getting 0x000000000000000000000000ed3a7bb89eb3e355bed8975c5ff03e39d1c91c75
instead of 0xed3a7bb89eb3e355bed8975c5ff03e39d1c91c75
how to convert the output of method call to ethereum address?

Ethereum address is 20 bytes (40 hex characters) long. But each of the EVM storage slots has a capacity of 32 bytes (64 hex characters).
eth_call returns the raw data from the storage slot, doesn't adjust for datatype size. That's why there's the padding.
You can use the web3 decodeParameter() function to parse the address:
// returns "0xed3a7bb89eB3e355beD8975c5Ff03e39D1C91C75"
const address = web3.eth.abi.decodeParameter(
'address',
'0x000000000000000000000000ed3a7bb89eb3e355bed8975c5ff03e39d1c91c75'
);
And because both address and storage slot sizes are fixed, you can also use the regular JS slice() function to parse a substring (from the 26th position including the leading 0x).
// returns "0xed3a7bb89eB3e355beD8975c5Ff03e39D1C91C75"
const address = '0x' + '0x000000000000000000000000ed3a7bb89eb3e355bed8975c5ff03e39d1c91c75'.slice(26);

You can decode all the data as per the ABI.json
const output= window.ethereum.eth.request({method: "eth_call",params: [tx]});
let outputsTypes = this.contract.methods[method](...args)._method.outputs;
const result= window.ethereum.eth.abi.decodeParameters(outputsTypes, output);

Related

How to test an API response for binary

Question:What is the easiest way to test an API response for a binary response?
Context:I have a function that makes an API Call for some data. The response (api_response) of that API call will either be JSON or binary. If JSON, and if it contains percent_complete then the data is not yet ready, and my function uses the percent_complete key:pair value to update a progress bar for the user. If the response is JSON and contains meta, then my data is ready and has returned as a JSON object. If the response is binary, then my data is also ready, however has been returned as .xlsx [binary]. This is the response when the data is not ready and you will see percent_complete is utilized for a progress bar -
{
"data": {
"id": "2768510",
"type": "jobs",
"attributes": {
"job_type": "PORTFOLIO_VIEW_RESULTS",
"started_at": "2022-04-14T16:19:21Z",
"parameters": {
"end_date": "2022-04-14",
"output_type": "json",
"view_id": 304078,
"portfolio_id": 1,
"portfolio_type": "firm",
"start_date": "2022-04-14"
},
"percent_complete": 0.0,
"status": "In Progress"
},
"relationships": {
"creator": {
"links": {
"self": "/v1/jobs/2768510/relationships/creator",
"related": "/v1/jobs/2768510/creator"
},
"data": {
"type": "users",
"id": "731221"
}
}
},
"links": {
"self": "/v1/jobs/2768510"
}
},
"included": []
Current function:The following function continues to call the API every 5-seconds (using the 7-digit code in self, per the above API object) until meta is returned in a JSON object (therefore my data is returned as a JSON object) and returns the JSON object as api_response.Otherwise, the API call continues every 5-seconds and simply uses percent_complete to update a status bar (using enlighten library)
def api_call():
# Calling function containing the JOBS API endpoint for calling, until its RESPONSE == data requested.
endpoint_url = endpoint_initializer()
# Calling function containing API credentials
key, secret, url, group_url = ini_reader()
# Setting variable for use in progress bar, used to reflect API 'percent_complete' key pair value.
BAR_FORMAT = u'{id_value} {percentage:3.0f}%|{bar}| ' u'[{elapsed}<{eta}, {rate:.2f} %/s]'
manager = enlighten.get_manager()
date = dt.datetime.today().strftime("%Y-%m-%d")
print("------------------------------------\n","API URL constructed for:", date, "\n------------------------------------")
print("----------------------------------------------------------------------\n","Addepar Endpoint:", endpoint_url, "\n----------------------------------------------------------------------")
# Setting variable with counter for progress bar.
pbar = manager.counter(total=100, bar_format=BAR_FORMAT)
while True:
response = requests.get(url = endpoint_url, auth = HTTPBasicAuth(key, secret), headers = {"Vendor-firm": "665"})
api_response = json.loads(response.text)
if "meta" not in api_response:
id_value = "id"
res1 = [val[id_value] for key, val in api_response.items() if id_value in val]
id_value = "".join(res1)
percent_value = "percent_complete"
res2 = api_response["data"]["attributes"].get("percent_complete", '')*100
pbar.count = res2
pbar.update(incr=0, id_value=id_value)
time.sleep(5)
elif "meta" in api_response:
pbar.count = 100
pbar.update(incr=0, id_value=id_value)
pbar.close()
return api_response
How would I expand this function to test if the response (api_response) contains binary and if so, then return api_response?
A normal http-server should return an appropriate content-type. Please check:
response.headers['content-type']
Per Markus response, by accessing the Content-Type response.headers, I am able to trinagulate whether the response is binary (Content-Type: application/binary) or JSON (Content-Type: application/vnd.api+json).

RPC call with Metamask

I want to create an RPC call (study purpose) from my app using metamask.
My method on my contract is:
function sayHelloMyName(string memory _name) external pure returns (string memory) {
require(bytes(_name).length != 0, "insert your name");
return string(abi.encodePacked("hello ", _name));
}
its hash is:
$ web3.utils.keccak256("sayHelloMyName(string)").substr(0, 10)
> '0x10a7b27a'
I want to pass my name foo where the hex decimal is 0x666f6f
web3.utils.toHex('foo')
'0x666f6f'
So my call is:
ethereum
.request({
method: 'eth_call',
params: [
{
from: currentAccount,
to: contractAddress,
data: 0x10a7b27a0000000000000000000000000000000000000000000000000000000000666f6f
}, "latest"],
})
.then((txHash) => {
console.log(txHash);
$('#info').html(txHash);
})
.catch((error) => {
console.error;
$('#info').text(JSON.stringify(error.message));
});
where the data is the method signature, and my hex name and padding (total 32 bytes)
Unfortunately, I get a revert of it.
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "execution reverted"
}
}
the code works, I can use it with web3 library.
Solidity string is encoded as a dynamic-length array of bytes including the first 32byte slot pointing to the location of the array beginning and the second 32byte slot containing the length of the string. Meaning: Not just the hex value of the string that you're passing.
It works with web3js because the JS library decodes the hex back to string (web3 assumes the input is hex as it starts with 0x), and then encodes it correctly to the byte array while filling the data field.
See output of this web3js snippet
const data = web3.eth.abi.encodeFunctionCall({
name: 'sayHelloMyName',
type: 'function',
inputs: [{
type: 'string',
name: '_name'
}]
}, [
'foo',
]);
console.log(data);
that prints
# formatted for readability
0x10a7b27a
0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000003
666f6f0000000000000000000000000000000000000000000000000000000000
First slot is a pointer to the location where the array starts. In this case (hex20 == dec32) that's beginning of the second slot.
Second slot (value 3) is the length of the values
And the third slot contains the actual hex-encoded value of the string
Solution: This long value (without the newlines) is what you need to pass instead.

web3 encodeFunctionCall does not work (well 2 specific functions calls together in 1 transaction does not work)

I am trying to execute deposit and withdraw function from yDAI (yearn.finance) within the same transaction using web3 encodeFunctionCall. deposit function works, but, withdraw function fails. However, if I execute the withdraw function alone separately, then it works.
let abi1 = web3.eth.abi.encodeFunctionCall( { "name": "deposit", "type": "function", "inputs": [ { "name": "_amount", "type": "uint256" } ] }, [web3.utils.toWei((1000).toString(), 'Ether')] );
let abi2 = web3.eth.abi.encodeFunctionCall( {"constant":false,"inputs":[],"name":"withdrawAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, [] );
I am encoding the above in a js file and then calling a function present in my smart contract using an array. Code present in smart contract:
for (uint i = 0; i < _addrs.length; i++)
address(_addrs[i]).call(_bytecode[i]);
There are no error messages.
Here is the code and abi for yDAI (yearn.finance).
https://etherscan.io/address/0xACd43E627e64355f1861cEC6d3a6688B31a6F952#code
Can anyone help me to solve this puzzle?

ethereum rpc , send transaction

How to send a transaction using RPC on ethereum.?
On documentation I see this:
params: [{
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"gas": "0x76c0", // 30400,
"gasPrice": "0x9184e72a000", // 10000000000000
"value": "0x9184e72a", // 2441406250
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]
Where do I find this:
data": "0xd46e.......72445675
Is there any simple library that I can input only amount and the address of transaction?
Web3.js is the de-facto library for interacting with ethereum which you can use. There's great documentation on how to send transactions.
web3.eth.sendTransaction(transactionObject [, callback])
The data field is either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialization code. Data of messages are encoded methods and their argument values. You can use the library ethereumjs-abi to encode and decode data fields.
"data" parameter is not for you, if you just want to make a simple transaction.
To make simple transaction, you can simply ignore all parameters except "from", "to" and "value" and call the method in this way:
params: [{
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x9184e72a", // 2441406250
}]
You asked for simple library with just amount and address. It seems by address you mean "to" address. Unlike bitcoin rpc, which simply uses all addresses belongs to wallet as source of transaction, you should define exact "from" address with ethereum rpc.
I have written a couple of wrappers around Web3 for NodeJS and Web browsers.
The latter one helps abstracting connections and contract development.
const { connect, useConnection, sendTransaction } = require("web3-wrap");
try {
if(window.web3){
await useConnection(window.web3);
}
else {
await connect();
}
const receipt = await sendTransaction({
to: "0x1234...",
value: 10 // amount to transfer, in wei
});
console.log("Receipt:", receipt);
}
catch(err){
console.error(err && err.message || err);
}
Hope it heps

Consuming html/json web service

Does someone know how I can consume or use this testing service for sending XML signed (invoice cross control Treasury Ministry)
== STAGING / SANDBOX ==
URL API RECEPTION =
https://api.comprobanteselectronicos.go.cr/recepcion-sandbox/v1/
OAUTH 2.0 ACCESS TOKEN URL =
https://idp.comprobanteselectronicos.go.cr/auth/realms/rut-stag/protocol/openid-connect/token
CLIENT ID = api-­stag
CLIENT SECRET = [VACIO]
SCOPE = [VACIO]
Language traduction:
VACIO = EMPTY
Very good,
Passing the json data in the url post and get method.
Is something like this.!
https://api.comprobanteselectronicos.go.cr/recepcion-sandbox/v1/{
"id": "50601011600310112345600100010100000000011999999999",
"date": "2016-01-01T00:00:00-0600",
"transmitter": {
"idType": "02",
"idNumber": "003101123456"
},
"receiver": {
"idType": "02",
"idNumber": "003101123456"
},
"xmlInvoice": "PD94bWwgdmVyc2lvbj0iMS4wIiA/Pg0KDQo8ZG9tYWluIHhtbG5zPSJ1cm46amJvc3M6ZG9tYWluOjQuMCI+DQogICAgPGV4dGVuc2lvbnM+DQogICAgICAgIDxleHRlbnNpb24gbW9kdWxlPSJvcmcuamJvc3MuYXMuY2x1c3RlcmluZy5pbmZpbmlzcGFuIi8+DQogICAgICAgIDxleHRlbnNpb24gbW9kdWxlPSJvcmcuamJvc3MuYXMuY2x1c3RlcmluZy5qZ3JvdXBzIi8+DQogICAgICAgIDxleHRlbnNpb24gbW9kdWxlPSJvcmcuamJvc3MuYXMuY29ubmVjdG9yIi8+DQogICAgICAgIDxleHRlbnNpb24gbW..."
}
"xmlInvoice": {
"description": "XML electronic invoice signed by the taxpayer using XAdES-EPES. The XML text must be converted to a byte array and encoded in Base64. The character map to use in XML and in Base64 encoding is UTF8.",
"type": "string"
}