diff --git a/src/components/ppom/batching.js b/src/components/ppom/batching.js index f00050cd..6f66b136 100644 --- a/src/components/ppom/batching.js +++ b/src/components/ppom/batching.js @@ -159,7 +159,7 @@ export function ppomMaliciousBatchingAndQueueing(parentContainer) { params: [ { from: globalContext.accounts[0], - to: '0x5FbDB2315678afecb367f032d93F642f64180aa3', + to: maliciousAddress, value: '0x0', gasLimit: MIN_GAS_LIMIT, maxFeePerGas: '0x2540be400', diff --git a/src/components/ppom/eip5792.js b/src/components/ppom/eip5792.js new file mode 100644 index 00000000..d913c67a --- /dev/null +++ b/src/components/ppom/eip5792.js @@ -0,0 +1,220 @@ +import globalContext from '../..'; +import { DEFAULT_CALLS, VERSION } from '../transactions/eip5792/sendCalls'; +import { getMaliciousTransactions } from './sharedConstants'; + +export function ppomMaliciousSendCalls(parentContainer) { + parentContainer.insertAdjacentHTML( + 'beforeend', + `
+
+
+

+ PPOM - EIP 5792 - Malicious Send Calls +

+ + + + + + +
+ + + +

+ Status +

+
+
+
`, + ); + + const ppomSendMaliciousEthButton = document.getElementById( + 'ppomSendMaliciousEthButton', + ); + + ppomSendMaliciousEthButton.onclick = async () => { + await sendMaliciousCalls('eth'); + }; + + const ppomSendMaliciousERC20TransferButton = document.getElementById( + 'ppomSendMaliciousERC20TransferButton', + ); + + ppomSendMaliciousERC20TransferButton.onclick = async () => { + await sendMaliciousCalls('erc20Transfer'); + }; + + const ppomSendMaliciousERC20ApprovalButton = document.getElementById( + 'ppomSendMaliciousERC20ApprovalButton', + ); + + ppomSendMaliciousERC20ApprovalButton.onclick = async () => { + await sendMaliciousCalls('erc20Approval'); + }; + + const ppomSendMaliciousSetApprovalForAllButton = document.getElementById( + 'ppomSendMaliciousSetApprovalForAllButton', + ); + + ppomSendMaliciousSetApprovalForAllButton.onclick = async () => { + await sendMaliciousCalls('setApprovalForAll'); + }; + + const ppomSendMaliciousContractInteractionButton = document.getElementById( + 'ppomSendMaliciousContractInteractionButton', + ); + + ppomSendMaliciousContractInteractionButton.onclick = async () => { + await sendMaliciousCalls('maliciousContractInteraction'); + }; + + const ppomSendThreeMaliciousTxsButton = document.getElementById( + 'ppomSendThreeMaliciousTxsButton', + ); + + ppomSendThreeMaliciousTxsButton.onclick = async () => { + await sendThreeMaliciousCalls(); + }; + + document.addEventListener('globalConnectionChange', function (e) { + if (e.detail.connected) { + // MetaMask is connected, enable the button + ppomSendMaliciousEthButton.disabled = false; + ppomSendMaliciousERC20TransferButton.disabled = false; + ppomSendMaliciousERC20ApprovalButton.disabled = false; + ppomSendMaliciousSetApprovalForAllButton.disabled = false; + ppomSendMaliciousContractInteractionButton.disabled = false; + ppomSendThreeMaliciousTxsButton.disabled = false; + } + }); + + document.addEventListener('disableAndClear', function () { + ppomSendMaliciousEthButton.disabled = true; + ppomSendMaliciousERC20TransferButton.disabled = true; + ppomSendMaliciousERC20ApprovalButton.disabled = true; + ppomSendMaliciousSetApprovalForAllButton.disabled = true; + ppomSendMaliciousContractInteractionButton.disabled = true; + ppomSendThreeMaliciousTxsButton.disabled = true; + }); + + async function sendMaliciousCalls(type) { + const maliciousTransactions = getMaliciousTransactions(globalContext); + const calls = []; + + switch (type) { + case 'eth': + calls.push(maliciousTransactions.eth); + break; + case 'erc20Transfer': + calls.push(maliciousTransactions.erc20Transfer); + break; + case 'erc20Approval': + calls.push(maliciousTransactions.erc20Approval); + break; + case 'maliciousContractInteraction': + calls.push(maliciousTransactions.maliciousContractInteraction); + break; + case 'setApprovalForAll': + calls.push(maliciousTransactions.setApprovalForAll); + break; + default: + // Do nothing + break; + } + + calls.push(...DEFAULT_CALLS); + + try { + const result = await globalContext.provider.request({ + method: 'wallet_sendCalls', + params: [getParams(calls)], + }); + document.getElementById('ppomRequestIdInput').value = result.id; + document.getElementById('ppomRequestIdContainer').hidden = false; + document.getElementById('ppomGetCallsStatusButton').disabled = false; + document.getElementById('ppomSendCallsErrorContainer').hidden = true; + } catch (error) { + console.error(error); + document.getElementById('ppomSendCallsErrorContainer').hidden = false; + document.getElementById( + 'ppomSendCallsError', + ).innerHTML = `Error: ${error.message}`; + } + } + + async function sendThreeMaliciousCalls() { + const maliciousTransactions = getMaliciousTransactions(globalContext); + + const calls = [ + maliciousTransactions.erc20Approval, + maliciousTransactions.setApprovalForAll, + maliciousTransactions.maliciousContractInteraction, + ]; + + try { + const result = await globalContext.provider.request({ + method: 'wallet_sendCalls', + params: [getParams(calls)], + }); + document.getElementById('ppomRequestIdInput').value = result.id; + document.getElementById('ppomRequestIdContainer').hidden = false; + document.getElementById('ppomGetCallsStatusButton').disabled = false; + document.getElementById('ppomSendCallsErrorContainer').hidden = true; + } catch (error) { + console.error(error); + document.getElementById('ppomSendCallsErrorContainer').hidden = false; + document.getElementById( + 'ppomSendCallsError', + ).innerHTML = `Error: ${error.message}`; + } + } + + // Get Calls Status functionality + document.getElementById('ppomGetCallsStatusButton').onclick = async () => { + const requestId = document.getElementById('ppomRequestIdInput').value; + const resultOutput = document.getElementById('ppomGetCallsStatusResult'); + + try { + const result = await globalContext.provider.request({ + method: 'wallet_getCallsStatus', + params: [requestId], + }); + + resultOutput.innerHTML = JSON.stringify(result, null, 2); + document.getElementById('ppomGetCallsStatusButton').disabled = false; + } catch (error) { + console.error(error); + resultOutput.innerHTML = `Error: ${error.message}`; + } + }; + + function getParams(calls) { + return { + version: VERSION, + from: globalContext.accounts[0], + chainId: `0x${globalContext.chainIdInt.toString(16)}`, + atomicRequired: true, + calls, + }; + } +} diff --git a/src/components/ppom/index.js b/src/components/ppom/index.js index e47c77b8..335180e0 100644 --- a/src/components/ppom/index.js +++ b/src/components/ppom/index.js @@ -1,3 +1,4 @@ -export * from './transactions'; export * from './batching'; export * from './bypasses'; +export * from './eip5792'; +export * from './transactions'; diff --git a/src/components/ppom/sharedConstants.js b/src/components/ppom/sharedConstants.js new file mode 100644 index 00000000..7969163f --- /dev/null +++ b/src/components/ppom/sharedConstants.js @@ -0,0 +1,51 @@ +import { maliciousAddress } from '../../sample-addresses'; +import { + ERC20_SAMPLE_CONTRACTS, + ERC721_SAMPLE_CONTRACTS, + MALICIOUS_CONTRACT_ADDRESSES, + NETWORKS_BY_CHAIN_ID, +} from '../../onchain-sample-contracts'; + +const maliciousTransactionsCache = {}; + +export const getMaliciousTransactions = (globalContext) => { + const chainId = globalContext.chainIdInt; + const networkName = NETWORKS_BY_CHAIN_ID[chainId] || 'default'; + + // to avoid recalculating the tx object everytime if the chainId hasn't changed + if (maliciousTransactionsCache[chainId]) { + return maliciousTransactionsCache[chainId]; + } + + const transactions = { + eth: { + to: maliciousAddress, + value: '0x9184e72a000', + }, + erc20Transfer: { + to: ERC20_SAMPLE_CONTRACTS[networkName], + data: '0xa9059cbb0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa30000000000000000000000000000000000000000000000000000000000000064', + value: '0x0', + }, + erc20Approval: { + to: ERC20_SAMPLE_CONTRACTS[networkName], + data: '0x095ea7b3000000000000000000000000e50a2dbc466d01a34c3e8b7e8e45fce4f7da39e6000000000000000000000000000000000000000000000000ffffffffffffffff', + value: '0x0', + }, + setApprovalForAll: { + to: ERC721_SAMPLE_CONTRACTS[networkName], + data: '0xa22cb465000000000000000000000000b85492afc686d5ca405e3cd4f50b05d358c75ede0000000000000000000000000000000000000000000000000000000000000001', + value: '0x0', + }, + maliciousContractInteraction: { + to: + MALICIOUS_CONTRACT_ADDRESSES[networkName] || + MALICIOUS_CONTRACT_ADDRESSES.default, + data: '0xef5cfb8c0000000000000000000000000b3e87a076ac4b0d1975f0f232444af6deb96c59', + value: '0x0', + }, + }; + + maliciousTransactionsCache[chainId] = transactions; + return transactions; +}; diff --git a/src/components/ppom/transactions.js b/src/components/ppom/transactions.js index 5f35441c..927c79d1 100644 --- a/src/components/ppom/transactions.js +++ b/src/components/ppom/transactions.js @@ -1,11 +1,7 @@ import globalContext from '../..'; import { maliciousAddress } from '../../sample-addresses'; -import { - ERC20_SAMPLE_CONTRACTS, - ERC721_SAMPLE_CONTRACTS, - MALICIOUS_CONTRACT_ADDRESSES, -} from '../../onchain-sample-contracts'; -import { isBaseNetworkId, isSepoliaNetworkId } from '../../utils'; +import { isSepoliaNetworkId } from '../../utils'; +import { getMaliciousTransactions } from './sharedConstants'; export function ppomMaliciousTransactionsAndSignatures(parentContainer) { parentContainer.insertAdjacentHTML( @@ -51,17 +47,17 @@ export function ppomMaliciousTransactionsAndSignatures(parentContainer) {
Signatures