</main>
<script type="module">
- document.querySelector('form').addEventListener('submit', async e => {
- e.preventDefault();
- const contract = e.target.elements['contract'].value;
- const rpc = e.target.elements['rpc'].value;
- const slotOutput = e.target.elements['slot-output'];
- const eventOutput = e.target.elements['event-output'];
-
- const slotPayload = [];
+ async function slotLookup(rpc, contract) {
const slots = {
// ERC-1967
'Logic contract address': '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', // keccak256('eip1967.proxy.implementation') - 1
'Beacon contract address': '0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50', // keccak256('eip1967.proxy.beacon') - 1
'Admin address': '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103', // keccak256('eip1967.proxy.admin') - 1
// ZeppelinOS (used in OpenZeppelin contracts v2 and below, predecessor to ERC-1967)
- 'Admin address (ZeppelinOS)': '0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b', // keccak256('org.zeppelinos.proxy.admin')
'Implementation address (ZeppelinOS)': '0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3', // keccak256('org.zeppelinos.proxy.implementation')
+ 'Admin address (ZeppelinOS)': '0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b' // keccak256('org.zeppelinos.proxy.admin')
}
+
+ const slotPayload = [];
for (const [key, value] of Object.entries(slots)) {
slotPayload.push({
jsonrpc: '2.0',
});
}
- const eventPayload = [];
+ const response = await fetch(rpc, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(slotPayload)
+ }).then(r => r.json());
+
+ const output = [];
+ for (const item of response) {
+ if (item?.result === undefined || Number(item.result) === 0) {
+ continue;
+ }
+ output.push({ id: item.id, data: `0x${item.result.substring(26)}` });
+ }
+ return output;
+ }
+
+ async function eventLookup(rpc, contract) {
const events = {
'Upgraded(address)': '0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b',
'BeaconUpgraded(address)': '0x1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e',
'AdminChanged(address,address)': '0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f'
}
+
+ const eventPayload = [];
for (const [key, value] of Object.entries(events)) {
eventPayload.push({
jsonrpc: '2.0',
});
}
- slotOutput.innerHTML = '';
- eventOutput.innerHTML = '';
-
- // Storage slot lookup
- fetch(rpc, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(slotPayload)
- })
- .then(r => r.json())
- .then(r => r.forEach(i => { Number(i.result) === 0 || slotOutput.insertAdjacentHTML('beforeend', `<p>${i.id}: 0x${i.result.substring(26)}</p>`) }));
-
- // Event lookup
- fetch(rpc, {
+ const response = await fetch(rpc, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(eventPayload)
- })
- .then(r => r.json())
- .then(r => {
- r.forEach(item => {
- if (item?.result === undefined) {
- return;
- }
- for (const log of item.result) {
- if (log.data === '0x') { // Upgraded event (new address is indexed)
- eventOutput.insertAdjacentHTML('beforeend', `<p>${item.id} (block ${Number(log.blockNumber)}): 0x${log.topics[1].substring(26)}</p>`);
- }
- else { // Admin changed event (new address is not indexed)
- eventOutput.insertAdjacentHTML('beforeend', `<p>${item.id} (block ${Number(log.blockNumber)}): 0x${log.data.slice(-40)}</p>`);
- }
- }
- });
- });
+ }).then(r => r.json());
+
+ const output = [];
+ for (const item of response) {
+ if (item?.result === undefined) {
+ continue;
+ }
+ for (const log of item.result) {
+ if (log.data === '0x') { // Upgraded event (new address is indexed)
+ output.push({ id: item.id, blockNumber: Number(log.blockNumber), data: `0x${log.topics[1].substring(26)}` });
+ }
+ else { // Admin changed event (new address is not indexed)
+ output.push({ id: item.id, blockNumber: Number(log.blockNumber), data: `0x${log.data.slice(-40)}` });
+ }
+ }
+ }
+ return output;
+ };
+
+ document.querySelector('form').addEventListener('submit', e => {
+ e.preventDefault();
+ const contract = e.target.elements['contract'].value;
+ const rpc = e.target.elements['rpc'].value;
+ const slotOutput = e.target.elements['slot-output'];
+ const eventOutput = e.target.elements['event-output'];
+
+ slotOutput.innerHTML = '';
+ eventOutput.innerHTML = '';
+
+ slotLookup(rpc, contract).then(arr => arr.forEach(i => slotOutput.insertAdjacentHTML('beforeend', `<p>${i.id}: ${i.data}</p>`)));
+ eventLookup(rpc, contract).then(arr => arr.forEach(i => eventOutput.insertAdjacentHTML('beforeend', `<p>${i.id} (block ${i.blockNumber}): ${i.data}</p>`)));
});
</script>
</body>