Environment
- Private Quorum Network with Raft Consensus
- “devDependencies”: {
“@nomiclabs/hardhat-ethers”: “^2.0.2”,
“@openzeppelin/hardhat-upgrades”: “^1.7.0”,
“ethers”: “^5.1.4”
},
“dependencies”: {
“@openzeppelin/contracts-upgradeable”: “^4.1.0”
}
Details
I am very new to OpenZeppelin and thanks for building such a awesome tool. my questions is
I use hardhat-upgrades plugin to deploy a upgradable contract:MyToken.sol and I believe the deployment is working since I can use the deployed proxy instance to trigger function (below code works for me):
const MyTokenContract = await ethers.getContractFactory("MyToken");
const contract = await upgrades.deployProxy(MyTokenContract);
await contract.deployed();
const contractName = await contract.name();
Also I can get below info from this deployment:
- Proxy contract’s address
- ABI of upgradable contract (MyToken.sol)
After that, I store the proxy address and contract abi in a database b/c for my case, I need to use a nodeJS application leverage that proxy contract address, MyToken’s abi and user’s keystore to call that upgradable contract’s function through the proxy contract.
I try the ethers’s new ethers.Contract( address , abi , signerOrProvider)
to init that upgradable contract instance and call the function, but it looks like I failed to use proxy contract address and MyToken.sol 's abi to do it. I get a error when I trigger the contract(MyToken.sol) function:
Error: call revert exception (method="name()", errorSignature=null, errorArgs=[null], reason=null, code=CALL_EXCEPTION, version=abi/5.1.2)
at Logger.makeError (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/logger/src.ts/index.ts:205:28)
at Logger.throwError (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/logger/src.ts/index.ts:217:20)
at Interface.decodeFunctionResult (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/abi/src.ts/interface.ts:326:23)
at Contract.<anonymous> (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/contracts/src.ts/index.ts:321:44)
at step (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/contracts/lib/index.js:48:23)
at Object.next (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/contracts/lib/index.js:29:53)
at fulfilled (/Users/mbao010/Documents/gitbase/pwc/drip/drip-contract-v2/node_modules/@ethersproject/contracts/lib/index.js:20:58)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at runNextTicks (internal/process/task_queues.js:62:3)
at listOnTimeout (internal/timers.js:523:9) {
reason: null,
So the questions is
- is that the right way to implement call a upgradeable contract via proxy address ,abi and signer ?
- For my current approach, I feel like I should get the proxy’s abi rather than the implementation contract’s abi, please suggest how to fix it.
Code to reproduce
-
Token.sol
contract MyToken is ERC20Upgradeable, OwnableUpgradeable { event Mint(address indexed _account, uint256 _amount); event Burn(address indexed _account, uint256 _amount); function initialize() initializer public { __ERC20_init("MyToken", "MTK"); } function decimals() public pure override returns (uint8) { return 18; } function transfer(address recipient, uint256 amount) public override returns (bool) { // TODO: add access permission check return super.transfer(recipient, amount); } function balanceOf(address acccount) public view override returns (uint256){ // TODO: add access permission check return super.balanceOf(acccount); } /** Below are admin functions **/ function transferFrom(address sender, address recipient, uint256 amount) public override onlyOwner returns (bool) { // TODO: add access permission check // TODO: add balance check _transfer(sender, recipient, amount); return true; } function mint(address account, uint256 amount) public onlyOwner { // TODO: add access permission check _mint(account, amount); emit Mint(account, amount); } function burn(address account, uint256 amount) public onlyOwner { // TODO: add access permission check _burn(account, amount); emit Burn(account, amount); }
}
-
deploy contract
const MyTokenContract = await ethers.getContractFactory(“MyToken”);
const contract = await upgrades.deployProxy(MyTokenContract);
await contract.deployed();
const contractName = await contract.name();// this is working
console.log(“Deployed Proxy Contract address:”, contract.address); -
Call contract via ethers
const contract = new ethers.Contract(proxyContractAddress, abi, signer)
const name = await contract.name(); // not work