UNPKG

@dethcrypto/eth-sdk

Version:

🛠 Generate type-safe, lightweight SDK for your Ethereum smart contracts

68 lines • 3.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NUMBER_OF_KNOWN_STORAGE_SLOTS = exports.ZEPPELIN_IMPLEMENTATION_STORAGE_SLOT = exports.EIP1967_IMPLEMENTATION_STORAGE_SLOT = exports.detectProxy = void 0; const abi_1 = require("@ethersproject/abi"); const bignumber_1 = require("@ethersproject/bignumber"); const config_1 = require("../config"); async function detectProxy(address, abi, provider) { const stored = await lookForImplementationAddr(address, abi, provider); const asNumber = bignumber_1.BigNumber.from(stored || 0); if (!asNumber.isZero()) { const implAddress = asNumber.toHexString(); const code = await provider.getCode(implAddress); const isContract = !bignumber_1.BigNumber.from(code).isZero(); if (isContract) { return { implAddress: (0, config_1.parseAddress)(implAddress), isProxy: true }; } } return { isProxy: false }; } exports.detectProxy = detectProxy; async function lookForImplementationAddr(address, abi, provider) { const call = async (name) => bignumber_1.BigNumber.from(await provider.call({ to: address, data: new abi_1.Interface(abi).encodeFunctionData(name, []), })); // We check storage slot specified by EIP-1967 to hold implementation address. // see https://eips.ethereum.org/EIPS/eip-1967 { const stored = bignumber_1.BigNumber.from(await provider.getStorageAt(address, exports.EIP1967_IMPLEMENTATION_STORAGE_SLOT)); if (!stored.isZero()) return stored; } // We check storage slot specified by openzeppelin to hold implementation address. // see https://github.com/OpenZeppelin/openzeppelin-labs/blob/master/initializer_with_sol_editing/contracts/UpgradeabilityProxy.sol#L24 { const stored = bignumber_1.BigNumber.from(await provider.getStorageAt(address, exports.ZEPPELIN_IMPLEMENTATION_STORAGE_SLOT)); if (!stored.isZero()) return stored; } // If there is an `.implementation` getter, we try to call it. const implementationGetter = abi.find((fragment) => fragment.name === 'implementation'); if (implementationGetter && isPossibleImplementationGetter(implementationGetter)) { return call('implementation'); } // Otherwise, we try shortest getter ending with "Implementation" const possibleImplementationGetters = abi.filter(isPossibleImplementationGetter); if (possibleImplementationGetters.length) { const [frag] = possibleImplementationGetters.sort((a, b) => a.name.length - b.name.length); return call(frag.name); } return null; } /** @internal */ exports.EIP1967_IMPLEMENTATION_STORAGE_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'; exports.ZEPPELIN_IMPLEMENTATION_STORAGE_SLOT = '0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3'; exports.NUMBER_OF_KNOWN_STORAGE_SLOTS = 2; const isPossibleImplementationGetter = (frag) => { var _a; if (frag.type === 'function' && frag.name && frag.name.match(/[iI]mplementation$/) && (frag.stateMutability === 'view' || frag.stateMutability === 'pure')) { const output = (_a = frag.outputs) === null || _a === void 0 ? void 0 : _a[0]; return (output === null || output === void 0 ? void 0 : output.type) === 'address'; } return false; }; //# sourceMappingURL=detectProxy.js.map