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.