Skip to content

Commit

Permalink
Refactor: Move all components to separate files (#379)
Browse files Browse the repository at this point in the history
* Move ENS Resolution to separate file

* lint fixes

* Move send form to separate file

* chore: refactor signature types to different components (#380)

* chore: refactor signature types to different components

* fix: injection order of components

* Simplify loading a batch of modules

* Use parentContainer pattern across all components

* Migrate malformed transactions form

And committing a naming crime, but we will allow it

* Use event listeners for enabling buttons when connected

This introduces a new parameters on `globalContext` called `_connected` with a getter and setter. When set to a new value, the setter dispatches a custom event `globalConnectionChange`. Each module with a button that needs to be enabled when MetaMask is connected thus has an event listener for that event. Now, those buttons are enabled via the listener.

This gets us part way to relying on listeners for all state changes.

* Move encrypt-decrypt to separate module

* Migrate encrypt-decrypt and all PPOMs

Also fix a few small errors from previous commits

* Fix imports

* fix: permit message verification (#382)

* chore: Split transactions into separate components (#383)

* chore: Split transactions into separate components

* chore: add index.js to export all modules

* chore: add index.js to export all modules

* Move interactions section to module files

* Move connections to separate files

Unfortunately most of the connection logic is still in index.js and is hard to untangle

* Wrap an error message in template string

* Migrate type onchange handler to module

* Move sendDeepLink href set to module

* set deep links in erc20 component code

* Fix glaring typo

* Programmatic sections

* lint fixes

* Move more events and utils

* Lint fix and remove array

* Decentralize clearDisplayElements

* No more allConnectedButtons

* Change innerHTML to innerText

* No more initializeFormElements

* Move 1559-related DOM updates to separate files

* Move updating DOM for deployed contract to separate files

* Move updating network specific buttons to separate file

* Simplify connection event logic

* Two more custom events

* Fix small error

* Remove unneeded lint disable line

* fix: enable defaults on wallet connect (#384)

---------

Co-authored-by: Priya <[email protected]>
  • Loading branch information
Montoya and pnarayanaswamy authored Jan 21, 2025
1 parent 15cb01a commit dac0701
Show file tree
Hide file tree
Showing 39 changed files with 5,219 additions and 4,644 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
.vscode
dist
.eslintcache
.DS_Store
73 changes: 73 additions & 0 deletions src/components/connections/connections.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* import { walletConnect } from "../../connections"; */
import globalContext from '../..';

export function connectionsComponent(parentContainer) {
parentContainer.insertAdjacentHTML(
'beforeend',
`<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">
Connect Actions
</h4>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="connectButton"
disabled
>
Connect
</button>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="walletConnect"
>
Wallet Connect
</button>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="sdkConnect"
>
SDK Connect
</button>
<hr />
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="getAccounts"
>
eth_accounts
</button>
<p class="info-text alert alert-secondary">
eth_accounts result: <span id="getAccountsResult"></span>
</p>
</div>
</div>
</div>`,
);

/*
const onboardButton = document.getElementById('connectButton');
const walletConnectBtn = document.getElementById('walletConnect');
const sdkConnectBtn = document.getElementById('sdkConnect');
*/
const getAccounts = document.getElementById('getAccounts');
const getAccountsResult = document.getElementById('getAccountsResult');

document.addEventListener('disableAndClear', function () {
getAccountsResult.innerText = '';
});

getAccounts.onclick = async () => {
try {
const _accounts = await globalContext.provider.request({
method: 'eth_accounts',
});
getAccountsResult.innerHTML = _accounts || 'Not able to get accounts';
} catch (err) {
console.error(err);
getAccountsResult.innerHTML = `Error: ${err.message}`;
}
};
}
2 changes: 2 additions & 0 deletions src/components/connections/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './connections';
export * from './permissions';
94 changes: 94 additions & 0 deletions src/components/connections/permissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { getPermissionsDisplayString } from '../../utils';
import globalContext from '../..';

export function permissionsComponent(parentContainer) {
parentContainer.insertAdjacentHTML(
'beforeend',
`<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">
Permissions Actions
</h4>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="requestPermissions"
>
Request Permissions
</button>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="getPermissions"
>
Get Permissions
</button>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="revokeAccountsPermission"
>
Revoke Accounts Permission
</button>
<p class="info-text alert alert-secondary">
Permissions result: <span id="permissionsResult"></span>
</p>
</div>
</div>
</div>`,
);

const requestPermissions = document.getElementById('requestPermissions');
const getPermissions = document.getElementById('getPermissions');
const revokeAccountsPermission = document.getElementById(
'revokeAccountsPermission',
);
const permissionsResult = document.getElementById('permissionsResult');

document.addEventListener('disableAndClear', function () {
permissionsResult.innerText = '';
});

requestPermissions.onclick = async () => {
try {
const permissionsArray = await globalContext.provider.request({
method: 'wallet_requestPermissions',
params: [{ eth_accounts: {} }],
});
permissionsResult.innerHTML =
getPermissionsDisplayString(permissionsArray);
} catch (err) {
console.error(err);
permissionsResult.innerHTML = `Error: ${err.message}`;
}
};

getPermissions.onclick = async () => {
try {
const permissionsArray = await globalContext.provider.request({
method: 'wallet_getPermissions',
});
permissionsResult.innerHTML =
getPermissionsDisplayString(permissionsArray);
} catch (err) {
console.error(err);
permissionsResult.innerHTML = `Error: ${err.message}`;
}
};

revokeAccountsPermission.onclick = async () => {
try {
await globalContext.provider.request({
method: 'wallet_revokePermissions',
params: [
{
eth_accounts: {},
},
],
});
} catch (err) {
permissionsResult.innerHTML = `${err.message}`;
}
};
}
156 changes: 156 additions & 0 deletions src/components/encryption/encrypt-decrypt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { encrypt } from '@metamask/eth-sig-util';
import { stringifiableToHex } from '../../utils';
import globalContext from '../..';

export function encryptDecryptComponent(parentContainer) {
parentContainer.insertAdjacentHTML(
'beforeend',
`<div class="row d-flex justify-content-center">
<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">
Encrypt / Decrypt
</h4>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="getEncryptionKeyButton"
disabled
>
Get Encryption Key
</button>
<hr />
<div id="encrypt-message-form">
<input
class="form-control"
type="text"
placeholder="Message to encrypt"
id="encryptMessageInput"
/>
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="encryptButton"
disabled
>
Encrypt
</button>
</div>
<hr />
<button
class="btn btn-primary btn-lg btn-block mb-3"
id="decryptButton"
disabled
>
Decrypt
</button>
<p class="info-text alert alert-secondary">
Encryption key: <span id="encryptionKeyDisplay"></span>
</p>
<p class="info-text text-truncate alert alert-secondary">
Ciphertext: <span id="ciphertextDisplay"></span>
</p>
<p class="info-text alert alert-secondary">
Cleartext: <span id="cleartextDisplay"></span>
</p>
</div>
</div>
</div>
</div>`,
);

const getEncryptionKeyButton = document.getElementById(
'getEncryptionKeyButton',
);
const encryptMessageInput = document.getElementById('encryptMessageInput');
const encryptButton = document.getElementById('encryptButton');
const decryptButton = document.getElementById('decryptButton');
const encryptionKeyDisplay = document.getElementById('encryptionKeyDisplay');
const ciphertextDisplay = document.getElementById('ciphertextDisplay');
const cleartextDisplay = document.getElementById('cleartextDisplay');

document.addEventListener('globalConnectionChange', function (e) {
if (e.detail.connected) {
// MetaMask is connected, enable the button
getEncryptionKeyButton.disabled = false;
}
});

document.addEventListener('disableAndClear', function () {
getEncryptionKeyButton.disabled = true;
encryptMessageInput.disabled = true;
encryptButton.disabled = true;
decryptButton.disabled = true;
encryptionKeyDisplay.innerText = '';
encryptMessageInput.value = '';
ciphertextDisplay.innerText = '';
cleartextDisplay.innerText = '';
});

/**
* Encrypt / Decrypt
*/

getEncryptionKeyButton.onclick = async () => {
try {
encryptionKeyDisplay.innerText = await globalContext.provider.request({
method: 'eth_getEncryptionPublicKey',
params: [globalContext.accounts[0]],
});
encryptMessageInput.disabled = false;
} catch (error) {
encryptionKeyDisplay.innerText = `Error: ${error.message}`;
encryptMessageInput.disabled = true;
encryptButton.disabled = true;
decryptButton.disabled = true;
}
};

encryptMessageInput.onkeyup = () => {
if (
!getEncryptionKeyButton.disabled &&
encryptMessageInput.value.length > 0
) {
if (encryptButton.disabled) {
encryptButton.disabled = false;
}
} else if (!encryptButton.disabled) {
encryptButton.disabled = true;
}
};

encryptButton.onclick = () => {
try {
ciphertextDisplay.innerText = stringifiableToHex(
encrypt({
publicKey: encryptionKeyDisplay.innerText,
data: encryptMessageInput.value,
version: 'x25519-xsalsa20-poly1305',
}),
);
decryptButton.disabled = false;
} catch (error) {
ciphertextDisplay.innerText = `Error: ${error.message}`;
decryptButton.disabled = true;
}
};

decryptButton.onclick = async () => {
try {
cleartextDisplay.innerText = await globalContext.provider.request({
method: 'eth_decrypt',
params: [ciphertextDisplay.innerText, globalContext.accounts[0]],
});
} catch (error) {
cleartextDisplay.innerText = `Error: ${error.message}`;
}
};
}
Loading

0 comments on commit dac0701

Please sign in to comment.