I have an ERC721 contract that is deployed via an UUPS proxy.
I have a proxy contract that forwards calls to the UUPS proxy via the _delegate
method.
For all methods besides one, I am getting:
> await thinContractWithProviderNoProxy.symbol()
Uncaught:
Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="symbol()", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.6.4)
at step (/Users/pw/Documents/coding/contracts/node_modules/@ethersproject/contracts/lib/index.js:48:23)
at Contract.<anonymous> (/Users/pw/Documents/coding/contracts/node_modules/@ethersproject/contracts/src.ts/index.ts:400:44)
at Interface.decodeFunctionResult (/Users/pw/Documents/coding/contracts/node_modules/@ethersproject/abi/src.ts/interface.ts:427:23)
at Logger.throwError (/Users/pw/Documents/coding/contracts/node_modules/@ethersproject/logger/src.ts/index.ts:273:20)
at Logger.makeError (/Users/pw/Documents/coding/contracts/node_modules/@ethersproject/logger/src.ts/index.ts:261:28) {
reason: null
The call that works is:
function setMintPrice(uint256 val) public payable {
mintPrice = val;
}
from:
contract ERC721 is
Initializable,
ERC721Upgradeable,
ERC721EnumerableUpgradeable,
ERC721URIStorageUpgradeable,
UUPSUpgradeable
{
using CountersUpgradeable for CountersUpgradeable.Counter;
uint256 mintPrice;
CountersUpgradeable.Counter private _tokenIdCounter;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {}
function initialize() public initializer {
__ERC721_init("Pluto ERC721", "PLUTO");
__ERC721Enumerable_init();
__ERC721URIStorage_init();
__UUPSUpgradeable_init();
}
function setMintPrice(uint256 val) public payable {
mintPrice = val;
}
function safeMint(address to, string memory uri) public {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) {
super._beforeTokenTransfer(from, to, tokenId);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId)
internal
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
{
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721Upgradeable, ERC721EnumerableUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function _authorizeUpgrade(address newImplementation) internal override {}
}
The error call revert exception means that:
1/ Method reverts during its execution.
2/ Method is not present in your contract.
3/ Contract not deployed on the network you're connected to (or address put is incorrect).
4/ Your network has some temporary outages.
3 and 4 aren't true since setMintPrice()
call should work. 2 shouldn't be true either given .symbol()
method does exist.
Why is my contract reverting in this case?
The proxy forwarding to the UUPS proxy looks like:
contract ThinContract is Proxy {
constructor(address addr) {
assert(
_IMPLEMENTATION_SLOT ==
bytes32(uint256(keccak256("eip1967.proxy.implementations")))
);
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = addr;
Address.functionDelegateCall(
addr,
abi.encodeWithSignature("initialize()")
);
}
bytes32 internal constant _IMPLEMENTATION_SLOT =
0x4f87f1e9c3bae405811ebf6eb673f2ac9deccca180b85510b910593bd47872ca;
/**
* @dev Returns the current implementation address.
*/
function implementation() public view returns (address) {
return _implementation();
}
function _implementation() internal view override returns (address) {
console.log("calling _implementation");
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}