From cec6dc91e4d0485db6e57654d18dfc66bbdad647 Mon Sep 17 00:00:00 2001
From: Priya Narayanaswamy <priya.narayanaswamy@consensys.net>
Date: Wed, 18 Dec 2024 19:38:22 +0100
Subject: [PATCH 1/3] chore: Split transactions into separate components

---
 src/components/transactions/eip747.js  | 100 +++
 src/components/transactions/erc1155.js | 294 +++++++++
 src/components/transactions/erc20.js   | 366 +++++++++++
 src/components/transactions/erc721.js  | 463 ++++++++++++++
 src/components/transactions/send.js    | 359 +++++++++++
 src/index.html                         | 652 +------------------
 src/index.js                           | 850 ++-----------------------
 7 files changed, 1631 insertions(+), 1453 deletions(-)
 create mode 100644 src/components/transactions/eip747.js
 create mode 100644 src/components/transactions/erc1155.js
 create mode 100644 src/components/transactions/erc20.js
 create mode 100644 src/components/transactions/erc721.js
 create mode 100644 src/components/transactions/send.js

diff --git a/src/components/transactions/eip747.js b/src/components/transactions/eip747.js
new file mode 100644
index 00000000..b8e50a42
--- /dev/null
+++ b/src/components/transactions/eip747.js
@@ -0,0 +1,100 @@
+import globalContext from '../..';
+
+export function eip747Component(parentContainer) {
+  parentContainer.insertAdjacentHTML(
+    'beforeend',
+    `      <div
+        class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch"
+      >
+        <div class="card full-width">
+          <div class="card-body">
+            <h4 class="card-title">
+              EIP 747
+            </h4>
+
+            <div class="form-group">
+              <label>ERC20 Token Address</label>
+              <input
+                class="form-control"
+                type="text"
+                placeholder="0x..."
+                id="eip747ContractAddress"
+              />
+            </div>
+
+            <div class="form-group">
+              <label>Symbol</label>
+              <input
+                class="form-control"
+                type="text"
+                placeholder="XYZ"
+                id="eip747Symbol"
+              />
+            </div>
+
+            <div class="form-group">
+              <label>Decimals</label>
+              <input
+                class="form-control"
+                type="number"
+                placeholder="18"
+                id="eip747Decimals"
+              />
+            </div>
+
+            <div class="form-group">
+              <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="eip747WatchButton"
+                disabled
+              >
+                Add Token
+              </button>
+            </div>
+
+            <p class="info-text alert alert-secondary">
+              EIP 747: <span id="eip747Status"></span>
+            </p>
+          </div>
+        </div>
+      </div>`,
+  );
+
+  // ERC 747 Section
+  const eip747ContractAddress = document.getElementById(
+    'eip747ContractAddress',
+  );
+  const eip747Symbol = document.getElementById('eip747Symbol');
+  const eip747Decimals = document.getElementById('eip747Decimals');
+  const eip747WatchButton = document.getElementById('eip747WatchButton');
+  const eip747Status = document.getElementById('eip747Status');
+
+  /**
+   *  EIP 747
+   */
+
+  eip747WatchButton.onclick = async () => {
+    eip747Status.innerHTML = 'Adding token...';
+
+    try {
+      const result = await globalContext.provider.request({
+        method: 'wallet_watchAsset',
+        params: {
+          type: 'ERC20',
+          options: {
+            address: eip747ContractAddress.value,
+            symbol: eip747Symbol.value,
+            decimals: parseInt(eip747Decimals.value, 10),
+            image: 'https://metamask.github.io/test-dapp/metamask-fox.svg',
+          },
+        },
+      });
+      eip747Status.innerHTML = 'NFT added successfully';
+      console.log(result);
+    } catch (error) {
+      eip747Status.innerHTML =
+        'There was an error adding the token. See console for details.';
+      console.error(error);
+    }
+  };
+}
diff --git a/src/components/transactions/erc1155.js b/src/components/transactions/erc1155.js
new file mode 100644
index 00000000..402f76cb
--- /dev/null
+++ b/src/components/transactions/erc1155.js
@@ -0,0 +1,294 @@
+import globalContext from '../..';
+
+export function erc1155Component(parentContainer) {
+  parentContainer.insertAdjacentHTML(
+    'beforeend',
+    `<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch">
+      <div class="card full-width">
+        <div class="card-body">
+          <h4 class="card-title">
+            ERC 1155
+          </h4>
+
+          <p class="info-text alert alert-success">
+            Token(s): <span id="erc1155TokenAddresses"></span>
+          </p>
+
+          <button
+          class="btn btn-primary btn-lg btn-block mb-3"
+          id="deployERC1155Button"
+          disabled
+        >
+          Deploy
+        </button>
+
+        <div class="form-group">
+          <label>Batch Mint Token IDs</label>
+          <input
+            class="form-control"
+            type="text"
+            placeholder="1, 2, 3"
+            id="batchMintTokenIds"
+          />
+        </div>
+
+        <div class="form-group">
+          <label>Batch Mint Token ID Amounts</label>
+          <input
+            class="form-control"
+            type="text"
+            placeholder="1, 1, 1000000000000000"
+            id="batchMintIdAmounts"
+          />
+        </div>
+
+        <div class="form-group">
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="batchMintButton"
+            disabled
+          >
+            Batch Mint
+          </button>
+        </div>
+
+        <div class="form-group">
+          <label>Batch Transfer Token IDs</label>
+          <input
+            class="form-control"
+            type="text"
+            placeholder="1, 2, 3"
+            id="batchTransferTokenIds"
+          />
+        </div>
+
+        <div class="form-group">
+          <label>Batch Transfer Token Amounts</label>
+          <input
+            class="form-control"
+            type="text"
+            placeholder="1, 1, 1"
+            id="batchTransferTokenAmounts"
+          />
+        </div>
+
+        <div class="form-group">
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="batchTransferFromButton"
+            disabled
+          >
+            Batch Transfer
+          </button>
+        </div>
+
+        <div class="form-group">
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="setApprovalForAllERC1155Button"
+            disabled
+          >
+            Set Approval For All
+          </button>
+        </div>
+
+        <div class="form-group">
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="revokeERC1155Button"
+            disabled
+          >
+            Revoke
+          </button>
+        </div>
+
+        <div class="form-group">
+          <label>Watch ERC1155 Token ID</label>
+          <input
+            class="form-control"
+            type="text"
+            value="1"
+            id="watchAssetInput"
+          />
+        </div>
+
+        <div class="form-group">
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="watchAssetButton"
+            disabled
+          >
+            Watch ERC1155 Asset
+          </button>
+        </div>
+
+        <p class="info-text alert alert-secondary">
+          ERC 1155 methods results: <span id="erc1155Status"></span>
+        </p>
+      </div>
+    </div>
+  </div>`,
+  );
+
+  const deployERC1155Button = document.getElementById('deployERC1155Button');
+  const batchMintTokenIds = document.getElementById('batchMintTokenIds');
+  const batchMintIdAmounts = document.getElementById('batchMintIdAmounts');
+  const batchMintButton = document.getElementById('batchMintButton');
+  const batchTransferTokenIds = document.getElementById(
+    'batchTransferTokenIds',
+  );
+  const batchTransferTokenAmounts = document.getElementById(
+    'batchTransferTokenAmounts',
+  );
+  const batchTransferFromButton = document.getElementById(
+    'batchTransferFromButton',
+  );
+  const setApprovalForAllERC1155Button = document.getElementById(
+    'setApprovalForAllERC1155Button',
+  );
+  const revokeERC1155Button = document.getElementById('revokeERC1155Button');
+  const watchAssetInput = document.getElementById('watchAssetInput');
+  const watchAssetButton = document.getElementById('watchAssetButton');
+  const erc1155Status = document.getElementById('erc1155Status');
+  const erc1155TokenAddresses = document.getElementById(
+    'erc1155TokenAddresses',
+  );
+
+  /**
+   * ERC1155 Token
+   */
+
+  let erc1155Contract;
+  deployERC1155Button.onclick = async () => {
+    erc1155Status.innerHTML = 'Deploying';
+
+    try {
+      erc1155Contract = await globalContext.erc1155Factory.deploy();
+      await erc1155Contract.deployTransaction.wait();
+    } catch (error) {
+      erc1155Status.innerHTML = 'Deployment Failed!';
+      throw error;
+    }
+
+    if (erc1155Contract.address === undefined) {
+      return;
+    }
+
+    console.log(
+      `Contract mined! address: ${erc1155Contract.address} transactionHash: ${erc1155Contract.deployTransaction.hash}`,
+    );
+
+    erc1155TokenAddresses.innerHTML = erc1155TokenAddresses.innerHTML
+      .concat(', ', erc1155Contract.address)
+      .split(', ')
+      .filter(Boolean)
+      .join(', ');
+
+    erc1155Status.innerHTML = 'Deployed';
+    batchTransferTokenIds.disabled = false;
+    batchTransferTokenAmounts.disabled = false;
+    batchMintButton.disabled = false;
+    batchTransferFromButton.disabled = false;
+    setApprovalForAllERC1155Button.disabled = false;
+    revokeERC1155Button.disabled = false;
+    watchAssetInput.disabled = false;
+    watchAssetButton.disabled = false;
+  };
+
+  batchMintButton.onclick = async () => {
+    erc1155Status.innerHTML = 'Batch Mint initiated';
+    const contract = erc1155Contract || globalContext.erc1155Contract;
+
+    const params = [
+      globalContext.accounts[0],
+      batchMintTokenIds.value.split(',').map(Number),
+      batchMintIdAmounts.value.split(',').map(Number),
+      '0x',
+    ];
+
+    let result;
+
+    try {
+      result = await contract.mintBatch(...params);
+    } catch (error) {
+      erc1155Status.innerHTML = 'Mint Failed!';
+      throw error;
+    }
+
+    console.log(result);
+    erc1155Status.innerHTML = 'Batch Minting completed';
+  };
+
+  batchTransferFromButton.onclick = async () => {
+    erc1155Status.innerHTML = 'Batch Transfer From initiated';
+    const contract = erc1155Contract || globalContext.erc1155Contract;
+
+    const params = [
+      globalContext.accounts[0],
+      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
+      batchTransferTokenIds.value.split(',').map(Number),
+      batchTransferTokenAmounts.value.split(',').map(Number),
+      '0x',
+    ];
+
+    let result;
+
+    try {
+      result = await contract.safeBatchTransferFrom(...params);
+    } catch (error) {
+      erc1155Status.innerHTML = 'Transaction Failed!';
+      throw error;
+    }
+    console.log(result);
+    erc1155Status.innerHTML = 'Batch Transfer From completed';
+  };
+
+  setApprovalForAllERC1155Button.onclick = async () => {
+    erc1155Status.innerHTML = 'Set Approval For All initiated';
+    const contract = erc1155Contract || globalContext.erc1155Contract;
+    let result = await contract.setApprovalForAll(
+      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
+      true,
+      {
+        from: globalContext.accounts[0],
+      },
+    );
+    result = await result.wait();
+    console.log(result);
+    erc1155Status.innerHTML = 'Set Approval For All completed';
+  };
+
+  revokeERC1155Button.onclick = async () => {
+    erc1155Status.innerHTML = 'Revoke initiated';
+    const contract = erc1155Contract || globalContext.erc1155Contract;
+    let result = await contract.setApprovalForAll(
+      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
+      false,
+      {
+        from: globalContext.accounts[0],
+      },
+    );
+    result = await result.wait();
+    console.log(result);
+    erc1155Status.innerHTML = 'Revoke completed';
+  };
+
+  watchAssetButton.onclick = async () => {
+    try {
+      const contract = erc1155Contract || globalContext.erc1155Contract;
+      const watchAssetResult = await globalContext.provider.request({
+        method: 'wallet_watchAsset',
+        params: {
+          type: 'ERC1155',
+          options: {
+            address: contract.address,
+            tokenId: watchAssetInput.value,
+          },
+        },
+      });
+      console.log(watchAssetResult);
+    } catch (error) {
+      console.error(error);
+    }
+  };
+}
diff --git a/src/components/transactions/erc20.js b/src/components/transactions/erc20.js
new file mode 100644
index 00000000..33c4ad49
--- /dev/null
+++ b/src/components/transactions/erc20.js
@@ -0,0 +1,366 @@
+import globalContext from '../..';
+
+export function erc20Component(parentContainer) {
+  parentContainer.insertAdjacentHTML(
+    'beforeend',
+    `<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch">
+      <div class="card full-width">
+        <div class="card-body">
+          <h4 class="card-title">
+            ERC 20
+          </h4>
+
+          <p class="info-text alert alert-success">
+            Token(s): <span id="erc20TokenAddresses"></span>
+          </p>
+
+          <div class="form-group">
+            <label>Token Decimals</label>
+            <input
+              class="form-control"
+              type="number"
+              id="tokenDecimals"
+              value="4"
+              max="18"
+              min="0"
+            />
+          </div>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="createToken"
+            disabled
+          >
+            Create Token
+          </button>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="watchAssets"
+            disabled
+          >
+            Add Token(s) to Wallet
+          </button>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="transferTokens"
+            disabled
+          >
+            Transfer Tokens
+          </button>
+
+          <a
+            id="transferTokensDeeplink"
+          >
+            <button
+            class="btn btn-warning btn-lg btn-block mb-3 text-dark"
+            >
+            (Mobile) Transfer Tokens with Deeplink
+            </button>
+          </a>
+
+          <hr />
+          <div class="form-group">
+            <label>Approve to Address</label>
+            <input
+              class="form-control"
+              id="approveTo"
+              value="0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4"
+            />
+          </div>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="approveTokens"
+            disabled
+          >
+            Approve Tokens
+          </button>
+          <a
+            id="approveTokensDeeplink"
+          >
+            <button
+            class="btn btn-warning btn-lg btn-block mb-3 text-dark"
+            >
+            (Mobile) Approve Tokens with Deeplink
+            </button>
+          </a>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="increaseTokenAllowance"
+            disabled
+          >
+            Increase Token Allowance
+          </button>
+
+          <hr />
+          <div class="form-group">
+            <label>Owner Address</label>
+            <input
+              class="form-control"
+              id="allowanceOwner"
+            />
+          </div>
+
+          <div class="form-group">
+            <label>Spender Address</label>
+            <input
+              class="form-control"
+              id="allowanceSpender"
+            />
+          </div>
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="getAllowance"
+            disabled
+          >
+            Get Allowance
+          </button>
+          <p class="info-text alert alert-secondary">
+            Allowance amount: <span id="allowanceAmountResult"></span>
+          </p>
+          <hr />
+          <div class="form-group">
+            <label>Transfer From</label>
+            <input
+              class="form-control"
+              id="transferFromSenderInput"
+            />
+          </div>
+
+          <div class="form-group">
+            <label>Transfer To</label>
+            <input
+              class="form-control"
+              id="transferFromRecipientInput"
+            />
+          </div>
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="transferFromTokens"
+            disabled
+          >
+            Transfer From Tokens
+          </button>
+          <hr />
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="transferTokensWithoutGas"
+            disabled
+          >
+            Transfer Tokens Without Gas
+          </button>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="approveTokensWithoutGas"
+            disabled
+          >
+            Approve Tokens Without Gas
+          </button>
+
+          <p class="info-text alert alert-secondary">
+            ERC 20 methods result: <span id="tokenMethodsResult"></span>
+          </p>
+        </div>
+      </div>
+    </div>`,
+  );
+
+  const erc20TokenAddresses = document.getElementById('erc20TokenAddresses');
+  const createToken = document.getElementById('createToken');
+  const watchAssets = document.getElementById('watchAssets');
+  const transferTokens = document.getElementById('transferTokens');
+  const transferFromTokens = document.getElementById('transferFromTokens');
+  const approveTokens = document.getElementById('approveTokens');
+  const increaseTokenAllowance = document.getElementById(
+    'increaseTokenAllowance',
+  );
+  const allowanceOwnerInput = document.getElementById('allowanceOwner');
+  const allowanceSpenderInput = document.getElementById('allowanceSpender');
+  const allowanceAmountResult = document.getElementById(
+    'allowanceAmountResult',
+  );
+  const getAllowance = document.getElementById('getAllowance');
+  const transferTokensWithoutGas = document.getElementById(
+    'transferTokensWithoutGas',
+  );
+  const approveTokensWithoutGas = document.getElementById(
+    'approveTokensWithoutGas',
+  );
+
+  const tokenMethodsResult = document.getElementById('tokenMethodsResult');
+  const decimalUnitsInput = document.getElementById('tokenDecimals');
+  const approveTokensToInput = document.getElementById('approveTo');
+  const transferFromSenderInput = document.getElementById(
+    'transferFromSenderInput',
+  );
+  const transferFromRecipientInput = document.getElementById(
+    'transferFromRecipientInput',
+  );
+  const tokenSymbol = 'TST';
+
+  /**
+   * ERC20 Token
+   */
+
+  let hstContract;
+  createToken.onclick = async () => {
+    const _initialAmount = 10;
+    const _tokenName = 'TST';
+
+    try {
+      hstContract = await globalContext.hstFactory.deploy(
+        _initialAmount,
+        _tokenName,
+        decimalUnitsInput.value,
+        tokenSymbol,
+      );
+      await hstContract.deployTransaction.wait();
+    } catch (error) {
+      erc20TokenAddresses.innerHTML = 'Creation Failed';
+      throw error;
+    }
+
+    if (hstContract.address === undefined) {
+      return;
+    }
+
+    console.log(
+      `Contract mined! address: ${hstContract.address} transactionHash: ${hstContract.deployTransaction.hash}`,
+    );
+    erc20TokenAddresses.innerHTML = erc20TokenAddresses.innerHTML
+      .concat(', ', hstContract.address)
+      .split(', ')
+      .filter(Boolean)
+      .join(', ');
+    watchAssets.disabled = false;
+    transferTokens.disabled = false;
+    transferFromTokens.disabled = false;
+    approveTokens.disabled = false;
+    increaseTokenAllowance.disabled = false;
+    allowanceOwnerInput.disabled = false;
+    allowanceSpenderInput.disabled = false;
+    allowanceAmountResult.disabled = false;
+    getAllowance.disabled = false;
+    transferTokensWithoutGas.disabled = false;
+    approveTokensWithoutGas.disabled = false;
+    approveTokensToInput.disabled = false;
+    transferFromSenderInput.disabled = false;
+    transferFromRecipientInput.disabled = false;
+  };
+
+  watchAssets.onclick = async () => {
+    const contractAddresses = erc20TokenAddresses.innerHTML.split(', ');
+
+    const promises = contractAddresses.map((erc20Address) => {
+      return globalContext.provider.request({
+        method: 'wallet_watchAsset',
+        params: {
+          type: 'ERC20',
+          options: {
+            address: erc20Address,
+            symbol: tokenSymbol,
+            decimals: decimalUnitsInput.value,
+            image: 'https://metamask.github.io/test-dapp/metamask-fox.svg',
+          },
+        },
+      });
+    });
+
+    Promise.all(promises).then((result) => {
+      console.log('result', result);
+    });
+  };
+
+  transferTokens.onclick = async () => {
+    const contract = hstContract || globalContext.hstContract;
+    const result = await contract.transfer(
+      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
+      decimalUnitsInput.value === '0'
+        ? 1
+        : `${1.5 * 10 ** decimalUnitsInput.value}`,
+      { from: globalContext.accounts[0] },
+    );
+    console.log('result', result);
+  };
+
+  approveTokens.onclick = async () => {
+    const contract = hstContract || globalContext.hstContract;
+    const result = await contract.approve(
+      approveTokensToInput.value,
+      `${7 * 10 ** decimalUnitsInput.value}`,
+      { from: globalContext.accounts[0] },
+    );
+    console.log('result', result);
+  };
+
+  increaseTokenAllowance.onclick = async () => {
+    const contract = hstContract || globalContext.hstContract;
+    const result = await contract.increaseAllowance(
+      approveTokensToInput.value,
+      `${1 * 10 ** decimalUnitsInput.value}`,
+      { from: globalContext.accounts[0] },
+    );
+    console.log('result', result);
+  };
+
+  getAllowance.onclick = async () => {
+    const contract = hstContract || globalContext.hstContract;
+    const result = await contract.allowance(
+      allowanceOwnerInput.value,
+      allowanceSpenderInput.value,
+      { from: globalContext.accounts[0] },
+    );
+    const allowance = result.toNumber() / 10 ** decimalUnitsInput.value;
+    allowanceAmountResult.innerHTML = allowance.toFixed(
+      decimalUnitsInput.value,
+    );
+  };
+
+  transferFromTokens.onclick = async () => {
+    try {
+      const contract = hstContract || globalContext.hstContract;
+      const result = await contract.transferFrom(
+        transferFromSenderInput.value,
+        transferFromRecipientInput.value,
+        decimalUnitsInput.value === '0'
+          ? 1
+          : `${1.5 * 10 ** decimalUnitsInput.value}`,
+        { from: globalContext.accounts[0] },
+      );
+      console.log('result', result);
+      tokenMethodsResult.innerHTML = result;
+    } catch (error) {
+      tokenMethodsResult.innerHTML = error.message;
+    }
+  };
+
+  transferTokensWithoutGas.onclick = async () => {
+    const contract = hstContract || globalContext.hstContract;
+    const result = await contract.transfer(
+      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
+      decimalUnitsInput.value === '0'
+        ? 1
+        : `${1.5 * 10 ** decimalUnitsInput.value}`,
+      {
+        gasPrice: '20000000000',
+      },
+    );
+    console.log('result', result);
+  };
+
+  approveTokensWithoutGas.onclick = async () => {
+    const contract = hstContract || globalContext.hstContract;
+    const result = await contract.approve(
+      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
+      `${7 * 10 ** decimalUnitsInput.value}`,
+      {
+        gasPrice: '20000000000',
+      },
+    );
+    console.log('result', result);
+  };
+}
diff --git a/src/components/transactions/erc721.js b/src/components/transactions/erc721.js
new file mode 100644
index 00000000..164a28e1
--- /dev/null
+++ b/src/components/transactions/erc721.js
@@ -0,0 +1,463 @@
+import { recoverTypedSignature } from '@metamask/eth-sig-util';
+import { toChecksumAddress } from 'ethereumjs-util';
+import { splitSig } from '../../signatures/utils';
+import globalContext from '../..';
+
+export function erc721Component(parentContainer) {
+  parentContainer.insertAdjacentHTML(
+    'beforeend',
+    `<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch">
+      <div class="card full-width">
+        <div class="card-body">
+          <h4 class="card-title">
+            ERC 721
+          </h4>
+
+          <p class="info-text alert alert-success">
+            Token(s): <span id="erc721TokenAddresses"></span>
+          </p>
+
+          <button
+            class="btn btn-primary btn-lg btn-block mb-3"
+            id="deployNFTsButton"
+            disabled
+          >
+            Deploy
+          </button>
+
+          <div class="form-group">
+            <label>Amount</label>
+            <input
+              class="form-control"
+              type="number"
+              id="mintAmountInput"
+              value="1"
+            />
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="mintButton"
+              disabled
+            >
+              Mint
+            </button>
+          </div>
+
+          <div class="form-group">
+            <label>Watch NFT</label>
+            <input
+              class="form-control"
+              type="number"
+              id="watchNFTInput"
+              value="1"
+            />
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="watchNFTButton"
+              disabled
+            >
+              Watch NFT
+            </button>
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="watchNFTsButton"
+              disabled
+            >
+              Watch all NFTs
+            </button>
+          </div>
+
+          <div class="form-group" id="watchNFTButtons">
+          </div>
+
+          <div class="form-group">
+            <label>Approve Token</label>
+            <input
+              class="form-control"
+              type="number"
+              id="approveTokenInput"
+              value="1"
+            />
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="approveButton"
+              disabled
+            >
+              Approve
+            </button>
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="setApprovalForAllButton"
+              disabled
+            >
+              Set Approval For All
+            </button>
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="revokeButton"
+              disabled
+            >
+              Revoke
+            </button>
+          </div>
+
+          <div class="form-group">
+            <label>Transfer Token</label>
+            <input
+              class="form-control"
+              type="number"
+              id="transferTokenInput"
+              value="1"
+            />
+          </div>
+
+          <div class="form-group">
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="transferFromButton"
+              disabled
+            >
+              Transfer From
+            </button>
+          </div>
+
+          <div class="form-group">
+            <label>NFT Permit</label>
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="sign721Permit"
+              disabled
+            >
+              Sign
+            </button>
+
+            <p class="info-text alert alert-warning">
+              Result:
+              <span id="sign721PermitResult"></span>
+              <p class="info-text alert alert-warning" id="sign721PermitResultR">r: </p>
+              <p class="info-text alert alert-warning" id="sign721PermitResultS">s: </p>
+              <p class="info-text alert alert-warning" id="sign721PermitResultV">v: </p>
+            </p>
+
+            <button
+              class="btn btn-primary btn-lg btn-block mb-3"
+              id="sign721PermitVerify"
+              disabled
+            >
+              Verify
+            </button>
+
+            <p class="info-text alert alert-warning">
+              Recovery result:
+              <span id="sign721PermitVerifyResult"></span>
+            </p>
+          </div>
+
+          <p class="info-text alert alert-secondary">
+            ERC 721 methods result: <span id="nftsStatus"></span>
+          </p>
+        </div>
+      </div>
+    </div>`,
+  );
+
+  // NFTs Section
+  const deployNFTsButton = document.getElementById('deployNFTsButton');
+  const mintButton = document.getElementById('mintButton');
+  const watchNFTsButton = document.getElementById('watchNFTsButton');
+  const watchNFTButtons = document.getElementById('watchNFTButtons');
+
+  const mintAmountInput = document.getElementById('mintAmountInput');
+  const approveTokenInput = document.getElementById('approveTokenInput');
+  const approveButton = document.getElementById('approveButton');
+  const watchNFTInput = document.getElementById('watchNFTInput');
+  const watchNFTButton = document.getElementById('watchNFTButton');
+  const setApprovalForAllButton = document.getElementById(
+    'setApprovalForAllButton',
+  );
+  const revokeButton = document.getElementById('revokeButton');
+  const transferTokenInput = document.getElementById('transferTokenInput');
+  const transferFromButton = document.getElementById('transferFromButton');
+  const nftsStatus = document.getElementById('nftsStatus');
+  const erc721TokenAddresses = document.getElementById('erc721TokenAddresses');
+  // 721 Permit
+  const sign721Permit = document.getElementById('sign721Permit');
+  const sign721PermitResult = document.getElementById('sign721PermitResult');
+  const sign721PermitResultR = document.getElementById('sign721PermitResultR');
+  const sign721PermitResultS = document.getElementById('sign721PermitResultS');
+  const sign721PermitResultV = document.getElementById('sign721PermitResultV');
+  const sign721PermitVerify = document.getElementById('sign721PermitVerify');
+  const sign721PermitVerifyResult = document.getElementById(
+    'sign721PermitVerifyResult',
+  );
+
+  /**
+   * ERC721 Token
+   */
+
+  let nftsContract;
+
+  deployNFTsButton.onclick = async () => {
+    nftsStatus.innerHTML = 'Deploying';
+
+    try {
+      nftsContract = await globalContext.nftsFactory.deploy();
+      await nftsContract.deployTransaction.wait();
+    } catch (error) {
+      nftsStatus.innerHTML = 'Deployment Failed';
+      throw error;
+    }
+
+    if (nftsContract.address === undefined) {
+      return;
+    }
+
+    console.log(
+      `Contract mined! address: ${nftsContract.address} transactionHash: ${nftsContract.deployTransaction.hash}`,
+    );
+
+    erc721TokenAddresses.innerHTML = erc721TokenAddresses.innerHTML
+      .concat(', ', nftsContract.address)
+      .split(', ')
+      .filter(Boolean)
+      .join(', ');
+
+    nftsStatus.innerHTML = 'Deployed';
+    mintButton.disabled = false;
+    sign721Permit.disabled = false;
+    mintAmountInput.disabled = false;
+  };
+
+  watchNFTsButton.onclick = async () => {
+    const contract = nftsContract || globalContext.nftsContract;
+    const currentTokenId = await contract.currentTokenId();
+    const nftsContractAddress = contract.address;
+    let watchNftsResult;
+    try {
+      watchNftsResult = await globalContext.provider.sendAsync(
+        Array.from({ length: currentTokenId }, (_, i) => i + 1).map(
+          (tokenId) => {
+            return {
+              method: 'wallet_watchAsset',
+              params: {
+                type: 'ERC721',
+                options: {
+                  address: nftsContractAddress,
+                  tokenId: tokenId.toString(),
+                },
+              },
+            };
+          },
+        ),
+      );
+    } catch (error) {
+      console.error(error);
+    }
+    console.log(watchNftsResult);
+  };
+
+  mintButton.onclick = async () => {
+    const contract = nftsContract || globalContext.nftsContract;
+    nftsStatus.innerHTML = 'Mint initiated';
+    let result = await contract.mintNFTs(mintAmountInput.value, {
+      from: globalContext.accounts[0],
+    });
+    result = await result.wait();
+    console.log(result);
+    nftsStatus.innerHTML = 'Mint completed';
+    approveTokenInput.disabled = false;
+    approveButton.disabled = false;
+    watchNFTInput.disabled = false;
+    watchNFTButton.disabled = false;
+    setApprovalForAllButton.disabled = false;
+    revokeButton.disabled = false;
+    transferTokenInput.disabled = false;
+    transferFromButton.disabled = false;
+    watchNFTsButton.disabled = false;
+    watchNFTButtons.innerHTML = '';
+  };
+
+  sign721Permit.onclick = async () => {
+    const from = globalContext.accounts[0];
+    const msgParams = await getNFTMsgParams();
+    console.log(msgParams);
+
+    let sign;
+    let r;
+    let s;
+    let v;
+
+    try {
+      sign = await globalContext.provider.request({
+        method: 'eth_signTypedData_v4',
+        params: [from, JSON.stringify(msgParams)],
+      });
+      const { _r, _s, _v } = splitSig(sign);
+      r = `0x${_r.toString('hex')}`;
+      s = `0x${_s.toString('hex')}`;
+      v = _v.toString();
+
+      sign721PermitResult.innerHTML = sign;
+      sign721PermitResultR.innerHTML = `r: ${r}`;
+      sign721PermitResultS.innerHTML = `s: ${s}`;
+      sign721PermitResultV.innerHTML = `v: ${v}`;
+      sign721PermitVerify.disabled = false;
+    } catch (err) {
+      console.error(err);
+      sign721PermitResult.innerHTML = `Error: ${err.message}`;
+    }
+  };
+
+  /**
+   *  Sign Permit Verification
+   */
+  sign721PermitVerify.onclick = async () => {
+    const from = globalContext.accounts[0];
+    const msgParams = await getNFTMsgParams();
+
+    try {
+      const sign = sign721PermitResult.innerHTML;
+      const recoveredAddr = recoverTypedSignature({
+        data: msgParams,
+        signature: sign,
+        version: 'V4',
+      });
+      if (toChecksumAddress(recoveredAddr) === toChecksumAddress(from)) {
+        console.log(`Successfully verified signer as ${recoveredAddr}`);
+        sign721PermitVerifyResult.innerHTML = recoveredAddr;
+      } else {
+        console.log(
+          `Failed to verify signer when comparing ${recoveredAddr} to ${from}`,
+        );
+      }
+    } catch (err) {
+      console.error(err);
+      sign721PermitVerifyResult.innerHTML = `Error: ${err.message}`;
+    }
+  };
+
+  watchNFTButton.onclick = async () => {
+    const contract = nftsContract || globalContext.nftsContract;
+    let watchNftsResult;
+    try {
+      watchNftsResult = await globalContext.provider.request({
+        method: 'wallet_watchAsset',
+        params: {
+          type: 'ERC721',
+          options: {
+            address: contract.address,
+            tokenId: watchNFTInput.value,
+          },
+        },
+      });
+    } catch (error) {
+      console.error(error);
+    }
+    console.log(watchNftsResult);
+  };
+
+  approveButton.onclick = async () => {
+    const contract = nftsContract || globalContext.nftsContract;
+    nftsStatus.innerHTML = 'Approve initiated';
+    let result = await contract.approve(
+      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
+      approveTokenInput.value,
+      {
+        from: globalContext.accounts[0],
+      },
+    );
+    result = await result.wait();
+    console.log(result);
+    nftsStatus.innerHTML = 'Approve completed';
+  };
+
+  setApprovalForAllButton.onclick = async () => {
+    nftsStatus.innerHTML = 'Set Approval For All initiated';
+    const contract = nftsContract || globalContext.nftsContract;
+    let result = await contract.setApprovalForAll(
+      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
+      true,
+      {
+        from: globalContext.accounts[0],
+      },
+    );
+    result = await result.wait();
+    console.log(result);
+    nftsStatus.innerHTML = 'Set Approval For All completed';
+  };
+
+  revokeButton.onclick = async () => {
+    nftsStatus.innerHTML = 'Revoke initiated';
+    const contract = nftsContract || globalContext.nftsContract;
+    let result = await contract.setApprovalForAll(
+      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
+      false,
+      {
+        from: globalContext.accounts[0],
+      },
+    );
+    result = await result.wait();
+    console.log(result);
+    nftsStatus.innerHTML = 'Revoke completed';
+  };
+
+  transferFromButton.onclick = async () => {
+    nftsStatus.innerHTML = 'Transfer From initiated';
+    const contract = nftsContract || globalContext.nftsContract;
+    let result = await contract.transferFrom(
+      globalContext.accounts[0],
+      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
+      transferTokenInput.value,
+      {
+        from: globalContext.accounts[0],
+      },
+    );
+    result = await result.wait();
+    console.log(result);
+    nftsStatus.innerHTML = 'Transfer From completed';
+  };
+
+  async function getNFTMsgParams() {
+    const contract = nftsContract || globalContext.nftsContract;
+    return {
+      domain: {
+        name: 'My NFT',
+        version: '1',
+        chainId: globalContext.chainIdInt,
+        verifyingContract: contract.address,
+      },
+      types: {
+        Permit: [
+          { name: 'spender', type: 'address' },
+          { name: 'tokenId', type: 'uint256' },
+          { name: 'nonce', type: 'uint256' },
+          { name: 'deadline', type: 'uint256' },
+        ],
+      },
+      primaryType: 'Permit',
+      message: {
+        spender: '0x0521797E19b8E274E4ED3bFe5254FAf6fac96F08',
+        tokenId: '3606393',
+        nonce: '0',
+        deadline: '1734995006',
+      },
+    };
+  }
+}
diff --git a/src/components/transactions/send.js b/src/components/transactions/send.js
new file mode 100644
index 00000000..9a35c755
--- /dev/null
+++ b/src/components/transactions/send.js
@@ -0,0 +1,359 @@
+import globalContext from '../..';
+
+export function sendComponent(parentContainer) {
+  parentContainer.insertAdjacentHTML(
+    'beforeend',
+    `<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch">
+        <div class="card full-width">
+            <div class="card-body">
+            <h4 class="card-title">
+                Send Eth
+            </h4>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="sendButton"
+                disabled
+            >
+                Send
+            </button>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="sendEIP1559Button"
+                disabled
+                hidden
+            >
+                Send EIP 1559 Transaction
+            </button>
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="sendEIP1559WithoutGasButton"
+                disabled
+                hidden
+            >
+                Send EIP 1559 Without Gas
+            </button>
+            <a
+                id="sendDeeplinkButton"
+            >
+                <button
+                class="btn btn-warning btn-lg btn-block mb-3 text-dark"
+                >
+                (Mobile) Send with Deeplink
+                </button>
+            </a>
+            <hr />
+            <h4 class="card-title">
+                Piggy bank contract
+            </h4>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="deployButton"
+                disabled
+            >
+                Deploy Contract
+            </button>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="depositButton"
+                disabled
+            >
+                Deposit
+            </button>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="withdrawButton"
+                disabled
+            >
+                Withdraw
+            </button>
+
+            <p class="info-text alert alert-secondary">
+                Contract Status: <span id="contractStatus">Not clicked</span>
+            </p>
+            <hr />
+            <h4 class="card-title">
+                Failing contract
+            </h4>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="deployFailingButton"
+                disabled
+
+            >
+                Deploy Failing Contract
+            </button>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="sendFailingButton"
+                disabled
+            >
+                Send Failing Transaction
+            </button>
+
+            <p class="info-text alert alert-secondary">
+                Failing Contract Status: <span id="failingContractStatus">Not clicked</span>
+            </p>
+            <hr />
+            <h4 class="card-title">
+                Multisig contract
+            </h4>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="deployMultisigButton"
+                disabled
+
+            >
+                Deploy Multisig Contract
+            </button>
+
+            <button
+                class="btn btn-primary btn-lg btn-block mb-3"
+                id="sendMultisigButton"
+                disabled
+            >
+                Send ETH to Multisig Address
+            </button>
+
+            <p class="info-text alert alert-secondary">
+                Multisig Contract Status: <span id="multisigContractStatus">Not clicked</span>
+            </p>
+            </div>
+        </div>
+    </div>`,
+  );
+
+  const sendButton = document.getElementById('sendButton');
+  const sendEIP1559Button = document.getElementById('sendEIP1559Button');
+  const sendEIP1559WithoutGasButton = document.getElementById(
+    'sendEIP1559WithoutGasButton',
+  );
+  // const sendDeeplinkButton = document.getElementById('sendDeeplinkButton');
+  const deployButton = document.getElementById('deployButton');
+  const depositButton = document.getElementById('depositButton');
+  const withdrawButton = document.getElementById('withdrawButton');
+  const contractStatus = document.getElementById('contractStatus');
+  const deployFailingButton = document.getElementById('deployFailingButton');
+  const sendFailingButton = document.getElementById('sendFailingButton');
+  const failingContractStatus = document.getElementById(
+    'failingContractStatus',
+  );
+  const deployMultisigButton = document.getElementById('deployMultisigButton');
+  const sendMultisigButton = document.getElementById('sendMultisigButton');
+  const multisigContractStatus = document.getElementById(
+    'multisigContractStatus',
+  );
+
+  /**
+   * Sending ETH
+   */
+
+  sendButton.onclick = async () => {
+    const result = await globalContext.provider.request({
+      method: 'eth_sendTransaction',
+      params: [
+        {
+          from: globalContext.accounts[0],
+          to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb',
+          value: '0x0',
+          gasLimit: '0x5208',
+          gasPrice: '0x2540be400',
+          type: '0x0',
+        },
+      ],
+    });
+    console.log(result);
+  };
+
+  sendEIP1559Button.onclick = async () => {
+    const result = await globalContext.provider.request({
+      method: 'eth_sendTransaction',
+      params: [
+        {
+          from: globalContext.accounts[0],
+          to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb',
+          value: '0x0',
+          gasLimit: '0x5028',
+          maxFeePerGas: '0x2540be400',
+          maxPriorityFeePerGas: '0x3b9aca00',
+        },
+      ],
+    });
+    console.log(result);
+  };
+
+  sendEIP1559WithoutGasButton.onclick = async () => {
+    const result = await globalContext.provider.request({
+      method: 'eth_sendTransaction',
+      params: [
+        {
+          from: globalContext.accounts[0],
+          to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb',
+          value: '0x0',
+        },
+      ],
+    });
+    console.log(result);
+  };
+
+  /**
+   * Piggy bank
+   */
+  let piggybankContract;
+
+  deployButton.onclick = async () => {
+    contractStatus.innerHTML = 'Deploying';
+    try {
+      piggybankContract = await globalContext.piggybankFactory.deploy();
+      await piggybankContract.deployTransaction.wait();
+    } catch (error) {
+      contractStatus.innerHTML = 'Deployment Failed';
+      throw error;
+    }
+
+    console.log(piggybankContract.address);
+    if (piggybankContract.address === undefined) {
+      return;
+    }
+
+    console.log(
+      `Contract mined! address: ${piggybankContract.address} transactionHash: ${piggybankContract.deployTransaction.hash}`,
+    );
+    contractStatus.innerHTML = 'Deployed';
+    depositButton.disabled = false;
+    withdrawButton.disabled = false;
+  };
+
+  depositButton.onclick = async () => {
+    contractStatus.innerHTML = 'Deposit initiated';
+    const contract = piggybankContract || globalContext.piggybankContract;
+    const result = await contract.deposit({
+      from: globalContext.accounts[0],
+      value: '0x3782dace9d900000',
+    });
+    console.log(result);
+    const receipt = await result.wait();
+    console.log(receipt);
+    contractStatus.innerHTML = 'Deposit completed';
+  };
+
+  withdrawButton.onclick = async () => {
+    const contract = piggybankContract || globalContext.piggybankContract;
+    const result = await contract.withdraw('0xde0b6b3a7640000', {
+      from: globalContext.accounts[0],
+    });
+    console.log(result);
+    const receipt = await result.wait();
+    console.log(receipt);
+    contractStatus.innerHTML = 'Withdrawn';
+  };
+
+  /**
+   * Failing
+   */
+
+  let failingContract;
+  deployFailingButton.onclick = async () => {
+    failingContractStatus.innerHTML = 'Deploying';
+
+    try {
+      failingContract = await globalContext.failingContractFactory.deploy();
+      await failingContract.deployTransaction.wait();
+    } catch (error) {
+      failingContractStatus.innerHTML = 'Deployment Failed';
+      throw error;
+    }
+
+    if (failingContract.address === undefined) {
+      return;
+    }
+
+    console.log(
+      `Contract mined! address: ${failingContract.address} transactionHash: ${failingContract.deployTransaction.hash}`,
+    );
+    failingContractStatus.innerHTML = 'Deployed';
+    sendFailingButton.disabled = false;
+  };
+
+  sendFailingButton.onclick = async () => {
+    try {
+      const contract = failingContract || globalContext.failingContract;
+      const result = await globalContext.provider.request({
+        method: 'eth_sendTransaction',
+        params: [
+          {
+            from: globalContext.accounts[0],
+            to: contract.address,
+            value: '0x0',
+            gasLimit: '0x5028',
+            maxFeePerGas: '0x2540be400',
+            maxPriorityFeePerGas: '0x3b9aca00',
+          },
+        ],
+      });
+      failingContractStatus.innerHTML =
+        'Failed transaction process completed as expected.';
+      console.log('send failing contract result', result);
+    } catch (error) {
+      console.log('error', error);
+      throw error;
+    }
+  };
+
+  /**
+   * Multisig
+   */
+
+  let multisigContract;
+  deployMultisigButton.onclick = async () => {
+    multisigContractStatus.innerHTML = 'Deploying';
+    try {
+      multisigContract = await globalContext.multisigFactory.deploy();
+      await multisigContract.deployTransaction.wait();
+    } catch (error) {
+      multisigContractStatus.innerHTML = 'Deployment Failed';
+      throw error;
+    }
+
+    if (multisigContract.address === undefined) {
+      return;
+    }
+
+    console.log(
+      `Contract mined! address: ${multisigContract.address} transactionHash: ${multisigContract.deployTransaction.hash}`,
+    );
+    multisigContractStatus.innerHTML = 'Deployed';
+    sendMultisigButton.disabled = false;
+  };
+
+  sendMultisigButton.onclick = async () => {
+    try {
+      const contract = multisigContract || globalContext.multisigContract;
+      const result = await globalContext.provider.request({
+        method: 'eth_sendTransaction',
+        params: [
+          {
+            from: globalContext.accounts[0],
+            to: contract.address,
+            value: '0x16345785D8A0', // 24414062500000
+            gasLimit: '0x5028',
+            maxFeePerGas: '0x2540be400',
+            maxPriorityFeePerGas: '0x3b9aca00',
+          },
+        ],
+      });
+      multisigContractStatus.innerHTML = 'Transaction completed as expected.';
+      console.log('send multisig contract result', result);
+    } catch (error) {
+      console.log('error', error);
+      throw error;
+    }
+  };
+}
diff --git a/src/index.html b/src/index.html
index f0f845a0..7b2155dd 100644
--- a/src/index.html
+++ b/src/index.html
@@ -195,657 +195,7 @@ <h4 class="card-title">
         </div>
       </section>
 
-      <section>
-        <div class="row">
-          <div
-            class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch"
-          >
-            <div class="card full-width">
-              <div class="card-body">
-                <h4 class="card-title">
-                  Send Eth
-                </h4>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="sendButton"
-                  disabled
-                >
-                  Send
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="sendEIP1559Button"
-                  disabled
-                  hidden
-                >
-                  Send EIP 1559 Transaction
-                </button>
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="sendEIP1559WithoutGasButton"
-                  disabled
-                  hidden
-                >
-                  Send EIP 1559 Without Gas
-                </button>
-                <a
-                  id="sendDeeplinkButton"
-                >
-                  <button
-                    class="btn btn-warning btn-lg btn-block mb-3 text-dark"
-                  >
-                  (Mobile) Send with Deeplink
-                  </button>
-                </a>
-                <hr />
-                <h4 class="card-title">
-                  Piggy bank contract
-                </h4>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="deployButton"
-                  disabled
-                >
-                  Deploy Contract
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="depositButton"
-                  disabled
-                >
-                  Deposit
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="withdrawButton"
-                  disabled
-                >
-                  Withdraw
-                </button>
-
-                <p class="info-text alert alert-secondary">
-                  Contract Status: <span id="contractStatus">Not clicked</span>
-                </p>
-                <hr />
-                <h4 class="card-title">
-                  Failing contract
-                </h4>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="deployFailingButton"
-                  disabled
-
-                >
-                  Deploy Failing Contract
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="sendFailingButton"
-                  disabled
-                >
-                  Send Failing Transaction
-                </button>
-
-                <p class="info-text alert alert-secondary">
-                  Failing Contract Status: <span id="failingContractStatus">Not clicked</span>
-                </p>
-                <hr />
-                <h4 class="card-title">
-                  Multisig contract
-                </h4>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="deployMultisigButton"
-                  disabled
-
-                >
-                  Deploy Multisig Contract
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="sendMultisigButton"
-                  disabled
-                >
-                  Send ETH to Multisig Address
-                </button>
-
-                <p class="info-text alert alert-secondary">
-                  Multisig Contract Status: <span id="multisigContractStatus">Not clicked</span>
-                </p>
-              </div>
-            </div>
-          </div>
-
-          <div
-            class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch"
-          >
-            <div class="card full-width">
-              <div class="card-body">
-                <h4 class="card-title">
-                  ERC 20
-                </h4>
-
-                <p class="info-text alert alert-success">
-                  Token(s): <span id="erc20TokenAddresses"></span>
-                </p>
-
-                <div class="form-group">
-                  <label>Token Decimals</label>
-                  <input
-                    class="form-control"
-                    type="number"
-                    id="tokenDecimals"
-                    value="4"
-                    max="18"
-                    min="0"
-                  />
-                </div>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="createToken"
-                  disabled
-                >
-                  Create Token
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="watchAssets"
-                  disabled
-                >
-                  Add Token(s) to Wallet
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="transferTokens"
-                  disabled
-                >
-                  Transfer Tokens
-                </button>
-
-                <a
-                  id="transferTokensDeeplink"
-                >
-                  <button
-                  class="btn btn-warning btn-lg btn-block mb-3 text-dark"
-                  >
-                  (Mobile) Transfer Tokens with Deeplink
-                  </button>
-                </a>
-
-                <hr />
-                <div class="form-group">
-                  <label>Approve to Address</label>
-                  <input
-                    class="form-control"
-                    id="approveTo"
-                    value="0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4"
-                  />
-                </div>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="approveTokens"
-                  disabled
-                >
-                  Approve Tokens
-                </button>
-                <a
-                  id="approveTokensDeeplink"
-                >
-                  <button
-                  class="btn btn-warning btn-lg btn-block mb-3 text-dark"
-                  >
-                  (Mobile) Approve Tokens with Deeplink
-                  </button>
-                </a>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="increaseTokenAllowance"
-                  disabled
-                >
-                  Increase Token Allowance
-                </button>
-
-                <hr />
-                <div class="form-group">
-                  <label>Owner Address</label>
-                  <input
-                    class="form-control"
-                    id="allowanceOwner"
-                  />
-                </div>
-
-                <div class="form-group">
-                  <label>Spender Address</label>
-                  <input
-                    class="form-control"
-                    id="allowanceSpender"
-                  />
-                </div>
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="getAllowance"
-                  disabled
-                >
-                  Get Allowance
-                </button>
-                <p class="info-text alert alert-secondary">
-                  Allowance amount: <span id="allowanceAmountResult"></span>
-                </p>
-                <hr />
-                <div class="form-group">
-                  <label>Transfer From</label>
-                  <input
-                    class="form-control"
-                    id="transferFromSenderInput"
-                  />
-                </div>
-
-                <div class="form-group">
-                  <label>Transfer To</label>
-                  <input
-                    class="form-control"
-                    id="transferFromRecipientInput"
-                  />
-                </div>
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="transferFromTokens"
-                  disabled
-                >
-                  Transfer From Tokens
-                </button>
-                <hr />
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="transferTokensWithoutGas"
-                  disabled
-                >
-                  Transfer Tokens Without Gas
-                </button>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="approveTokensWithoutGas"
-                  disabled
-                >
-                  Approve Tokens Without Gas
-                </button>
-
-                <p class="info-text alert alert-secondary">
-                  ERC 20 methods result: <span id="tokenMethodsResult"></span>
-                </p>
-              </div>
-            </div>
-          </div>
-          <div
-            class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch"
-          >
-            <div class="card full-width">
-              <div class="card-body">
-                <h4 class="card-title">
-                  ERC 721
-                </h4>
-
-                <p class="info-text alert alert-success">
-                  Token(s): <span id="erc721TokenAddresses"></span>
-                </p>
-
-                <button
-                  class="btn btn-primary btn-lg btn-block mb-3"
-                  id="deployNFTsButton"
-                  disabled
-                >
-                  Deploy
-                </button>
-
-                <div class="form-group">
-                  <label>Amount</label>
-                  <input
-                    class="form-control"
-                    type="number"
-                    id="mintAmountInput"
-                    value="1"
-                  />
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="mintButton"
-                    disabled
-                  >
-                    Mint
-                  </button>
-                </div>
-
-                <div class="form-group">
-                  <label>Watch NFT</label>
-                  <input
-                    class="form-control"
-                    type="number"
-                    id="watchNFTInput"
-                    value="1"
-                  />
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="watchNFTButton"
-                    disabled
-                  >
-                    Watch NFT
-                  </button>
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="watchNFTsButton"
-                    disabled
-                  >
-                    Watch all NFTs
-                  </button>
-                </div>
-
-                <div class="form-group" id="watchNFTButtons">
-                </div>
-
-                <div class="form-group">
-                  <label>Approve Token</label>
-                  <input
-                    class="form-control"
-                    type="number"
-                    id="approveTokenInput"
-                    value="1"
-                  />
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="approveButton"
-                    disabled
-                  >
-                    Approve
-                  </button>
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="setApprovalForAllButton"
-                    disabled
-                  >
-                    Set Approval For All
-                  </button>
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="revokeButton"
-                    disabled
-                  >
-                    Revoke
-                  </button>
-                </div>
-
-                <div class="form-group">
-                  <label>Transfer Token</label>
-                  <input
-                    class="form-control"
-                    type="number"
-                    id="transferTokenInput"
-                    value="1"
-                  />
-                </div>
-
-                <div class="form-group">
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="transferFromButton"
-                    disabled
-                  >
-                    Transfer From
-                  </button>
-                </div>
-
-                <div class="form-group">
-                  <label>NFT Permit</label>
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="sign721Permit"
-                    disabled
-                  >
-                    Sign
-                  </button>
-
-                  <p class="info-text alert alert-warning">
-                    Result:
-                    <span id="sign721PermitResult"></span>
-                    <p class="info-text alert alert-warning" id="sign721PermitResultR">r: </p>
-                    <p class="info-text alert alert-warning" id="sign721PermitResultS">s: </p>
-                    <p class="info-text alert alert-warning" id="sign721PermitResultV">v: </p>
-                  </p>
-
-                  <button
-                    class="btn btn-primary btn-lg btn-block mb-3"
-                    id="sign721PermitVerify"
-                    disabled
-                  >
-                    Verify
-                  </button>
-
-                  <p class="info-text alert alert-warning">
-                    Recovery result:
-                    <span id="sign721PermitVerifyResult"></span>
-                  </p>
-                </div>
-
-                <p class="info-text alert alert-secondary">
-                  ERC 721 methods result: <span id="nftsStatus"></span>
-                </p>
-              </div>
-            </div>
-          </div>
-          <div
-          class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch"
-        >
-          <div class="card full-width">
-            <div class="card-body">
-              <h4 class="card-title">
-                ERC 1155
-              </h4>
-
-              <p class="info-text alert alert-success">
-                Token(s): <span id="erc1155TokenAddresses"></span>
-              </p>
-
-              <button
-              class="btn btn-primary btn-lg btn-block mb-3"
-              id="deployERC1155Button"
-              disabled
-            >
-              Deploy
-            </button>
-
-            <div class="form-group">
-              <label>Batch Mint Token IDs</label>
-              <input
-                class="form-control"
-                type="text"
-                placeholder="1, 2, 3"
-                id="batchMintTokenIds"
-              />
-            </div>
-
-            <div class="form-group">
-              <label>Batch Mint Token ID Amounts</label>
-              <input
-                class="form-control"
-                type="text"
-                placeholder="1, 1, 1000000000000000"
-                id="batchMintIdAmounts"
-              />
-            </div>
-
-            <div class="form-group">
-              <button
-                class="btn btn-primary btn-lg btn-block mb-3"
-                id="batchMintButton"
-                disabled
-              >
-                Batch Mint
-              </button>
-            </div>
-
-            <div class="form-group">
-              <label>Batch Transfer Token IDs</label>
-              <input
-                class="form-control"
-                type="text"
-                placeholder="1, 2, 3"
-                id="batchTransferTokenIds"
-              />
-            </div>
-
-            <div class="form-group">
-              <label>Batch Transfer Token Amounts</label>
-              <input
-                class="form-control"
-                type="text"
-                placeholder="1, 1, 1"
-                id="batchTransferTokenAmounts"
-              />
-            </div>
-
-            <div class="form-group">
-              <button
-                class="btn btn-primary btn-lg btn-block mb-3"
-                id="batchTransferFromButton"
-                disabled
-              >
-                Batch Transfer
-              </button>
-            </div>
-
-            <div class="form-group">
-              <button
-                class="btn btn-primary btn-lg btn-block mb-3"
-                id="setApprovalForAllERC1155Button"
-                disabled
-              >
-                Set Approval For All
-              </button>
-            </div>
-
-            <div class="form-group">
-              <button
-                class="btn btn-primary btn-lg btn-block mb-3"
-                id="revokeERC1155Button"
-                disabled
-              >
-                Revoke
-              </button>
-            </div>
-
-            <div class="form-group">
-              <label>Watch ERC1155 Token ID</label>
-              <input
-                class="form-control"
-                type="text"
-                value="1"
-                id="watchAssetInput"
-              />
-            </div>
-
-            <div class="form-group">
-              <button
-                class="btn btn-primary btn-lg btn-block mb-3"
-                id="watchAssetButton"
-                disabled
-              >
-                Watch ERC1155 Asset
-              </button>
-            </div>
-
-            <p class="info-text alert alert-secondary">
-              ERC 1155 methods results: <span id="erc1155Status"></span>
-            </p>
-          </div>
-        </div>
-      </div>
-      <div
-        class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12 d-flex align-items-stretch"
-      >
-        <div class="card full-width">
-          <div class="card-body">
-            <h4 class="card-title">
-              EIP 747
-            </h4>
-
-            <div class="form-group">
-              <label>ERC20 Token Address</label>
-              <input
-                class="form-control"
-                type="text"
-                placeholder="0x..."
-                id="eip747ContractAddress"
-              />
-            </div>
-
-            <div class="form-group">
-              <label>Symbol</label>
-              <input
-                class="form-control"
-                type="text"
-                placeholder="XYZ"
-                id="eip747Symbol"
-              />
-            </div>
-
-            <div class="form-group">
-              <label>Decimals</label>
-              <input
-                class="form-control"
-                type="number"
-                placeholder="18"
-                id="eip747Decimals"
-              />
-            </div>
-
-            <div class="form-group">
-              <button
-                class="btn btn-primary btn-lg btn-block mb-3"
-                id="eip747WatchButton"
-                disabled
-              >
-                Add Token
-              </button>
-            </div>
-
-            <p class="info-text alert alert-secondary">
-              EIP 747: <span id="eip747Status"></span>
-            </p>
-          </div>
-        </div>
-      </div>
-      </div>
+      <section id="components-tranactions">
       </section>
 
       <section id="components-ppom"></section>
diff --git a/src/index.js b/src/index.js
index 37ea2ec8..10ac7d9c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,15 +1,12 @@
 import MetaMaskOnboarding from '@metamask/onboarding';
 // eslint-disable-next-line camelcase
-import { recoverTypedSignature } from '@metamask/eth-sig-util';
 import { ethers } from 'ethers';
-import { toChecksumAddress } from 'ethereumjs-util';
 import {
   handleSdkConnect,
   handleWalletConnect,
   walletConnect,
 } from './connections';
 import Constants from './constants.json';
-import { splitSig } from './signatures/utils';
 import { NETWORKS_BY_CHAIN_ID } from './onchain-sample-contracts';
 import { getPermissionsDisplayString } from './utils';
 
@@ -33,6 +30,11 @@ import {
 } from './components/signatures';
 import { ensResolutionComponent } from './components/resolutions/ens-resolution';
 import { sendFormComponent } from './components/forms/send-form';
+import { sendComponent } from './components/transactions/send';
+import { erc20Component } from './components/transactions/erc20';
+import { erc721Component } from './components/transactions/erc721';
+import { erc1155Component } from './components/transactions/erc1155';
+import { eip747Component } from './components/transactions/eip747';
 
 const {
   hstBytecode,
@@ -57,6 +59,18 @@ const globalContext = {
   chainIdPadded: undefined,
   networkName: undefined,
   _connected: false,
+  piggybankContract: undefined,
+  piggybankFactory: undefined,
+  failingContractFactory: undefined,
+  failingContract: undefined,
+  multisigContract: undefined,
+  multisigFactory: undefined,
+  hstContract: undefined,
+  hstFactory: undefined,
+  nftsContract: undefined,
+  nftsFactory: undefined,
+  erc1155Contract: undefined,
+  erc1155Factory: undefined,
   get connected() {
     return this._connected;
   },
@@ -134,6 +148,17 @@ const revokeAccountsPermissionButton = document.getElementById(
   'revokeAccountsPermission',
 );
 
+const transactionsContainer =
+  document.getElementById('components-tranactions') || document.body;
+const transactionsRow = document.createElement('div');
+transactionsRow.className = 'row';
+transactionsContainer.appendChild(transactionsRow);
+sendComponent(transactionsRow);
+erc20Component(transactionsRow);
+erc721Component(transactionsRow);
+erc1155Component(transactionsRow);
+eip747Component(transactionsRow);
+
 // Contract Section
 const deployButton = document.getElementById('deployButton');
 const depositButton = document.getElementById('depositButton');
@@ -169,14 +194,7 @@ const nftsStatus = document.getElementById('nftsStatus');
 const erc721TokenAddresses = document.getElementById('erc721TokenAddresses');
 // 721 Permit
 const sign721Permit = document.getElementById('sign721Permit');
-const sign721PermitResult = document.getElementById('sign721PermitResult');
-const sign721PermitResultR = document.getElementById('sign721PermitResultR');
-const sign721PermitResultS = document.getElementById('sign721PermitResultS');
-const sign721PermitResultV = document.getElementById('sign721PermitResultV');
 const sign721PermitVerify = document.getElementById('sign721PermitVerify');
-const sign721PermitVerifyResult = document.getElementById(
-  'sign721PermitVerifyResult',
-);
 
 // ERC 1155 Section
 
@@ -201,11 +219,7 @@ const erc1155Status = document.getElementById('erc1155Status');
 const erc1155TokenAddresses = document.getElementById('erc1155TokenAddresses');
 
 // ERC 747 Section
-const eip747ContractAddress = document.getElementById('eip747ContractAddress');
-const eip747Symbol = document.getElementById('eip747Symbol');
-const eip747Decimals = document.getElementById('eip747Decimals');
 const eip747WatchButton = document.getElementById('eip747WatchButton');
-const eip747Status = document.getElementById('eip747Status');
 
 // Send Eth Section
 const sendButton = document.getElementById('sendButton');
@@ -223,7 +237,6 @@ const transferFromSenderInput = document.getElementById(
 const transferFromRecipientInput = document.getElementById(
   'transferFromRecipientInput',
 );
-const tokenSymbol = 'TST';
 const erc20TokenAddresses = document.getElementById('erc20TokenAddresses');
 const createToken = document.getElementById('createToken');
 const watchAssets = document.getElementById('watchAssets');
@@ -878,19 +891,6 @@ const handleScrollTo = async ({ delay = false } = {}) => {
  * Contracts
  */
 
-let hstFactory;
-let piggybankFactory;
-let nftsFactory;
-let failingContractFactory;
-let multisigFactory;
-let erc1155Factory;
-let hstContract;
-let piggybankContract;
-let nftsContract;
-let failingContract;
-let multisigContract;
-let erc1155Contract;
-
 // Must be called after the active provider changes
 const initializeContracts = () => {
   try {
@@ -900,63 +900,63 @@ const initializeContracts = () => {
       'any',
     );
     if (deployedContractAddress) {
-      hstContract = new ethers.Contract(
+      globalContext.hstContract = new ethers.Contract(
         deployedContractAddress,
         hstAbi,
         globalContext.ethersProvider.getSigner(),
       );
-      piggybankContract = new ethers.Contract(
+      globalContext.piggybankContract = new ethers.Contract(
         deployedContractAddress,
         piggybankAbi,
         globalContext.ethersProvider.getSigner(),
       );
-      nftsContract = new ethers.Contract(
+      globalContext.nftsContract = new ethers.Contract(
         deployedContractAddress,
         nftsAbi,
         globalContext.ethersProvider.getSigner(),
       );
-      failingContract = new ethers.Contract(
+      globalContext.failingContract = new ethers.Contract(
         deployedContractAddress,
         failingContractAbi,
         globalContext.ethersProvider.getSigner(),
       );
-      multisigContract = new ethers.Contract(
+      globalContext.multisigContract = new ethers.Contract(
         deployedContractAddress,
         multisigAbi,
         globalContext.ethersProvider.getSigner(),
       );
-      erc1155Contract = new ethers.Contract(
+      globalContext.erc1155Contract = new ethers.Contract(
         deployedContractAddress,
         erc1155Abi,
         globalContext.ethersProvider.getSigner(),
       );
     }
-    hstFactory = new ethers.ContractFactory(
+    globalContext.hstFactory = new ethers.ContractFactory(
       hstAbi,
       hstBytecode,
       globalContext.ethersProvider.getSigner(),
     );
-    piggybankFactory = new ethers.ContractFactory(
+    globalContext.piggybankFactory = new ethers.ContractFactory(
       piggybankAbi,
       piggybankBytecode,
       globalContext.ethersProvider.getSigner(),
     );
-    nftsFactory = new ethers.ContractFactory(
+    globalContext.nftsFactory = new ethers.ContractFactory(
       nftsAbi,
       nftsBytecode,
       globalContext.ethersProvider.getSigner(),
     );
-    failingContractFactory = new ethers.ContractFactory(
+    globalContext.failingContractFactory = new ethers.ContractFactory(
       failingContractAbi,
       failingContractBytecode,
       globalContext.ethersProvider.getSigner(),
     );
-    multisigFactory = new ethers.ContractFactory(
+    globalContext.multisigFactory = new ethers.ContractFactory(
       multisigAbi,
       multisigBytecode,
       globalContext.ethersProvider.getSigner(),
     );
-    erc1155Factory = new ethers.ContractFactory(
+    globalContext.erc1155Factory = new ethers.ContractFactory(
       erc1155Abi,
       erc1155Bytecode,
       globalContext.ethersProvider.getSigner(),
@@ -1074,7 +1074,9 @@ const updateContractElements = () => {
     multisigContractStatus.innerHTML = 'Deployed';
     sendMultisigButton.disabled = false;
     // ERC721 Token - NFTs contract
-    erc721TokenAddresses.innerHTML = nftsContract ? nftsContract.address : '';
+    erc721TokenAddresses.innerHTML = globalContext.nftsContract
+      ? globalContext.nftsContract.address
+      : '';
     nftsStatus.innerHTML = 'Deployed';
     mintButton.disabled = false;
     sign721Permit.disabled = false;
@@ -1091,8 +1093,8 @@ const updateContractElements = () => {
     watchNFTButtons.innerHTML = '';
 
     // ERC 1155 Multi Token
-    erc1155TokenAddresses.innerHTML = erc1155Contract
-      ? erc1155Contract.address
+    erc1155TokenAddresses.innerHTML = globalContext.erc1155Contract
+      ? globalContext.erc1155Contract.address
       : '';
     erc1155Status.innerHTML = 'Deployed';
     batchMintButton.disabled = false;
@@ -1106,7 +1108,9 @@ const updateContractElements = () => {
     watchAssetInput.disabled = false;
     watchAssetButton.disabled = false;
     // ERC20 Token - Send Tokens
-    erc20TokenAddresses.innerHTML = hstContract ? hstContract.address : '';
+    erc20TokenAddresses.innerHTML = globalContext.hstContract
+      ? globalContext.hstContract.address
+      : '';
     watchAssets.disabled = false;
     transferTokens.disabled = false;
     transferFromTokens.disabled = false;
@@ -1126,738 +1130,6 @@ const updateContractElements = () => {
 
 // Initializes form button onclicks
 const initializeFormElements = () => {
-  /**
-   * Piggy bank
-   */
-
-  deployButton.onclick = async () => {
-    contractStatus.innerHTML = 'Deploying';
-
-    try {
-      piggybankContract = await piggybankFactory.deploy();
-      await piggybankContract.deployTransaction.wait();
-    } catch (error) {
-      contractStatus.innerHTML = 'Deployment Failed';
-      throw error;
-    }
-
-    if (piggybankContract.address === undefined) {
-      return;
-    }
-
-    console.log(
-      `Contract mined! address: ${piggybankContract.address} transactionHash: ${piggybankContract.deployTransaction.hash}`,
-    );
-    contractStatus.innerHTML = 'Deployed';
-    depositButton.disabled = false;
-    withdrawButton.disabled = false;
-  };
-
-  depositButton.onclick = async () => {
-    contractStatus.innerHTML = 'Deposit initiated';
-    const result = await piggybankContract.deposit({
-      from: globalContext.accounts[0],
-      value: '0x3782dace9d900000',
-    });
-    console.log(result);
-    const receipt = await result.wait();
-    console.log(receipt);
-    contractStatus.innerHTML = 'Deposit completed';
-  };
-
-  withdrawButton.onclick = async () => {
-    const result = await piggybankContract.withdraw('0xde0b6b3a7640000', {
-      from: globalContext.accounts[0],
-    });
-    console.log(result);
-    const receipt = await result.wait();
-    console.log(receipt);
-    contractStatus.innerHTML = 'Withdrawn';
-  };
-
-  /**
-   * Failing
-   */
-
-  deployFailingButton.onclick = async () => {
-    failingContractStatus.innerHTML = 'Deploying';
-
-    try {
-      failingContract = await failingContractFactory.deploy();
-      await failingContract.deployTransaction.wait();
-    } catch (error) {
-      failingContractStatus.innerHTML = 'Deployment Failed';
-      throw error;
-    }
-
-    if (failingContract.address === undefined) {
-      return;
-    }
-
-    console.log(
-      `Contract mined! address: ${failingContract.address} transactionHash: ${failingContract.deployTransaction.hash}`,
-    );
-    failingContractStatus.innerHTML = 'Deployed';
-    sendFailingButton.disabled = false;
-  };
-
-  sendFailingButton.onclick = async () => {
-    try {
-      const result = await globalContext.provider.request({
-        method: 'eth_sendTransaction',
-        params: [
-          {
-            from: globalContext.accounts[0],
-            to: failingContract.address,
-            value: '0x0',
-            gasLimit: '0x5028',
-            maxFeePerGas: '0x2540be400',
-            maxPriorityFeePerGas: '0x3b9aca00',
-          },
-        ],
-      });
-      failingContractStatus.innerHTML =
-        'Failed transaction process completed as expected.';
-      console.log('send failing contract result', result);
-    } catch (error) {
-      console.log('error', error);
-      throw error;
-    }
-  };
-
-  /**
-   * Multisig
-   */
-
-  deployMultisigButton.onclick = async () => {
-    multisigContractStatus.innerHTML = 'Deploying';
-
-    try {
-      multisigContract = await multisigFactory.deploy();
-      await multisigContract.deployTransaction.wait();
-    } catch (error) {
-      multisigContractStatus.innerHTML = 'Deployment Failed';
-      throw error;
-    }
-
-    if (multisigContract.address === undefined) {
-      return;
-    }
-
-    console.log(
-      `Contract mined! address: ${multisigContract.address} transactionHash: ${multisigContract.deployTransaction.hash}`,
-    );
-    multisigContractStatus.innerHTML = 'Deployed';
-    sendMultisigButton.disabled = false;
-  };
-
-  sendMultisigButton.onclick = async () => {
-    try {
-      const result = await globalContext.provider.request({
-        method: 'eth_sendTransaction',
-        params: [
-          {
-            from: globalContext.accounts[0],
-            to: multisigContract.address,
-            value: '0x16345785D8A0', // 24414062500000
-            gasLimit: '0x5028',
-            maxFeePerGas: '0x2540be400',
-            maxPriorityFeePerGas: '0x3b9aca00',
-          },
-        ],
-      });
-      multisigContractStatus.innerHTML = 'Transaction completed as expected.';
-      console.log('send multisig contract result', result);
-    } catch (error) {
-      console.log('error', error);
-      throw error;
-    }
-  };
-
-  /**
-   * ERC721 Token
-   */
-
-  deployNFTsButton.onclick = async () => {
-    nftsStatus.innerHTML = 'Deploying';
-
-    try {
-      nftsContract = await nftsFactory.deploy();
-      await nftsContract.deployTransaction.wait();
-    } catch (error) {
-      nftsStatus.innerHTML = 'Deployment Failed';
-      throw error;
-    }
-
-    if (nftsContract.address === undefined) {
-      return;
-    }
-
-    console.log(
-      `Contract mined! address: ${nftsContract.address} transactionHash: ${nftsContract.deployTransaction.hash}`,
-    );
-
-    erc721TokenAddresses.innerHTML = erc721TokenAddresses.innerHTML
-      .concat(', ', nftsContract.address)
-      .split(', ')
-      .filter(Boolean)
-      .join(', ');
-
-    nftsStatus.innerHTML = 'Deployed';
-    mintButton.disabled = false;
-    sign721Permit.disabled = false;
-    mintAmountInput.disabled = false;
-  };
-
-  watchNFTsButton.onclick = async () => {
-    const currentTokenId = await nftsContract.currentTokenId();
-    const nftsContractAddress = nftsContract.address;
-    let watchNftsResult;
-    try {
-      watchNftsResult = await globalContext.provider.sendAsync(
-        Array.from({ length: currentTokenId }, (_, i) => i + 1).map(
-          (tokenId) => {
-            return {
-              method: 'wallet_watchAsset',
-              params: {
-                type: 'ERC721',
-                options: {
-                  address: nftsContractAddress,
-                  tokenId: tokenId.toString(),
-                },
-              },
-            };
-          },
-        ),
-      );
-    } catch (error) {
-      console.error(error);
-    }
-    console.log(watchNftsResult);
-  };
-
-  mintButton.onclick = async () => {
-    nftsStatus.innerHTML = 'Mint initiated';
-    let result = await nftsContract.mintNFTs(mintAmountInput.value, {
-      from: globalContext.accounts[0],
-    });
-    result = await result.wait();
-    console.log(result);
-    nftsStatus.innerHTML = 'Mint completed';
-    approveTokenInput.disabled = false;
-    approveButton.disabled = false;
-    watchNFTInput.disabled = false;
-    watchNFTButton.disabled = false;
-    setApprovalForAllButton.disabled = false;
-    revokeButton.disabled = false;
-    transferTokenInput.disabled = false;
-    transferFromButton.disabled = false;
-    watchNFTsButton.disabled = false;
-    watchNFTButtons.innerHTML = '';
-  };
-
-  sign721Permit.onclick = async () => {
-    const from = globalContext.accounts[0];
-    const msgParams = await getNFTMsgParams();
-    console.log(msgParams);
-
-    let sign;
-    let r;
-    let s;
-    let v;
-
-    try {
-      sign = await globalContext.provider.request({
-        method: 'eth_signTypedData_v4',
-        params: [from, JSON.stringify(msgParams)],
-      });
-      const { _r, _s, _v } = splitSig(sign);
-      r = `0x${_r.toString('hex')}`;
-      s = `0x${_s.toString('hex')}`;
-      v = _v.toString();
-
-      sign721PermitResult.innerHTML = sign;
-      sign721PermitResultR.innerHTML = `r: ${r}`;
-      sign721PermitResultS.innerHTML = `s: ${s}`;
-      sign721PermitResultV.innerHTML = `v: ${v}`;
-      sign721PermitVerify.disabled = false;
-    } catch (err) {
-      console.error(err);
-      sign721PermitResult.innerHTML = `Error: ${err.message}`;
-    }
-  };
-
-  /**
-   *  Sign Permit Verification
-   */
-  sign721PermitVerify.onclick = async () => {
-    const from = globalContext.accounts[0];
-    const msgParams = await getNFTMsgParams();
-
-    try {
-      const sign = sign721PermitResult.innerHTML;
-      const recoveredAddr = recoverTypedSignature({
-        data: msgParams,
-        signature: sign,
-        version: 'V4',
-      });
-      if (toChecksumAddress(recoveredAddr) === toChecksumAddress(from)) {
-        console.log(`Successfully verified signer as ${recoveredAddr}`);
-        sign721PermitVerifyResult.innerHTML = recoveredAddr;
-      } else {
-        console.log(
-          `Failed to verify signer when comparing ${recoveredAddr} to ${from}`,
-        );
-      }
-    } catch (err) {
-      console.error(err);
-      sign721PermitVerifyResult.innerHTML = `Error: ${err.message}`;
-    }
-  };
-
-  watchNFTButton.onclick = async () => {
-    let watchNftsResult;
-    try {
-      watchNftsResult = await globalContext.provider.request({
-        method: 'wallet_watchAsset',
-        params: {
-          type: 'ERC721',
-          options: {
-            address: nftsContract.address,
-            tokenId: watchNFTInput.value,
-          },
-        },
-      });
-    } catch (error) {
-      console.error(error);
-    }
-    console.log(watchNftsResult);
-  };
-
-  approveButton.onclick = async () => {
-    nftsStatus.innerHTML = 'Approve initiated';
-    let result = await nftsContract.approve(
-      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
-      approveTokenInput.value,
-      {
-        from: globalContext.accounts[0],
-      },
-    );
-    result = await result.wait();
-    console.log(result);
-    nftsStatus.innerHTML = 'Approve completed';
-  };
-
-  setApprovalForAllButton.onclick = async () => {
-    nftsStatus.innerHTML = 'Set Approval For All initiated';
-    let result = await nftsContract.setApprovalForAll(
-      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
-      true,
-      {
-        from: globalContext.accounts[0],
-      },
-    );
-    result = await result.wait();
-    console.log(result);
-    nftsStatus.innerHTML = 'Set Approval For All completed';
-  };
-
-  revokeButton.onclick = async () => {
-    nftsStatus.innerHTML = 'Revoke initiated';
-    let result = await nftsContract.setApprovalForAll(
-      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
-      false,
-      {
-        from: globalContext.accounts[0],
-      },
-    );
-    result = await result.wait();
-    console.log(result);
-    nftsStatus.innerHTML = 'Revoke completed';
-  };
-
-  transferFromButton.onclick = async () => {
-    nftsStatus.innerHTML = 'Transfer From initiated';
-    let result = await nftsContract.transferFrom(
-      globalContext.accounts[0],
-      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
-      transferTokenInput.value,
-      {
-        from: globalContext.accounts[0],
-      },
-    );
-    result = await result.wait();
-    console.log(result);
-    nftsStatus.innerHTML = 'Transfer From completed';
-  };
-
-  /**
-   * ERC1155 Token
-   */
-
-  deployERC1155Button.onclick = async () => {
-    erc1155Status.innerHTML = 'Deploying';
-
-    try {
-      erc1155Contract = await erc1155Factory.deploy();
-      await erc1155Contract.deployTransaction.wait();
-    } catch (error) {
-      erc1155Status.innerHTML = 'Deployment Failed!';
-      throw error;
-    }
-
-    if (erc1155Contract.address === undefined) {
-      return;
-    }
-
-    console.log(
-      `Contract mined! address: ${erc1155Contract.address} transactionHash: ${erc1155Contract.deployTransaction.hash}`,
-    );
-
-    erc1155TokenAddresses.innerHTML = erc1155TokenAddresses.innerHTML
-      .concat(', ', erc1155Contract.address)
-      .split(', ')
-      .filter(Boolean)
-      .join(', ');
-
-    erc1155Status.innerHTML = 'Deployed';
-    batchTransferTokenIds.disabled = false;
-    batchTransferTokenAmounts.disabled = false;
-    batchMintButton.disabled = false;
-    batchTransferFromButton.disabled = false;
-    setApprovalForAllERC1155Button.disabled = false;
-    revokeERC1155Button.disabled = false;
-    watchAssetInput.disabled = false;
-    watchAssetButton.disabled = false;
-  };
-
-  batchMintButton.onclick = async () => {
-    erc1155Status.innerHTML = 'Batch Mint initiated';
-
-    const params = [
-      globalContext.accounts[0],
-      batchMintTokenIds.value.split(',').map(Number),
-      batchMintIdAmounts.value.split(',').map(Number),
-      '0x',
-    ];
-
-    let result;
-
-    try {
-      result = await erc1155Contract.mintBatch(...params);
-    } catch (error) {
-      erc1155Status.innerHTML = 'Mint Failed!';
-      throw error;
-    }
-
-    console.log(result);
-    erc1155Status.innerHTML = 'Batch Minting completed';
-  };
-
-  batchTransferFromButton.onclick = async () => {
-    erc1155Status.innerHTML = 'Batch Transfer From initiated';
-
-    const params = [
-      globalContext.accounts[0],
-      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
-      batchTransferTokenIds.value.split(',').map(Number),
-      batchTransferTokenAmounts.value.split(',').map(Number),
-      '0x',
-    ];
-
-    let result;
-
-    try {
-      result = await erc1155Contract.safeBatchTransferFrom(...params);
-    } catch (error) {
-      erc1155Status.innerHTML = 'Transaction Failed!';
-      throw error;
-    }
-    console.log(result);
-    erc1155Status.innerHTML = 'Batch Transfer From completed';
-  };
-
-  setApprovalForAllERC1155Button.onclick = async () => {
-    erc1155Status.innerHTML = 'Set Approval For All initiated';
-    let result = await erc1155Contract.setApprovalForAll(
-      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
-      true,
-      {
-        from: globalContext.accounts[0],
-      },
-    );
-    result = await result.wait();
-    console.log(result);
-    erc1155Status.innerHTML = 'Set Approval For All completed';
-  };
-
-  revokeERC1155Button.onclick = async () => {
-    erc1155Status.innerHTML = 'Revoke initiated';
-    let result = await erc1155Contract.setApprovalForAll(
-      '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4',
-      false,
-      {
-        from: globalContext.accounts[0],
-      },
-    );
-    result = await result.wait();
-    console.log(result);
-    erc1155Status.innerHTML = 'Revoke completed';
-  };
-
-  watchAssetButton.onclick = async () => {
-    try {
-      const watchAssetResult = await globalContext.provider.request({
-        method: 'wallet_watchAsset',
-        params: {
-          type: 'ERC1155',
-          options: {
-            address: erc1155Contract.address,
-            tokenId: watchAssetInput.value,
-          },
-        },
-      });
-      console.log(watchAssetResult);
-    } catch (error) {
-      console.error(error);
-    }
-  };
-
-  /**
-   *  EIP 747
-   */
-
-  eip747WatchButton.onclick = async () => {
-    eip747Status.innerHTML = 'Adding token...';
-
-    try {
-      const result = await globalContext.provider.request({
-        method: 'wallet_watchAsset',
-        params: {
-          type: 'ERC20',
-          options: {
-            address: eip747ContractAddress.value,
-            symbol: eip747Symbol.value,
-            decimals: parseInt(eip747Decimals.value, 10),
-            image: 'https://metamask.github.io/test-dapp/metamask-fox.svg',
-          },
-        },
-      });
-      eip747Status.innerHTML = 'NFT added successfully';
-      console.log(result);
-    } catch (error) {
-      eip747Status.innerHTML =
-        'There was an error adding the token. See console for details.';
-      console.error(error);
-    }
-  };
-
-  /**
-   * Sending ETH
-   */
-
-  sendButton.onclick = async () => {
-    const result = await globalContext.provider.request({
-      method: 'eth_sendTransaction',
-      params: [
-        {
-          from: globalContext.accounts[0],
-          to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb',
-          value: '0x0',
-          gasLimit: '0x5208',
-          gasPrice: '0x2540be400',
-          type: '0x0',
-        },
-      ],
-    });
-    console.log(result);
-  };
-
-  sendEIP1559Button.onclick = async () => {
-    const result = await globalContext.provider.request({
-      method: 'eth_sendTransaction',
-      params: [
-        {
-          from: globalContext.accounts[0],
-          to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb',
-          value: '0x0',
-          gasLimit: '0x5028',
-          maxFeePerGas: '0x2540be400',
-          maxPriorityFeePerGas: '0x3b9aca00',
-        },
-      ],
-    });
-    console.log(result);
-  };
-
-  sendEIP1559WithoutGasButton.onclick = async () => {
-    const result = await globalContext.provider.request({
-      method: 'eth_sendTransaction',
-      params: [
-        {
-          from: globalContext.accounts[0],
-          to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb',
-          value: '0x0',
-        },
-      ],
-    });
-    console.log(result);
-  };
-
-  /**
-   * ERC20 Token
-   */
-
-  createToken.onclick = async () => {
-    const _initialAmount = 10;
-    const _tokenName = 'TST';
-
-    try {
-      hstContract = await hstFactory.deploy(
-        _initialAmount,
-        _tokenName,
-        decimalUnitsInput.value,
-        tokenSymbol,
-      );
-      await hstContract.deployTransaction.wait();
-    } catch (error) {
-      erc20TokenAddresses.innerHTML = 'Creation Failed';
-      throw error;
-    }
-
-    if (hstContract.address === undefined) {
-      return;
-    }
-
-    console.log(
-      `Contract mined! address: ${hstContract.address} transactionHash: ${hstContract.deployTransaction.hash}`,
-    );
-    erc20TokenAddresses.innerHTML = erc20TokenAddresses.innerHTML
-      .concat(', ', hstContract.address)
-      .split(', ')
-      .filter(Boolean)
-      .join(', ');
-    watchAssets.disabled = false;
-    transferTokens.disabled = false;
-    transferFromTokens.disabled = false;
-    approveTokens.disabled = false;
-    increaseTokenAllowance.disabled = false;
-    allowanceOwnerInput.disabled = false;
-    allowanceSpenderInput.disabled = false;
-    allowanceAmountResult.disabled = false;
-    getAllowance.disabled = false;
-    transferTokensWithoutGas.disabled = false;
-    approveTokensWithoutGas.disabled = false;
-    approveTokensToInput.disabled = false;
-    transferFromSenderInput.disabled = false;
-    transferFromRecipientInput.disabled = false;
-  };
-
-  watchAssets.onclick = async () => {
-    const contractAddresses = erc20TokenAddresses.innerHTML.split(', ');
-
-    const promises = contractAddresses.map((erc20Address) => {
-      return globalContext.provider.request({
-        method: 'wallet_watchAsset',
-        params: {
-          type: 'ERC20',
-          options: {
-            address: erc20Address,
-            symbol: tokenSymbol,
-            decimals: decimalUnitsInput.value,
-            image: 'https://metamask.github.io/test-dapp/metamask-fox.svg',
-          },
-        },
-      });
-    });
-
-    Promise.all(promises).then((result) => {
-      console.log('result', result);
-    });
-  };
-
-  transferTokens.onclick = async () => {
-    const result = await hstContract.transfer(
-      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
-      decimalUnitsInput.value === '0'
-        ? 1
-        : `${1.5 * 10 ** decimalUnitsInput.value}`,
-      { from: globalContext.accounts[0] },
-    );
-    console.log('result', result);
-  };
-
-  approveTokens.onclick = async () => {
-    const result = await hstContract.approve(
-      approveTokensToInput.value,
-      `${7 * 10 ** decimalUnitsInput.value}`,
-      { from: globalContext.accounts[0] },
-    );
-    console.log('result', result);
-  };
-
-  increaseTokenAllowance.onclick = async () => {
-    const result = await hstContract.increaseAllowance(
-      approveTokensToInput.value,
-      `${1 * 10 ** decimalUnitsInput.value}`,
-      { from: globalContext.accounts[0] },
-    );
-    console.log('result', result);
-  };
-
-  getAllowance.onclick = async () => {
-    const result = await hstContract.allowance(
-      allowanceOwnerInput.value,
-      allowanceSpenderInput.value,
-      { from: globalContext.accounts[0] },
-    );
-    const allowance = result.toNumber() / 10 ** decimalUnitsInput.value;
-    allowanceAmountResult.innerHTML = allowance.toFixed(
-      decimalUnitsInput.value,
-    );
-  };
-
-  transferFromTokens.onclick = async () => {
-    try {
-      const result = await hstContract.transferFrom(
-        transferFromSenderInput.value,
-        transferFromRecipientInput.value,
-        decimalUnitsInput.value === '0'
-          ? 1
-          : `${1.5 * 10 ** decimalUnitsInput.value}`,
-        { from: globalContext.accounts[0] },
-      );
-      console.log('result', result);
-      tokenMethodsResult.innerHTML = result;
-    } catch (error) {
-      tokenMethodsResult.innerHTML = error.message;
-    }
-  };
-
-  transferTokensWithoutGas.onclick = async () => {
-    const result = await hstContract.transfer(
-      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
-      decimalUnitsInput.value === '0'
-        ? 1
-        : `${1.5 * 10 ** decimalUnitsInput.value}`,
-      {
-        gasPrice: '20000000000',
-      },
-    );
-    console.log('result', result);
-  };
-
-  approveTokensWithoutGas.onclick = async () => {
-    const result = await hstContract.approve(
-      '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
-      `${7 * 10 ** decimalUnitsInput.value}`,
-      {
-        gasPrice: '20000000000',
-      },
-    );
-    console.log('result', result);
-  };
-
   /**
    * Permissions
    */
@@ -1954,32 +1226,6 @@ const initializeFormElements = () => {
     }
   };
 
-  async function getNFTMsgParams() {
-    return {
-      domain: {
-        name: 'My NFT',
-        version: '1',
-        chainId: globalContext.chainIdInt,
-        verifyingContract: nftsContract.address,
-      },
-      types: {
-        Permit: [
-          { name: 'spender', type: 'address' },
-          { name: 'tokenId', type: 'uint256' },
-          { name: 'nonce', type: 'uint256' },
-          { name: 'deadline', type: 'uint256' },
-        ],
-      },
-      primaryType: 'Permit',
-      message: {
-        spender: '0x0521797E19b8E274E4ED3bFe5254FAf6fac96F08',
-        tokenId: '3606393',
-        nonce: '0',
-        deadline: '1734995006',
-      },
-    };
-  }
-
   /**
    * Providers
    */

From 07ebb183943049428c1c84d8f1162bc7ea51940e Mon Sep 17 00:00:00 2001
From: Priya Narayanaswamy <priya.narayanaswamy@consensys.net>
Date: Wed, 18 Dec 2024 19:44:53 +0100
Subject: [PATCH 2/3] chore: add index.js to export all modules

---
 src/index.js | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/index.js b/src/index.js
index 10ac7d9c..47e6a5f3 100644
--- a/src/index.js
+++ b/src/index.js
@@ -30,11 +30,13 @@ import {
 } from './components/signatures';
 import { ensResolutionComponent } from './components/resolutions/ens-resolution';
 import { sendFormComponent } from './components/forms/send-form';
-import { sendComponent } from './components/transactions/send';
-import { erc20Component } from './components/transactions/erc20';
-import { erc721Component } from './components/transactions/erc721';
-import { erc1155Component } from './components/transactions/erc1155';
-import { eip747Component } from './components/transactions/eip747';
+import {
+  sendComponent,
+  erc20Component,
+  erc1155Component,
+  eip747Component,
+  erc721Component,
+} from './components/transactions';
 
 const {
   hstBytecode,

From 1dc89e639560b36d6b08c8f3796775536b482eb9 Mon Sep 17 00:00:00 2001
From: Priya Narayanaswamy <priya.narayanaswamy@consensys.net>
Date: Wed, 18 Dec 2024 19:48:57 +0100
Subject: [PATCH 3/3] chore: add index.js to export all modules

---
 src/components/transactions/index.js | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 src/components/transactions/index.js

diff --git a/src/components/transactions/index.js b/src/components/transactions/index.js
new file mode 100644
index 00000000..f885a52a
--- /dev/null
+++ b/src/components/transactions/index.js
@@ -0,0 +1,5 @@
+export * from './eip747';
+export * from './erc20';
+export * from './erc721';
+export * from './erc1155';
+export * from './send';
