Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/onchaintrust-snap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onchaintrust/onchaintrust-snap",
"version": "0.5.1",
"version": "1.0.0",
"description": "OnChainTrust - Bringing Trust To Cryptocurrency Transactions",
"repository": {
"type": "git",
Expand Down Expand Up @@ -34,8 +34,6 @@
"devDependencies": {
"@metamask/snaps-cli": "^8.2.0",
"@metamask/snaps-jest": "^9.4.0",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"eslint": "^9.33.0",
"jest": "^30.0.5",
"prettier": "^3.6.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/onchaintrust-snap/snap.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SnapConfig } from '@metamask/snaps-cli';
import { resolve } from 'path';

const config: SnapConfig = {
input: resolve(__dirname, 'src/index.ts'),
input: resolve(__dirname, 'src/index.tsx'),
server: {
port: 8080,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/onchaintrust-snap/snap.manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"version": "0.5.1",
"version": "1.0.0",
"description": "Community-powered security for on-chain transactions: recipient / smart contract owner information on the transaction confirmation screen, protection against phishing and frontend attacks, and more.",
"proposedName": "OnChainTrust",
"repository": {
"type": "git",
"url": "https://github.com/OnChainTrust/onchaintrust-snap.git"
},
"source": {
"shasum": "D7v/eNuK0/xBL3UBmYy4go2l3Tkt4frOauA4CTdv2tE=",
"shasum": "4R94xJE4i6Ib4uak8kLXZH9mM+b2AApRI/rA3aej21s=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
66 changes: 0 additions & 66 deletions packages/onchaintrust-snap/src/index.test.ts

This file was deleted.

56 changes: 56 additions & 0 deletions packages/onchaintrust-snap/src/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { installSnap } from '@metamask/snaps-jest';
import { Box, Text, Heading } from '@metamask/snaps-sdk/jsx';

describe('onTransaction handler tests (JSX UI, live server)', () => {
describe('when address is verified', () => {
it('should display UI components correctly', async () => {
const snap: any = await installSnap();
const recipientAddress = '0x00000000000000000000000000000000f0cacc1a';

const response = await snap.onTransaction({
to: recipientAddress,
origin: 'https://example.com',
});

const screen = response.getInterface();

expect(screen).toRender(
<Box>
<Text key="el-0">✅ Verified address</Text>
<Heading key="el-1">Example Corp LTD</Heading>
<Text key="el-2">LEI: 1234567890</Text>
<Text key="el-3">Email: example@example.com</Text>
<Text key="el-4">Message: Hello there</Text>
</Box>,
);
});
});

describe('when address is malicious', () => {
it('should display UI components correctly', async () => {
const snap: any = await installSnap();
const recipientAddress = '0x00000000000000000000000000000000f00dbabe';

const response = await snap.onTransaction({
to: recipientAddress,
origin: 'https://example.com',
});

const screen = response.getInterface();

expect(screen).toRender(
<Box>
<Heading key="el-0">
Security Alert: Potentially Unsafe Action Detected!
</Heading>
<Text key="el-1">
🚫 STOP: Your transaction is directed towards an address that has
been flagged for suspicious activity. Engaging with this address may
result in the loss of your digital assets or compromise your
personal security.
</Text>
</Box>,
);
});
});
});
104 changes: 0 additions & 104 deletions packages/onchaintrust-snap/src/index.ts

This file was deleted.

82 changes: 82 additions & 0 deletions packages/onchaintrust-snap/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import type { OnTransactionHandler } from '@metamask/snaps-sdk';
import { SeverityLevel } from '@metamask/snaps-sdk';
import {
Box,
Heading,
Text,
Divider,
Copyable,
Image,
} from '@metamask/snaps-sdk/jsx';

type ElementDefinition = { type: string; value?: string };

const requestUiDefinition = async (
address: string,
transactionOrigin: string,
chainId: string,
): Promise<{ ui: ElementDefinition[]; severity?: 'critical' | string }> => {
const baseUrl = 'https://app.onchaintrust.org/api/getAddressInfo';
const uri = new URL(baseUrl);
uri.searchParams.append('address', address);
uri.searchParams.append('origin', transactionOrigin);
uri.searchParams.append('chain_id', chainId);
uri.searchParams.append('client', 'metamask');

try {
const res = await fetch(uri);
if (!res.ok) {
throw new Error('Bad response from server');
}
return await res.json();
} catch (error) {
console.error('UI fetch failed:', error);
return {
ui: [
{ type: 'heading', value: 'Error' },
{ type: 'text', value: 'An error occurred, please try again later' },
],
};
}
};

const renderElement = (el: ElementDefinition, idx: number) => {
const k = `el-${idx}`;
switch (el.type) {
case 'heading':
return el.value ? <Heading key={k}>{el.value}</Heading> : null;
case 'text':
return el.value ? <Text key={k}>{el.value}</Text> : null;
case 'divider':
return <Divider />;
Copy link

Copilot AI Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Divider component is missing a key prop, which will cause React warnings when rendered in a list. Add key={k} to maintain consistency with other elements.

Suggested change
return <Divider />;
return <Divider key={k} />;

Copilot uses AI. Check for mistakes.
case 'copyable':
return el.value ? <Copyable key={k} value={el.value} /> : null;
case 'image':
return el.value ? <Image key={k} src={el.value} alt="" /> : null;
default:
return null;
}
};

// Handle outgoing transactions (Transaction Insights)
export const onTransaction: OnTransactionHandler = async ({
transactionOrigin,
chainId,
transaction,
}) => {
const apiResponse = await requestUiDefinition(
transaction.to ?? '',
transactionOrigin ?? '',
chainId,
);

const content = (
<Box>{apiResponse.ui?.map((el, i) => renderElement(el, i))}</Box>
);
const result =
apiResponse.severity === 'critical'
? { content, severity: SeverityLevel.Critical }
: { content };

return result;
};
2 changes: 0 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4037,8 +4037,6 @@ __metadata:
"@metamask/snaps-cli": ^8.2.0
"@metamask/snaps-jest": ^9.4.0
"@metamask/snaps-sdk": 9.2.0
"@types/react": ^19.1.10
"@types/react-dom": ^19.1.7
buffer: ^6.0.3
eslint: ^9.33.0
jest: ^30.0.5
Expand Down
Loading