diff --git a/README.md b/README.md index 20abd96..af410dd 100644 --- a/README.md +++ b/README.md @@ -81,9 +81,9 @@ The next step is to install the MetaMask Flask development plugin. This is a spe To use the Tenderly MetaMask snap, you'll need a Tenderly account. If you don't have one already, visit the [Tenderly website](https://dashboard.tenderly.co/register) and create a new account. -### Create an Access Key +### Create an Access Token -Once you've logged into your Tenderly account, you will need to create an `access-key`. This is a unique identifier that allows the Tenderly MetaMask snap to interact with your Tenderly account. You can generate it on the following link https://dashboard.tenderly.co/account/authorization. +Once you've logged into your Tenderly account, you will need to create an `access token`. This is a unique identifier that allows the Tenderly MetaMask snap to interact with your Tenderly account. You can generate it on the following link https://dashboard.tenderly.co/account/authorization. image @@ -123,7 +123,7 @@ With the app running, you can now install the Tenderly MetaMask snap. To do this ### Add Tenderly Credentials -Finally, you'll need to add your Tenderly credentials to the snap. Click on **Add access key** button within the app. You'll need to enter your credentials in the following format: `{user_id}@{project_id}@{access_key}`. +Finally, you'll need to add your Tenderly credentials to the snap. Click on **Add access token** button within the app. You'll need to enter your credentials in the following format: `{account_id}@{project_id}@{access_token}`. That's it! You've successfully set up the Tenderly MetaMask snap. If you encounter any issues during the setup process, don't hesitate to reach out to our support team at support@tenderly.co. We're here to help! 💜 diff --git a/packages/site/src/components/Buttons.tsx b/packages/site/src/components/Buttons.tsx index 704950c..071eb54 100644 --- a/packages/site/src/components/Buttons.tsx +++ b/packages/site/src/components/Buttons.tsx @@ -79,7 +79,7 @@ const SuccessButton = styled.button` &:hover { color: #ffffff; - background-color: #8bc34a; + background-color: #62b966; } ${({ theme }) => theme.mediaQueries.small} { @@ -155,7 +155,7 @@ export const SendFailedTxButton = (props: ComponentProps) => { export const UpdateTenderlyAccessKeyButton = ( props: ComponentProps, ) => { - return ; + return ; }; export const GoToDocsButton = () => { diff --git a/packages/site/src/pages/index.tsx b/packages/site/src/pages/index.tsx index fe81736..529a96b 100644 --- a/packages/site/src/pages/index.tsx +++ b/packages/site/src/pages/index.tsx @@ -5,7 +5,6 @@ import { updateTenderlyAccessKey, sendTransaction, sendTenderlyTransaction, - // sendSuccessfulTransaction, sendFailedTransaction, } from '../utils'; import { @@ -110,10 +109,18 @@ const ErrorMessage = styled.div` } `; +const PreContainer = styled.pre` + padding: 1rem; + background-color: ${({ theme }) => theme.colors.background.alternative}; + border-radius: 4px; + word-break: break-all; + white-space: pre-wrap; +`; + const Index = () => { const [state, dispatch] = useContext(MetaMaskContext); - const successfulTx = { + const successfulTxPayload = { to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', value: '0x0', data: '0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000004c4b40', @@ -176,7 +183,7 @@ const Index = () => { content={{ title: 'Add Tenderly Credentials', description: - 'Add Tenderly User ID, Project ID and Access Key. Required to interact with Tenderly API.', + 'Add Tenderly Account ID, Project ID and Access Token. Required to interact with Tenderly API.', data: (
{ content={{ title: 'Send Successful Transaction', description: - "Send a successful transaction with a predefined payload. It will be simulated using Tenderly Simulation API. Don't confirm it!", + 'Send a successful transaction with a predefined payload. It will be simulated using Tenderly Simulation API. Do not confirm it!', data: (
{ content={{ title: 'Send Failed Transaction', description: - "Send a failed transaction with a predefined payload. It will be simulated using Tenderly Simulation API. Don't confirm it!", + 'Send a failed transaction with a predefined payload. It will be simulated using Tenderly Simulation API. Do not confirm it!', data: (
{ content={{ title: 'Send Any Transaction', description: - "Send a transaction with a custom payload. It will be simulated using Tenderly Simulation API. Don't confirm it!", + 'Send a transaction with a custom payload. It will be simulated using Tenderly Simulation API. Do not confirm it!', data: (
@@ -295,17 +302,9 @@ const Index = () => { 5 USDC to demo.eth. Copy it and click on the{' '} Send Transaction button.
-
-                  {JSON.stringify(successfulTx, null, 2)}
-                
+ + {JSON.stringify(successfulTxPayload, null, 2)} + => { params: { snapId: defaultSnapOrigin, request: { - method: 'update_tenderly_credentials', + method: CustomRequestMethod.UPDATE_TENDERLY_CREDENTIALS, }, }, }); @@ -74,12 +75,31 @@ export const sendTenderlyTransaction = async (): Promise => { params: { snapId: defaultSnapOrigin, request: { - method: 'send_tenderly_transaction', + method: CustomRequestMethod.SEND_TENDERLY_TRANSACTION, }, }, }); }; +/** + * Sends a transaction using the Ethereum provider's `eth_sendTransaction` JSON-RPC method. + * The transaction data is taken from the input parameter. + * + * @param data - The data of the transaction to be sent. This should be an object containing + * the relevant transaction data such as the `to` address, the `value`, the `gas`, + * the `gasPrice`, and the `data` (for contract interactions). + * @returns A Promise that resolves to the transaction hash if the transaction + * submission was successful, or rejects with an error if something went wrong. + * @throws Will throw an error if no accounts are available or if the Ethereum provider's request fails. + * @example + * // ERC20 Transfer - sending 1 USDC to demo.eth + * sendTransaction({ + * to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + * value: '0x0', + * data: '0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240', + * }).then(txHash => console.log(txHash)) + * .catch(error => console.error(error)); + */ export const sendTransaction = async (data: any): Promise => { try { const [from] = (await window.ethereum.request({ diff --git a/packages/snap/jest.config.js b/packages/snap/jest.config.js new file mode 100644 index 0000000..f0a22c3 --- /dev/null +++ b/packages/snap/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: '@metamask/snaps-jest', + transform: { + '^.+\\.(t|j)sx?$': 'ts-jest', + }, +}; diff --git a/packages/snap/package.json b/packages/snap/package.json index 0e462d5..a83ef09 100644 --- a/packages/snap/package.json +++ b/packages/snap/package.json @@ -28,6 +28,7 @@ "dependencies": { "@metamask/snaps-types": "^0.32.2", "@metamask/snaps-ui": "^0.32.2", + "@metamask/utils": "^6.2.0", "buffer": "^6.0.3" }, "devDependencies": { diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 62556b6..f6223cb 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/Tenderly/tenderly-metamask-snap-simulate-asset-changes.git" }, "source": { - "shasum": "9Qy94W81xSy0NVW/77DwofrhrQtavXsgyZnvgA6Icbs=", + "shasum": "OXuq1oRKZP51I/dTk9HMvOce1cS9gRkyQXt+lVWpQq4=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/constants.ts b/packages/snap/src/constants.ts new file mode 100644 index 0000000..dce910f --- /dev/null +++ b/packages/snap/src/constants.ts @@ -0,0 +1,6 @@ +enum CustomRequestMethod { + UPDATE_TENDERLY_CREDENTIALS = 'update_tenderly_credentials', + SEND_TENDERLY_TRANSACTION = 'send_tenderly_transaction', +} + +export { CustomRequestMethod }; diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 608c57e..721eded 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -9,6 +9,7 @@ import { handleSendTenderlyTransaction, simulate, } from './tenderly'; +import { CustomRequestMethod } from './constants'; /** * Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`. @@ -22,15 +23,25 @@ import { */ export const onRpcRequest: OnRpcRequestHandler = ({ origin, request }) => { switch (request.method) { - case 'update_tenderly_credentials': + case CustomRequestMethod.UPDATE_TENDERLY_CREDENTIALS: return handleUpdateTenderlyCredentials(origin); - case 'send_tenderly_transaction': + case CustomRequestMethod.SEND_TENDERLY_TRANSACTION: return handleSendTenderlyTransaction(origin); default: throw new Error(`Method ${request.method} not supported.`); } }; +/** + * Handles transactions by providing insights before a transaction is signed. + * This function is a required export for a snap that wishes to interact with MetaMask transactions. + * Whenever there's a contract interaction and a transaction is submitted through MetaMask, this method is invoked. + * The raw unsigned transaction payload is passed as an argument to this handler method. + * + * @param args - The request handler args as object. + * @param args.transaction - The transaction to handle. + * @param args.transactionOrigin - The transaction origin. + */ export const onTransaction: OnTransactionHandler = async ({ transaction, transactionOrigin, @@ -44,7 +55,10 @@ export const onTransaction: OnTransactionHandler = async ({ }; } - const simulationResponse = await simulate(transaction, transactionOrigin); + const simulationResponse = await simulate( + transaction, + transactionOrigin || '', + ); return { content: { diff --git a/packages/snap/src/tenderly/credentials-access.ts b/packages/snap/src/tenderly/credentials-access.ts index 59d7753..906ba80 100644 --- a/packages/snap/src/tenderly/credentials-access.ts +++ b/packages/snap/src/tenderly/credentials-access.ts @@ -2,15 +2,15 @@ import { panel, text, heading } from '@metamask/snaps-ui'; import { requestSnapPrompt } from './utils'; export type TenderlyCredentials = { + accountId: string; projectId: string; - userId: string; - accessKey: string; + accessToken: string; }; /** * Fetches the credentials associated with Tenderly project. * - * @param origin - The origin of the request + * @param origin - The origin of the request. */ export async function fetchCredentials( origin: string, @@ -33,7 +33,7 @@ export async function fetchCredentials( /** * Updates the credentials associated with Tenderly project. * - * @param origin - The origin of the request + * @param origin - The origin of the request. */ export async function handleUpdateTenderlyCredentials(origin: string) { const tenderlyAccess = await requestNewTenderlyCredentials(origin); @@ -50,7 +50,7 @@ export async function handleUpdateTenderlyCredentials(origin: string) { /** * Requests the new Tenderly credentials. * - * @param origin - The origin of the request + * @param origin - The origin of the request. */ async function requestNewTenderlyCredentials( origin: string, @@ -61,31 +61,31 @@ async function requestNewTenderlyCredentials( throw new Error('Request for new Tenderly access failed; missing input'); } - const [userId, projectId, accessKey] = credentialsRaw.split('@'); + const [accountId, projectId, accessToken] = credentialsRaw.split('@'); - if (!userId || !projectId || !accessKey) { + if (!accountId || !projectId || !accessToken) { throw new Error('Request for new Tenderly access failed; invalid input'); } return { - userId, + accountId, projectId, - accessKey, + accessToken, }; } /** * Requests the Tenderly credentials. * - * @param origin - The origin of the request + * @param origin - The origin of the request. */ async function requestCredentials(origin: string): Promise { return requestSnapPrompt( panel([ heading(`${origin} wants to add credentials from Tenderly`), text('Enter your Tenderly credentials in format:'), - text('**{user_id}@{project_id}@{access_key}**'), + text('**{account_id}@{project_id}@{access_token}**'), ]), - 'userId@projectId@accessKey', + 'accountId@projectId@accessToken', ); } diff --git a/packages/snap/src/tenderly/formatter.ts b/packages/snap/src/tenderly/formatter.ts index 25014cf..4c3b7ff 100644 --- a/packages/snap/src/tenderly/formatter.ts +++ b/packages/snap/src/tenderly/formatter.ts @@ -10,9 +10,13 @@ import { arrMakeUnique, makeAddressFormatters } from './utils'; import { TenderlyCredentials } from './credentials-access'; /** + * This function receives the raw data and credentials of a Tenderly project simulation, + * calls the individual formatter functions for each relevant section + * (like balance changes, output value, asset changes, etc.) and returns a panel with all the formatted outputs. * - * @param data - * @param credentials + * @param data - Simulation API data. + * @param credentials - Tenderly credentials object. + * @returns Panel with formatted values. */ export function formatResponse( data: any, @@ -40,10 +44,13 @@ export function formatResponse( } /** + * This function generates a panel showing balance changes for each account involved in the transaction. + * If there are no balance changes, it simply informs the user. * - * @param data - * @param options0 - * @param options0.formatAddress + * @param data - Simulation API data. + * @param formatters - Formatters value from makeAddressFormatters(). + * @param formatters.formatAddress - Function that formats an address. + * @returns Panel outputs with balance diff. */ function formatBalanceDiff(data: any, { formatAddress }: any): Component[] { const panelOutputs: Component[] = [heading('Balance changes:')]; @@ -69,10 +76,13 @@ function formatBalanceDiff(data: any, { formatAddress }: any): Component[] { } /** + * This function creates a panel that presents the output values of the transaction, if any exist. + * It also decodes the output, if possible. * - * @param data - * @param options0 - * @param options0.formatAddressesWithinStr + * @param data - Simulation API data. + * @param formatters - Formatters value from makeAddressFormatters(). + * @param formatters.formatAddressesWithinStr - Function that formats an address within a string. + * @returns Panel outputs with decoded values. */ function formatOutputValue( data: any, @@ -105,8 +115,11 @@ function formatOutputValue( } /** + * This function formats a panel to show any changes to assets, differentiating between ERC20, ERC721, and other changes. + * If there are no changes, it informs the user. * - * @param data + * @param data - Simulation API data. + * @returns Panel outputs with asset changes. */ function formatAssetChanges(data: any): Component[] { const panelOutputs: Component[] = [heading('Asset Changes:')]; @@ -179,9 +192,12 @@ function formatAssetChanges(data: any): Component[] { } /** + * This function creates a panel that lists any changes to storage that occurred during the transaction. + * It uniquely formats addresses and nested data structures for clarity. * - * @param data - * @param formatters + * @param data - Simulation API data. + * @param formatters - Formatters value from makeAddressFormatters(). + * @returns Panel outputs with storage changes. */ function formatStorageChanges(data: any, formatters: any): Component[] { const { formatAddress, formatAddressesWithinStr } = formatters; @@ -201,7 +217,6 @@ function formatStorageChanges(data: any, formatters: any): Component[] { const storageChanges = stateDiff.filter((d: any) => d.address === contract); storageChanges.forEach((diff: any) => { - // todo: support raw format here! if (diff.soltype) { panelOutputs.push( text(`▸ **${diff.soltype.name}[${diff.soltype.type}]:**`), @@ -223,9 +238,12 @@ function formatStorageChanges(data: any, formatters: any): Component[] { } /** + * This function presents the event logs, if they exist, for each transaction. + * The logs are formatted for readability and include input values. * - * @param data - * @param formatters + * @param data - Simulation API data. + * @param formatters - Formatters value from makeAddressFormatters(). + * @returns Panel outputs with event logs. */ function formatEventLogs(data: any, formatters: any): Component[] { const { formatAddress, formatAddressesWithinStr } = formatters; @@ -264,14 +282,18 @@ function formatEventLogs(data: any, formatters: any): Component[] { } /** + * This function produces a formatted visual hierarchy of call traces, showing nested calls recursively. * - * @param data + * @param data - Simulation API data. + * @returns Panel outputs with call trace. */ function formatCallTrace(data: any): Component[] { /** + * ShowS nested calls recursively. * - * @param calls - * @param iter + * @param calls - Trace calls. + * @param iter - Indentation. + * @returns Call trace lines. */ function formatCallsRecursive(calls: any, iter = 0): Component[] { let lines: Component[] = []; @@ -300,15 +322,17 @@ function formatCallTrace(data: any): Component[] { } /** + * This function returns a link to the full details of the simulation on the Tenderly Dashboard, and a separate shareable link. * - * @param data - * @param credentials + * @param data - Simulation API data. + * @param credentials - Tenderly credentials object. + * @returns Panel with simulation outputs. */ export function formatSimulationUrl( data: any, credentials: TenderlyCredentials, ): Component[] { - const simulationUrl = `https://dashboard.tenderly.co/${credentials.userId}/${credentials.projectId}/simulator/${data.simulation?.id}`; + const simulationUrl = `https://dashboard.tenderly.co/${credentials.accountId}/${credentials.projectId}/simulator/${data.simulation?.id}`; const sharedSimulationUrl = `https://dashboard.tenderly.co/shared/simulation/${data.simulation?.id}`; return [ diff --git a/packages/snap/src/tenderly/simulation.ts b/packages/snap/src/tenderly/simulation.ts index 0636d2a..91cbe3a 100644 --- a/packages/snap/src/tenderly/simulation.ts +++ b/packages/snap/src/tenderly/simulation.ts @@ -7,7 +7,7 @@ import { hex2int, requestSnapPrompt } from './utils'; /** * Updates the credentials associated with Tenderly project. * - * @param origin - The origin of the request + * @param origin - The origin of the request. */ export async function handleSendTenderlyTransaction(origin: string) { return requestSnapPrompt( @@ -20,8 +20,13 @@ export async function handleSendTenderlyTransaction(origin: string) { } /** + * This is the main function that handles the simulation of a transaction. + * It fetches the credentials required for the Tenderly simulation, submits the transaction data to the Tenderly API, + * handles any errors returned by the API, and if there are no errors, + * formats the response received from the Tenderly API for output. * - * @param transactionOrigin + * @param transaction - The transaction to simulate. + * @param transactionOrigin - The origin of the transaction. */ export async function simulate( transaction: { [key: string]: Json }, @@ -30,7 +35,7 @@ export async function simulate( const credentials = await fetchCredentials(transactionOrigin); if (!credentials) { - return panel([text('🚨 Tenderly access key updated. Please try again.')]); + return panel([text('🚨 Tenderly access token updated. Please try again.')]); } const simulationResponse = await submitSimulation(transaction, credentials); @@ -40,8 +45,12 @@ export async function simulate( } /** + * This function sends a request to the Tenderly API to simulate a transaction. + * It prepares the transaction data, sends it to the API, and if the simulation is successful, + * it makes the simulation publicly accessible. * - * @param credentials + * @param transaction - The transaction to simulate. + * @param credentials - Tenderly credentials object. */ async function submitSimulation( transaction: { [key: string]: Json }, @@ -49,7 +58,7 @@ async function submitSimulation( ) { const chainId = await ethereum.request({ method: 'eth_chainId' }); const response = await fetch( - `https://api.tenderly.co/api/v1/account/${credentials.userId}/project/${credentials.projectId}/simulate`, + `https://api.tenderly.co/api/v1/account/${credentials.accountId}/project/${credentials.projectId}/simulate`, { method: 'POST', body: JSON.stringify({ @@ -68,7 +77,7 @@ async function submitSimulation( }), headers: { 'Content-Type': 'application/json', - 'X-Access-Key': credentials.accessKey, + 'X-Access-Key': credentials.accessToken, }, }, ); @@ -78,12 +87,12 @@ async function submitSimulation( // Make the simulation publicly accessible if (parsedResponse?.simulation?.id) { await fetch( - `https://api.tenderly.co/api/v1/account/${credentials.userId}/project/${credentials.projectId}/simulations/${parsedResponse.simulation.id}/share`, + `https://api.tenderly.co/api/v1/account/${credentials.accountId}/project/${credentials.projectId}/simulations/${parsedResponse.simulation.id}/share`, { method: 'POST', headers: { 'Content-Type': 'application/json', - 'X-Access-Key': credentials.accessKey, + 'X-Access-Key': credentials.accessToken, }, }, ); @@ -93,9 +102,13 @@ async function submitSimulation( } /** + * This function handles any errors that might occur during the simulation of the transaction. + * It checks if a transaction or error message is included in the data returned from the simulation, + * and if an error is found, it creates a formatted error response. * - * @param data - * @param credentials + * @param data - Simulation API response. + * @param credentials - Tenderly credentials object. + * @returns Panel - MetaMask Snap panel. */ function catchError(data: any, credentials: TenderlyCredentials): Panel | null { if (!data.transaction) { diff --git a/packages/snap/src/tenderly/utils.ts b/packages/snap/src/tenderly/utils.ts index b64a19a..d599968 100644 --- a/packages/snap/src/tenderly/utils.ts +++ b/packages/snap/src/tenderly/utils.ts @@ -2,8 +2,10 @@ import { Panel } from '@metamask/snaps-ui'; import { Json } from '@metamask/utils'; /** + * Converts hex value to integer. * - * @param hex + * @param hex - Hex value. + * @returns Integer value. */ export function hex2int(hex: string | Json): number | null { return hex ? parseInt(hex.toString(), 16) : null; @@ -16,7 +18,7 @@ export function hex2int(hex: string | Json): number | null { * @param r */ export function strReplaceAll(o: string, s: string, r: string): string { - return o.replace(new RegExp(s, 'g'), r); + return o.replace(new RegExp(s, 'gu'), r); } /** diff --git a/yarn.lock b/yarn.lock index b7f7fed..bdfab62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1599,6 +1599,16 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/common@npm:^3.2.0": + version: 3.2.0 + resolution: "@ethereumjs/common@npm:3.2.0" + dependencies: + "@ethereumjs/util": ^8.1.0 + crc-32: ^1.2.0 + checksum: cb9cc11f5c868cb577ba611cebf55046e509218bbb89b47ccce010776dafe8256d70f8f43fab238aec74cf71f62601cd5842bc03a83261200802de365732a14b + languageName: node + linkType: hard + "@ethereumjs/rlp@npm:^4.0.1": version: 4.0.1 resolution: "@ethereumjs/rlp@npm:4.0.1" @@ -1627,6 +1637,18 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/tx@npm:^4.1.2": + version: 4.2.0 + resolution: "@ethereumjs/tx@npm:4.2.0" + dependencies: + "@ethereumjs/common": ^3.2.0 + "@ethereumjs/rlp": ^4.0.1 + "@ethereumjs/util": ^8.1.0 + ethereum-cryptography: ^2.0.0 + checksum: 87a3f5f2452cfbf6712f8847525a80c213210ed453c211c793c5df801fe35ecef28bae17fadd222fcbdd94277478a47e52d2b916a90a6b30cda21f1e0cdaee42 + languageName: node + linkType: hard + "@ethereumjs/util@npm:^8.0.5": version: 8.0.5 resolution: "@ethereumjs/util@npm:8.0.5" @@ -1638,6 +1660,17 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/util@npm:^8.1.0": + version: 8.1.0 + resolution: "@ethereumjs/util@npm:8.1.0" + dependencies: + "@ethereumjs/rlp": ^4.0.1 + ethereum-cryptography: ^2.0.0 + micro-ftch: ^0.3.1 + checksum: 9ae5dee8f12b0faf81cd83f06a41560e79b0ba96a48262771d897a510ecae605eb6d84f687da001ab8ccffd50f612ae50f988ef76e6312c752897f462f3ac08d + languageName: node + linkType: hard + "@ethersproject/abstract-provider@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abstract-provider@npm:5.7.0" @@ -2785,6 +2818,20 @@ __metadata: languageName: node linkType: hard +"@metamask/utils@npm:^6.2.0": + version: 6.2.0 + resolution: "@metamask/utils@npm:6.2.0" + dependencies: + "@ethereumjs/tx": ^4.1.2 + "@noble/hashes": ^1.3.1 + "@types/debug": ^4.1.7 + debug: ^4.3.4 + semver: ^7.3.8 + superstruct: ^1.0.3 + checksum: 0bc675358ecc09b3bc04da613d73666295d7afa51ff6b8554801585966900b24b8545bd93b8b2e9a17db867ebe421fe884baf3558ec4ca3199fa65504f677c1b + languageName: node + linkType: hard + "@mischnic/json-sourcemap@npm:^0.1.0": version: 0.1.0 resolution: "@mischnic/json-sourcemap@npm:0.1.0" @@ -2847,6 +2894,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.1.0, @noble/curves@npm:~1.1.0": + version: 1.1.0 + resolution: "@noble/curves@npm:1.1.0" + dependencies: + "@noble/hashes": 1.3.1 + checksum: 2658cdd3f84f71079b4e3516c47559d22cf4b55c23ac8ee9d2b1f8e5b72916d9689e59820e0f9d9cb4a46a8423af5b56dc6bb7782405c88be06a015180508db5 + languageName: node + linkType: hard + "@noble/ed25519@npm:^1.6.0": version: 1.7.3 resolution: "@noble/ed25519@npm:1.7.3" @@ -2861,6 +2917,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.3.1, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.1": + version: 1.3.1 + resolution: "@noble/hashes@npm:1.3.1" + checksum: 7fdefc0f7a0c1ec27acc6ff88841793e3f93ec4ce6b8a6a12bfc0dd70ae6b7c4c82fe305fdfeda1735d5ad4a9eebe761e6693b3d355689c559e91242f4bc95b1 + languageName: node + linkType: hard + "@noble/hashes@npm:^1.0.0": version: 1.3.0 resolution: "@noble/hashes@npm:1.3.0" @@ -3393,6 +3456,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.3.1": + version: 1.3.1 + resolution: "@scure/bip32@npm:1.3.1" + dependencies: + "@noble/curves": ~1.1.0 + "@noble/hashes": ~1.3.1 + "@scure/base": ~1.1.0 + checksum: 394d65f77a40651eba21a5096da0f4233c3b50d422864751d373fcf142eeedb94a1149f9ab1dbb078086dab2d0bc27e2b1afec8321bf22d4403c7df2fea5bfe2 + languageName: node + linkType: hard + "@scure/bip39@npm:1.1.1": version: 1.1.1 resolution: "@scure/bip39@npm:1.1.1" @@ -3403,6 +3477,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.2.1": + version: 1.2.1 + resolution: "@scure/bip39@npm:1.2.1" + dependencies: + "@noble/hashes": ~1.3.0 + "@scure/base": ~1.1.0 + checksum: c5bd6f1328fdbeae2dcdd891825b1610225310e5e62a4942714db51066866e4f7bef242c7b06a1b9dcc8043a4a13412cf5c5df76d3b10aa9e36b82e9b6e3eeaa + languageName: node + linkType: hard + "@sideway/address@npm:^4.1.3": version: 4.1.4 resolution: "@sideway/address@npm:4.1.4" @@ -3694,6 +3778,7 @@ __metadata: "@metamask/snaps-cli": ^0.32.2 "@metamask/snaps-types": ^0.32.2 "@metamask/snaps-ui": ^0.32.2 + "@metamask/utils": ^6.2.0 "@typescript-eslint/eslint-plugin": ^5.33.0 "@typescript-eslint/parser": ^5.33.0 buffer: ^6.0.3 @@ -8603,6 +8688,18 @@ __metadata: languageName: node linkType: hard +"ethereum-cryptography@npm:^2.0.0": + version: 2.1.2 + resolution: "ethereum-cryptography@npm:2.1.2" + dependencies: + "@noble/curves": 1.1.0 + "@noble/hashes": 1.3.1 + "@scure/bip32": 1.3.1 + "@scure/bip39": 1.2.1 + checksum: 2e8f7b8cc90232ae838ab6a8167708e8362621404d26e79b5d9e762c7b53d699f7520aff358d9254de658fcd54d2d0af168ff909943259ed27dc4cef2736410c + languageName: node + linkType: hard + "ethereumjs-util@npm:^7.0.10": version: 7.1.5 resolution: "ethereumjs-util@npm:7.1.5" @@ -12150,6 +12247,13 @@ __metadata: languageName: node linkType: hard +"micro-ftch@npm:^0.3.1": + version: 0.3.1 + resolution: "micro-ftch@npm:0.3.1" + checksum: 0e496547253a36e98a83fb00c628c53c3fb540fa5aaeaf718438873785afd193244988c09d219bb1802984ff227d04938d9571ef90fe82b48bd282262586aaff + languageName: node + linkType: hard + "micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5"