Skip to content

Commit

Permalink
feat: update snap
Browse files Browse the repository at this point in the history
  • Loading branch information
dzimiks committed Jul 26, 2023
1 parent 320a2a8 commit d1027ec
Show file tree
Hide file tree
Showing 15 changed files with 267 additions and 72 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<img width="577" alt="image" src="https://github.com/Tenderly/tenderly-metamask-snap-simulate-asset-changes/assets/26412515/0abb39b3-dd2b-4af6-98c4-73c00f4f70f0">

Expand Down Expand Up @@ -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! 💜

Expand Down
4 changes: 2 additions & 2 deletions packages/site/src/components/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const SuccessButton = styled.button`
&:hover {
color: #ffffff;
background-color: #8bc34a;
background-color: #62b966;
}
${({ theme }) => theme.mediaQueries.small} {
Expand Down Expand Up @@ -155,7 +155,7 @@ export const SendFailedTxButton = (props: ComponentProps<typeof Button>) => {
export const UpdateTenderlyAccessKeyButton = (
props: ComponentProps<typeof Button>,
) => {
return <Button {...props}>Add Access Key</Button>;
return <Button {...props}>Add Access Token</Button>;
};

export const GoToDocsButton = () => {
Expand Down
33 changes: 16 additions & 17 deletions packages/site/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
updateTenderlyAccessKey,
sendTransaction,
sendTenderlyTransaction,
// sendSuccessfulTransaction,
sendFailedTransaction,
} from '../utils';
import {
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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: (
<div
style={{
Expand Down Expand Up @@ -205,7 +212,7 @@ const Index = () => {
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: (
<div
style={{
Expand Down Expand Up @@ -255,7 +262,7 @@ const Index = () => {
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: (
<div
style={{
Expand Down Expand Up @@ -287,25 +294,17 @@ const Index = () => {
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: (
<div>
<div>
This example transaction payload will send{' '}
<strong>5 USDC</strong> to demo.eth. Copy it and click on the{' '}
<strong>Send Transaction</strong> button.
</div>
<pre
style={{
padding: '1rem',
backgroundColor: '#e7e7e7',
borderRadius: '4px',
wordBreak: 'break-word',
whiteSpace: 'pre-wrap',
}}
>
{JSON.stringify(successfulTx, null, 2)}
</pre>
<PreContainer>
{JSON.stringify(successfulTxPayload, null, 2)}
</PreContainer>
<SendTxButton
onClick={handleSendTxClick}
disabled={!state.installedSnap}
Expand Down
6 changes: 6 additions & 0 deletions packages/site/src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
enum CustomRequestMethod {
UPDATE_TENDERLY_CREDENTIALS = 'update_tenderly_credentials',
SEND_TENDERLY_TRANSACTION = 'send_tenderly_transaction',
}

export { CustomRequestMethod };
24 changes: 22 additions & 2 deletions packages/site/src/utils/snap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defaultSnapOrigin } from '../config';
import { GetSnapsResponse, Snap } from '../types';
import { CustomRequestMethod } from './constants';

/**
* Get the installed snaps in MetaMask.
Expand Down Expand Up @@ -59,7 +60,7 @@ export const updateTenderlyAccessKey = async (): Promise<any> => {
params: {
snapId: defaultSnapOrigin,
request: {
method: 'update_tenderly_credentials',
method: CustomRequestMethod.UPDATE_TENDERLY_CREDENTIALS,
},
},
});
Expand All @@ -74,12 +75,31 @@ export const sendTenderlyTransaction = async (): Promise<any> => {
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<any> => {
try {
const [from] = (await window.ethereum.request({
Expand Down
6 changes: 6 additions & 0 deletions packages/snap/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
preset: '@metamask/snaps-jest',
transform: {
'^.+\\.(t|j)sx?$': 'ts-jest',
},
};
1 change: 1 addition & 0 deletions packages/snap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions packages/snap/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
enum CustomRequestMethod {
UPDATE_TENDERLY_CREDENTIALS = 'update_tenderly_credentials',
SEND_TENDERLY_TRANSACTION = 'send_tenderly_transaction',
}

export { CustomRequestMethod };
20 changes: 17 additions & 3 deletions packages/snap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
handleSendTenderlyTransaction,
simulate,
} from './tenderly';
import { CustomRequestMethod } from './constants';

/**
* Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`.
Expand All @@ -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,
Expand All @@ -44,7 +55,10 @@ export const onTransaction: OnTransactionHandler = async ({
};
}

const simulationResponse = await simulate(transaction, transactionOrigin);
const simulationResponse = await simulate(
transaction,
transactionOrigin || '',
);

return {
content: {
Expand Down
24 changes: 12 additions & 12 deletions packages/snap/src/tenderly/credentials-access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -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,
Expand All @@ -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<string | null> {
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',
);
}
Loading

0 comments on commit d1027ec

Please sign in to comment.