@0xfutbol/id
Version:
React component library with shared providers for 0xFutbol ID
229 lines (228 loc) • 9.51 kB
JavaScript
;var index=require('./index-gEYw6hWC.js');require('react'),require('react/jsx-runtime'),require('@0xfutbol/id-sign'),require('react-use'),require('@0xfutbol/constants'),require('thirdweb'),require('@matchain/matchid-sdk-react'),require('@tanstack/react-query'),require('@matchain/matchid-sdk-react/index.css'),require('react-dom');/**
* Retrieves the value stored at a specific position in the storage of a contract.
* @param request - The EIP1193 request function.
* @param params - The parameters for the eth_getStorageAt method.
* @returns A promise that resolves to the value stored at the specified position.
* @rpc
* @example
* ```ts
* import { getRpcClient, eth_getStorageAt } from "thirdweb/rpc";
* const rpcRequest = getRpcClient({ client, chain });
* const storageValue = await eth_getStorageAt(rpcRequest, {
* address: "0x...",
* position: 0n,
* });
* ```
*/
async function eth_getStorageAt(request, params) {
return await request({
method: "eth_getStorageAt",
params: [
index.d(params.address),
params.position,
params.blockTag ?? "latest",
],
});
}/**
* Extracts the implementation address from a given bytecode string if it matches any of the known minimal proxy patterns.
* @param bytecode The bytecode string to extract the implementation address from.
* @returns The implementation address as a string if a match is found, otherwise undefined.
* @example
* ```ts
* import { extractMinimalProxyImplementationAddress } from "thirdweb/utils";
* const bytecode = "0x363d3d373d3d3d363d73...";
* const implementationAddress = extractMinimalProxyImplementationAddress(bytecode);
* ```
* @utils
*/
function extractMinimalProxyImplementationAddress(bytecode) {
if (!bytecode.startsWith("0x")) {
// biome-ignore lint/style/noParameterAssign: perf
bytecode = `0x${bytecode}`;
}
// EIP-1167 clone minimal proxy - https://eips.ethereum.org/EIPS/eip-1167
if (bytecode.startsWith("0x363d3d373d3d3d363d73")) {
const implementationAddress = bytecode.slice(22, 62);
return `0x${implementationAddress}`;
}
// Minimal Proxy with receive() from 0xSplits - https://github.com/0xSplits/splits-contracts/blob/c7b741926ec9746182d0d1e2c4c2046102e5d337/contracts/libraries/Clones.sol
if (bytecode.startsWith("0x36603057343d5230")) {
// +40 = size of addr
const implementationAddress = bytecode.slice(122, 122 + 40);
return `0x${implementationAddress}`;
}
// 0age's minimal proxy - https://medium.com/coinmonks/the-more-minimal-proxy-5756ae08ee48
if (bytecode.startsWith("0x3d3d3d3d363d3d37363d73")) {
// +40 = size of addr
const implementationAddress = bytecode.slice(24, 24 + 40);
return `0x${implementationAddress}`;
}
// vyper's minimal proxy (uniswap v1) - https://etherscan.io/address/0x09cabec1ead1c0ba254b09efb3ee13841712be14#code
if (bytecode.startsWith("0x366000600037611000600036600073")) {
const implementationAddress = bytecode.slice(32, 32 + 40);
return `0x${implementationAddress}`;
}
if (bytecode.startsWith("0x36600080376020600036600073")) {
const implementationAddress = bytecode.slice(28, 28 + 40);
return `0x${implementationAddress}`;
}
// EIP-7511 minimal proxy with PUSH0 opcode - https://eips.ethereum.org/EIPS/eip-7511
if (bytecode.startsWith("0x365f5f375f5f365f73")) {
const implementationAddress = bytecode.slice(20, 60);
return `0x${implementationAddress}`;
}
// EIP-7702 - https://eips.ethereum.org/EIPS/eip-7702#abstract
if (bytecode.length === 48 && bytecode.startsWith("0xef0100")) {
const implementationAddress = bytecode.slice(8, 48);
return `0x${implementationAddress}`;
}
return undefined;
}// TODO: move to const exports
const AddressZero = "0x0000000000000000000000000000000000000000";
const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
/**
* Resolves the implementation address and bytecode for a given proxy contract.
* @param contract The contract to resolve the implementation for.
* @returns A promise that resolves to an object containing the implementation address and bytecode.
* @example
* ```ts
* import { resolveImplementation } from "thirdweb";
* const implementation = await resolveImplementation(contract);
* ```
* @contract
*/
async function resolveImplementation(
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix any
contract) {
const [originalBytecode, beacon] = await Promise.all([
index.cM(contract),
getBeaconFromStorageSlot(contract),
]);
// check minimal proxy first synchronously
const minimalProxyImplementationAddress = extractMinimalProxyImplementationAddress(originalBytecode);
if (minimalProxyImplementationAddress) {
return {
address: minimalProxyImplementationAddress,
bytecode: await index.cM(index.at({
...contract,
address: minimalProxyImplementationAddress,
})),
};
}
// check other proxy types
let implementationAddress;
if (beacon && beacon !== AddressZero) {
// In case of a BeaconProxy, it is setup as BeaconProxy --> Beacon --> Implementation
// Hence we replace the proxy address with Beacon address, and continue further resolving below
// biome-ignore lint/style/noParameterAssign: we purposefully mutate the contract object here
contract = index.at({
...contract,
address: beacon,
});
implementationAddress = await getImplementationFromContractCall(contract);
}
else {
implementationAddress = await getImplementationFromStorageSlot(contract);
}
if (implementationAddress &&
index.cN(implementationAddress) &&
implementationAddress !== AddressZero) {
const implementationBytecode = await index.cM({
...contract,
address: implementationAddress,
});
// return the original contract bytecode if the implementation bytecode is empty
if (implementationBytecode === "0x") {
return {
address: contract.address,
bytecode: originalBytecode,
};
}
return {
address: implementationAddress,
bytecode: implementationBytecode,
};
}
return { address: contract.address, bytecode: originalBytecode };
}
async function getBeaconFromStorageSlot(
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix any
contract) {
/**
* The storage slot of the Beacon as defined in EIP-1967
* See https://eips.ethereum.org/EIPS/eip-1967#beacon-contract-address
*
* bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1))
*/
const rpcRequest = index.f({
client: contract.client,
chain: contract.chain,
});
try {
const proxyStorage = await eth_getStorageAt(rpcRequest, {
address: contract.address,
position: "0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50",
});
return `0x${proxyStorage.slice(-40)}`;
}
catch {
return undefined;
}
}
async function getImplementationFromStorageSlot(
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix any
contract) {
const rpcRequest = index.f({
client: contract.client,
chain: contract.chain,
});
try {
const proxyStoragePromises = [
eth_getStorageAt(rpcRequest, {
address: contract.address,
position: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
}),
eth_getStorageAt(rpcRequest, {
address: contract.address,
position:
// keccak256("matic.network.proxy.implementation") - used in polygon USDT proxy: https://polygonscan.com/address/0xc2132d05d31c914a87c6611c10748aeb04b58e8f#code
"0xbaab7dbf64751104133af04abc7d9979f0fda3b059a322a8333f533d3f32bf7f",
}),
eth_getStorageAt(rpcRequest, {
address: contract.address,
position:
// keccak256("org.zeppelinos.proxy.implementation") - e.g. base USDC proxy: https://basescan.org/address/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913#code
"0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3",
}),
];
const proxyStorages = await Promise.all(proxyStoragePromises);
const proxyStorage = proxyStorages.find((storage) => storage !== ZERO_BYTES32);
return proxyStorage ? `0x${proxyStorage.slice(-40)}` : AddressZero;
}
catch {
return undefined;
}
}
const UPGRADEABLE_PROXY_ABI = {
type: "function",
name: "implementation",
inputs: [],
outputs: [
{
type: "address",
name: "",
internalType: "address",
},
],
stateMutability: "view",
};
async function getImplementationFromContractCall(
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix any
contract) {
try {
return await index.P({ contract, method: UPGRADEABLE_PROXY_ABI });
}
catch {
return undefined;
}
}exports.resolveImplementation=resolveImplementation;//# sourceMappingURL=resolveImplementation-3PTFaS7f.js.map