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