create upgradable proxy contract that works with MetaMask - ethereum

I'm creating a proxy contract that connect to existing ERC-20 contract.
this proxy contract should able to connects with metamask and show token balances.
every things works fine when add token in metamask with proxy address, it show symbol and decimal number correctly but not balance. shown zero instead.
proxy contract code:
contract Proxy {
address private _implementation;
event Upgraded(address indexed implementation);
function implementation() public view returns (address) {
return _implementation;
}
function upgradeTo(address impl) public {
_implementation = impl;
emit Upgraded(impl);
}
function () payable external {
address _impl = implementation();
require(_impl != address(0));
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
let size := returndatasize
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
the function balanceOf working fine when i add token in metamask with ERC-20 contract address. but show zero by proxy contract
function balanceOf(address tokenOwner) public view returns (uint256) {
return balances[tokenOwner];
}
My efforts
for test i wrote this function:
function test(address theAddress) public view returns (address) {
return theAddress ;
}
when i call argument '0xC357c241b98B15B3A08aeC3AcD49fBC0cbD74fcE'
on ERC-20 contract returns same address but on proxy returns
this value:
0xc357c241b98b19150f7f8f1d47ad1cd500000000
another test that i do is this function:
function test2(string memory theString) public view returns (string memory) {
return theString ;
}
this function works fine on both proxy and ERC-20 contract!!
thanks all.
Edit 1
my test with web3.js
var interval ;
document.addEventListener('DOMContentLoaded', function() {
interval = setInterval(run , 1000);
}, false);
function run(){
web3 = new Web3(web3.currentProvider);
console.log("call");
if(web3.eth.accounts[0] === undefined)
return;
clearInterval(interval);
console.log(web3.eth.accounts[0]);
web3.eth.defaultAccount = web3.eth.accounts[0];
var CoursetroContract = web3.eth.contract( JSON.parse(`[
{
"constant": true,
"inputs": [
{
"name": "theAddress",
"type": "address"
}
],
"name": "test",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "theString",
"type": "string"
}
],
"name": "test2",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]`));
var contract = CoursetroContract.at('0xd3744cac3a2f796c16b45e5be582c1c5f3039482'); //proxy
//var contract = CoursetroContract.at('0xd025c8835b2a4bd2f9eeb1d682db224f7b301868'); //erc20
contract.test(0xC357c241b98B15B3A08aeC3AcD49fBC0cbD74fcE,
function(err,result){
console.log("err" ,err);
console.log("result" , result);
}
);
Edit 2
this contract addresses is already available in Ropsten Testnet

The proxy contract works a bit differently.
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
The DELEGATECALL in your proxy contract calls the contract via the address specified in _impl. So, as a result, it runs the _impl code ( in your case ERC20 ) in proxy contracts's environment. As a result, the storage of proxy is modified and not ERC20 contracts storage. Link to how delegatecall works.
So my suggestion would be to look at how you are initializing your ERC20 contract and setting its balance.
You would have to do something like this
erc20Contract = await erc20Contract.at(proxy.address)
erc20Contract.initialize()
The first line gives you the interface of erc20Contract at proxy contract's address.
And the second line would redo the work of the constructor at proxy contract's address and storage.

Related

Quorum: "invalid opcode: SELFBALANCE" error unless 'petersburg' chosen manually

We are running a GoQuorum 27.7 network.
In Remix with 'default' as the EVM version, when running the function SELFBALANCE it gives the error: invalid opcode: SELFBALANCE .
However, when manually choosing "petersburg" as the EVM version, it works fine.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
contract TestCalls {
uint256 public XYSTORED = 0;
function setBalance() external returns(uint256) {
XYSTORED = address(this).balance;
return XYSTORED;
}
function withdawlCIC() external {
payable(msg.sender).transfer(XYSTORED);
XYSTORED = address(this).balance;
}
function emergencyWithdrawl() external {
payable(msg.sender).transfer(XYSTORED);
}
function ViewXXBalance() external view returns(uint256 balance) {
balance = address(this).balance;
}
}
What is the approach to allow let it work without having to choose "petersburg" every time a contract with this function is deployed?
It is a QBFT network.
"config": {
"chainId": 1234,
"homesteadBlock": 0,
"eip150Block": 0,
"eip150Hash": "0x0000000000000000000000000000000000000000000000>
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
..........
I tried adding the following transitions to Genesis. The issue persisted:
"transitions": [{
"block": 54074,
"istanbulBlock": true
},
{
"block": 547122,
"petersburgBlock": true
}]
To run a function in Remix to retrieve the self balance.

How to get access to specific metadata of a ERC721 token

I would like to get n ERC721 token with a specific "dna".
See the metadata below:
{
"dna": "602472F",
"name": "Test #1",
"description": "My Collectibles",
"image": "ipfs://QmasMm8v9WkU11BtnWsybDW6/1.png",
"edition": 1,
"attributes": [
{
"trait": "type",
"value": "Fire"
},
{
"trait_type": "Eyes",
"value": "Black"
}
]
}
I know how to access a token using tokenURI.
Here is my code:
string public uri;
string public uriSuffix = ".json";
function _baseURI() internal view virtual override returns (string memory) {
return uri;
}
function tokenURI(uint256 _tokenId) public view virtual override returns (string memory){
require(_exists(_tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory currentBaseURI = _baseURI();
return bytes(currentBaseURI).length > 0 ? string(abi.encodePacked(currentBaseURI, _tokenId.toString(), uriSuffix)) : "";
}
Now, how can I check if a token has the dna I am looking for? Should I get this info from Opensea API or from the solidity side?
Ps: All my .json and .png files are hosted in IPFS.
EVM contracts are not able to read offchain data (the JSON file) directly. You'd need to use an offchain app (or an oracle provider such as Chainlink) for that to feed the offchain data to the contract.
So it's much easier to just query the data from an offchain app.
Example using node.js and the web3 package for querying the contract:
const contract = new web3.eth.Contract(abiJson, contractAddress);
const tokenURI = await contract.methods.tokenURI(tokenId);
const contents = (await axios.get(tokenURI)).data;
return contents.dna;

Sending both ether and calling function on smart contract using Web3

So there's an ERC20 contract with an additional fallback function. I am trying to send ether to the contract as well as send tokens in same transaction. I am not sure if this is possible but I have found some examples of sending custom data to a contract. I have following code:
async getTransaction(sender: string, receiver: string, value: string, amount: string, gasPrice: number) {
let data = this.tokenContract.methods.transfer(receiver, amount).encodeABI();
let gas = await this.web3.eth.estimateGas({
value,
data,
from: sender,
to: this.CONTRACT_ADDRESS
});
let nonce = await this.getNonce(sender);
return {
value,
// data,
from: sender,
to: this.CONTRACT_ADDRESS,
gas: this.web3.utils.toHex(Math.trunc(gas)),
gasPrice: this.web3.utils.toHex(Math.trunc(gasPrice * 1e9)),
chain: this.web3.utils.toHex(1337),
nonce,
hardfork: "MUIRCLACIER"
}
}
It only works to send tokens when value is 0. If value is positive it fails at the gas estimation step with the error below. It only works if data field is removed from gas estimation and transaction, it sends the specified value successfully.
The question, is it technically possible to do both: send ether and invoke a function on the contract in a single transaction?
{
"message": "VM Exception while processing transaction: revert",
"code": -32000,
"data": {
"stack": "RuntimeError: VM Exception while processing transaction: revert\n at Function.RuntimeError.fromResults (/Applications/Ganache.app/Contents/Resources/static/node/node_modules/ganache-core/lib/utils/runtimeerror.js:94:13)\n at module.exports (/Applications/Ganache.app/Contents/Resources/static/node/node_modules/ganache-core/lib/utils/gas/guestimation.js:142:32)",
"name": "RuntimeError"
}
}
Error: Internal JSON-RPC error.
{
"message": "VM Exception while processing transaction: revert",
"code": -32000,
"data": {
"stack": "RuntimeError: VM Exception while processing transaction: revert\n at Function.RuntimeError.fromResults (/Applications/Ganache.app/Contents/Resources/static/node/node_modules/ganache-core/lib/utils/runtimeerror.js:94:13)\n at module.exports (/Applications/Ganache.app/Contents/Resources/static/node/node_modules/ganache-core/lib/utils/gas/guestimation.js:142:32)",
"name": "RuntimeError"
}
}
is it technically possible to do both: send ether and invoke a function on the contract in a single transaction?
Yes. The function receiving ETH needs to be have the payable modifier.
function foo() external payable {
// the received amount is in the global variable `msg.value`
}

Go-ethereum private network in Proof-of-Authority problem: call contract method but nothing response

When I created a 2 nodes private network with POA consensus and it works fine when I sent a simple transaction.
But when I deploy a simple contract SimpleStorage.sol with Truffle, I want to call the get() method by using the myetherwallet, but it returns 0 , not 100.
The detailed of SimpleStorage is as shown below:
pragma solidity >=0.4.17;
contract SimpleStorage {
uint storedData = 100;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
System information
Geth Version: 1.8.23-stable
Git Commit: c942700427557e3ff6de3aaf6b916e2f056c1ec2
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.11.5
Operating System: darwin (MacOs)
GOPATH=
GOROOT=/Users/travis/.gimme/versions/go1.11.5.darwin.amd64
Truffle v5.0.7 (core: 5.0.7)
Solidity v0.5.0 (solc-js)
Node v9.10.0
Behavior to reproduce
Genesis.json
{
"config": {
"chainId": 1515,
"homesteadBlock": 1,
"eip150Block": 2,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 3,
"eip158Block": 3,
"byzantiumBlock": 4,
"clique": {
"period": 2,
"epoch": 30000
}
},
"nonce": "0x0",
"timestamp": "0x5d5769ad",
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000003b50d35ed4032c984992ad0d757ba65338523919fc0f1c754a2dfa18640ce2a0950aea20d1d206940000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x7FFFFFFFFFFFF",
"difficulty": "0x1",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"3b50d35ed4032c984992ad0d757ba65338523919": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"fc0f1c754a2dfa18640ce2a0950aea20d1d20694": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
}
},
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
Geth start command
geth --datadir node1/ --syncmode 'full' --port 30312 --rpc --rpcaddr 0.0.0.0 --rpcport 8502 --rpccorsdomain "*" --ws --wsaddr 0.0.0.0 --wsport 8602 --wsorigins "*" --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3 --wsapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3 --bootnodes 'enode://4765bd12afddce5bb5a2ea55e58ffcdbade132a593bddd9f2723e18460b407039bf07e3fa851b12b0b20c8e0b4c2d3518c9578f201b4efe6ab4d9243e28cccaa#127.0.0.1:30310' --networkid 1515 --gasprice '1' -unlock '0x3b50d35ed4032c984992ad0d757ba65338523919' --password node1/password.txt --mine --targetgaslimit 2251799813685247
Truffle set up
truffle-config.js
module.exports = {
networks: {
geth: {
host: "127.0.0.1",
port: 8501,
from: "0xfc0f1c754a2dfa18640ce2a0950aea20d1d20694",
network_id: "*",
gasPrice: "0x47B7600",
gas: "0x47B7600"
}
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
// version: "0.5.1", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
// evmVersion: "byzantium"
// }
}
}
}
migration script
truffle migrate --network geth --reset
Expected behavior
When called get() method, it should return 100.
Actual behaviour
It returned 0
I found that there's another one ran into a similar issue as me:
One of ethereum solidity methods is not working properly got error Returned values aren't valid, did it run Out of Gas
Can anyone help me to address this issue?
I have figured out why I cannot retrieve the value from variable storedData...
When I set storedData to be public, then it works fined.
(But to be noticed that if using ganache-cli, I can get the storedData even if it is not public variable...)
pragma solidity >=0.4.17;
contract SimpleStorage {
// uint storedData = 100;
uint public storedData = 100; // set it to be public
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}

oracles implementation with smart contracts

I am trying to deploy a smart contract to a private Blockchain which uses oraclizeAPI.sol library code.
Basically the smart contract is a small implementation of oraclize.
The import does not work, either with the github link or with local import, solc compilation fails because of import.
Both of the below does not work, the contract is not getting properly compiled by solc
1.import "oraclizeAPI.sol";
2.import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";
So, next approch i took was to copy the code of oraclizeAPI.sol, directly into the contract code file.
Now the contract gets compiled properly but the i am falling shot on gas every time, while deploying.
Error:
The contract couldn't be stored, please check your gas amount.
Now here are the details of the Blockchain.
genesis.json
{
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x4000",
"alloc": {
"84840c340067c75806273d2524dfbae646a7c68f":
{ "balance": "1606938044258990275541962092341162602522202993782792835301376" }
},
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase": "0x84840c340067c75806273d2524dfbae646a7c68f",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x8000000000000000"
}
I am currently trying to deply the contract using the coinbase id.
web3.eth.getBlock("latest").gasLimit
132661998547049420
web3.eth.getBalance('0x84840c340067c75806273d2524dfbae646a7c68f').e
60
contract code:
contract oraclizeExample is usingOraclize {
string public data;
event newOraclizeQuery(string description);
event newData(string data);
event eventC(string data);
function oraclizeExample() payable {
update();
}
function __callback(bytes32 myid, string result) {
if (msg.sender != oraclize_cbAddress()) throw;
data = result;
newData(result);
//return result;
}
function eventCheck(string dataFClient) returns (string) {
eventC(dataFClient);
return dataFClient;
}
function update() payable returns (string) {
newOraclizeQuery("Oraclize query was sent, standing by for the answer..");
oraclize_query("URL", "json(https://jewel-api.herokuapp.com/jewel/58d89d264d59a000110829bb).invoice_num");
return "update function was called!";
}
}
The code of contract creation.
var ContractABI = web3.eth.contract(JSON.parse(interface));
var SaveContract = ContractABI.new(
{
from: account,
data: bytecode,
gas: '93048696279858031'
}, function (e, contract) {
if(e){
console.log(e, contract);
return;
}
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
fs.writeFileSync('./contracts_data/'+ contract_name + '_final', 'Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash)
return;
}
});
If you want to check the complete contract code with the and the way i am doing this please got to this link.
https://github.com/utkarsh17ife/oraclizeExample/tree/master/contracts_data
Or the complete implementation with node as well:
https://github.com/utkarsh17ife/oraclizeExample
And yes i am able to mine other contract using this setup.
Comment if you need further info on this.
If you are using a private chain you must run the ethereum-bridge, you are getting a throw because your smart contract invokes the oraclize_query function on deployment (constructor function) but no Oraclize contracts were found on your chain.