@portal-hq/web 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import { BlockaidAddressScanRequest, BlockaidAddressScanResponse, BlockaidBulkTokenScanRequest, BlockaidBulkTokenScanResponse, BlockaidScanEvmTxRequest, BlockaidScanEvmTxResponse, BlockaidScanSolanaTxRequest, BlockaidScanSolanaTxResponse, BlockaidSiteScanRequest, BlockaidSiteScanResponse } from 'src/shared/types'
1
2
  import type { ClientResponse } from '../../types'
2
3
  import { BackupMethods, PortalCurve, ChainNamespace } from '../index'
3
4
 
@@ -1729,3 +1730,205 @@ export const mockScanUrlResponse = {
1729
1730
  },
1730
1731
  },
1731
1732
  }
1733
+
1734
+ // Blockaid mock data
1735
+ export const mockBlockaidScanEvmTxRequest = {
1736
+ chain: 'ethereum',
1737
+ data: {
1738
+ from: '0x1234567890123456789012345678901234567890',
1739
+ to: '0x0987654321098765432109876543210987654321',
1740
+ data: '0xabcdef',
1741
+ value: '1000000000000000000',
1742
+ },
1743
+ metadata: {
1744
+ domain: 'https://example.com',
1745
+ },
1746
+ account_address: '0x1234567890123456789012345678901234567890',
1747
+ options: ['validation', 'simulation'],
1748
+ } as BlockaidScanEvmTxRequest
1749
+
1750
+ export const mockBlockaidScanEvmTxResponse = {
1751
+ data: {
1752
+ rawResponse: {
1753
+ validation: {
1754
+ classification: 'benign',
1755
+ description: 'This transaction appears safe',
1756
+ features: [
1757
+ {
1758
+ type: 'Benign',
1759
+ feature_id: 'safe_transfer',
1760
+ description: 'Standard ETH transfer',
1761
+ },
1762
+ ],
1763
+ reason: 'Standard transfer',
1764
+ result_type: 'Benign',
1765
+ status: 'Success',
1766
+ },
1767
+ simulation: {
1768
+ account_address: '0x1234567890123456789012345678901234567890',
1769
+ account_summary: {},
1770
+ address_details: {},
1771
+ assets_diffs: {},
1772
+ block: 18500000,
1773
+ chain: 'ethereum',
1774
+ exposures: {},
1775
+ status: 'Success',
1776
+ total_usd_diff: {},
1777
+ total_usd_exposure: {},
1778
+ transaction_action: 'transfer',
1779
+ session_key: {},
1780
+ },
1781
+ block: '18500000',
1782
+ chain: 'ethereum',
1783
+ account_address: '0x1234567890123456789012345678901234567890',
1784
+ },
1785
+ },
1786
+ } as BlockaidScanEvmTxResponse
1787
+
1788
+ export const mockBlockaidScanSolanaTxRequest = {
1789
+ account_address: 'CqQMFUCEMbK9Cp9yMonmthKqzc59Ta48JpZMZsh1bDqf',
1790
+ transactions: ['base64encodedtransaction'],
1791
+ metadata: {
1792
+ url: 'https://example.com',
1793
+ },
1794
+ chain: 'mainnet',
1795
+ options: ['validation', 'simulation'],
1796
+ } as BlockaidScanSolanaTxRequest
1797
+
1798
+ export const mockBlockaidScanSolanaTxResponse = {
1799
+ data: {
1800
+ rawResponse: {
1801
+ encoding: 'base64',
1802
+ status: 'Success',
1803
+ request_id: 'test-request-id',
1804
+ result: {
1805
+ validation: {
1806
+ features: [],
1807
+ reason: 'Standard transaction',
1808
+ result_type: 'Benign',
1809
+ },
1810
+ simulation: {
1811
+ account_summary: {
1812
+ account_assets_diff: [],
1813
+ },
1814
+ accounts_details: [],
1815
+ assets_diff: {},
1816
+ assets_ownership_diff: {},
1817
+ delegations: {},
1818
+ },
1819
+ },
1820
+ },
1821
+ },
1822
+ } as BlockaidScanSolanaTxResponse
1823
+
1824
+ export const mockBlockaidScanAddressRequest = {
1825
+ chain: 'ethereum',
1826
+ address: '0x1234567890123456789012345678901234567890',
1827
+ metadata: {
1828
+ domain: 'https://example.com',
1829
+ },
1830
+ } as BlockaidAddressScanRequest
1831
+
1832
+ export const mockBlockaidScanAddressResponse = {
1833
+ data: {
1834
+ rawResponse: {
1835
+ result_type: 'Benign',
1836
+ features: [
1837
+ {
1838
+ type: 'Benign',
1839
+ feature_id: 'verified_contract',
1840
+ description: 'Verified contract on Etherscan',
1841
+ },
1842
+ ],
1843
+ },
1844
+ },
1845
+ } as BlockaidAddressScanResponse
1846
+
1847
+ export const mockBlockaidScanTokensRequest = {
1848
+ chain: 'ethereum',
1849
+ tokens: [
1850
+ '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
1851
+ '0xdac17f958d2ee523a2206206994597c13d831ec7',
1852
+ ],
1853
+ metadata: {
1854
+ domain: 'https://example.com',
1855
+ },
1856
+ } as BlockaidBulkTokenScanRequest
1857
+
1858
+ export const mockBlockaidScanTokensResponse = {
1859
+ data: {
1860
+ rawResponse: {
1861
+ results: {
1862
+ '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': {
1863
+ result_type: 'Benign',
1864
+ malicious_score: '0',
1865
+ attack_types: {},
1866
+ chain: 'ethereum',
1867
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
1868
+ metadata: {
1869
+ type: 'ERC20',
1870
+ name: 'USD Coin',
1871
+ symbol: 'USDC',
1872
+ decimals: 6,
1873
+ },
1874
+ fees: {},
1875
+ trading_limits: {},
1876
+ financial_stats: {
1877
+ holders_count: 1000000,
1878
+ },
1879
+ },
1880
+ '0xdac17f958d2ee523a2206206994597c13d831ec7': {
1881
+ result_type: 'Benign',
1882
+ malicious_score: '0',
1883
+ attack_types: {},
1884
+ chain: 'ethereum',
1885
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
1886
+ metadata: {
1887
+ type: 'ERC20',
1888
+ name: 'Tether USD',
1889
+ symbol: 'USDT',
1890
+ decimals: 6,
1891
+ },
1892
+ fees: {},
1893
+ trading_limits: {},
1894
+ financial_stats: {
1895
+ holders_count: 2000000,
1896
+ },
1897
+ },
1898
+ },
1899
+ },
1900
+ },
1901
+ } as BlockaidBulkTokenScanResponse
1902
+
1903
+ export const mockBlockaidScanUrlRequest = {
1904
+ url: 'https://example.com',
1905
+ metadata: {
1906
+ type: 'catalog',
1907
+ },
1908
+ } as BlockaidSiteScanRequest
1909
+
1910
+ export const mockBlockaidScanUrlResponse = {
1911
+ data: {
1912
+ rawResponse: {
1913
+ status: 'hit',
1914
+ url: 'https://example.com',
1915
+ scan_start_time: '2024-01-01T00:00:00Z',
1916
+ scan_end_time: '2024-01-01T00:00:01Z',
1917
+ malicious_score: 0,
1918
+ is_reachable: true,
1919
+ is_web3_site: true,
1920
+ is_malicious: false,
1921
+ attack_types: {},
1922
+ network_operations: [],
1923
+ json_rpc_operations: [],
1924
+ contract_write: {
1925
+ contract_addresses: [],
1926
+ functions: {},
1927
+ },
1928
+ contract_read: {
1929
+ contract_addresses: [],
1930
+ functions: {},
1931
+ },
1932
+ },
1933
+ },
1934
+ } as BlockaidSiteScanResponse
@@ -0,0 +1,146 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+
5
+ import Blockaid from '.'
6
+ import Mpc from '../../../mpc'
7
+ import portalMock from '../../../__mocks/portal/portal'
8
+ import {
9
+ mockHost,
10
+ mockBlockaidScanEvmTxRequest,
11
+ mockBlockaidScanEvmTxResponse,
12
+ mockBlockaidScanSolanaTxRequest,
13
+ mockBlockaidScanSolanaTxResponse,
14
+ mockBlockaidScanAddressRequest,
15
+ mockBlockaidScanAddressResponse,
16
+ mockBlockaidScanTokensRequest,
17
+ mockBlockaidScanTokensResponse,
18
+ mockBlockaidScanUrlRequest,
19
+ mockBlockaidScanUrlResponse,
20
+ } from '../../../__mocks/constants'
21
+
22
+ describe('Blockaid', () => {
23
+ let blockaid: Blockaid
24
+ let mpc: Mpc
25
+
26
+ beforeEach(() => {
27
+ jest.clearAllMocks()
28
+
29
+ portalMock.host = mockHost
30
+ mpc = new Mpc({
31
+ portal: portalMock,
32
+ })
33
+
34
+ blockaid = new Blockaid({ mpc })
35
+ })
36
+
37
+ describe('scanEVMTx', () => {
38
+ it('should call mpc.blockaidScanEvmTx with the correct arguments', async () => {
39
+ const spy = jest
40
+ .spyOn(mpc, 'blockaidScanEvmTx')
41
+ .mockResolvedValue(mockBlockaidScanEvmTxResponse)
42
+
43
+ const result = await blockaid.scanEVMTx(mockBlockaidScanEvmTxRequest)
44
+
45
+ expect(spy).toHaveBeenCalledWith(mockBlockaidScanEvmTxRequest)
46
+ expect(result).toEqual(mockBlockaidScanEvmTxResponse)
47
+ })
48
+
49
+ it('should propagate errors from mpc.blockaidScanEvmTx', async () => {
50
+ const error = new Error('Test error')
51
+ jest.spyOn(mpc, 'blockaidScanEvmTx').mockRejectedValue(error)
52
+
53
+ await expect(
54
+ blockaid.scanEVMTx(mockBlockaidScanEvmTxRequest),
55
+ ).rejects.toThrow('Test error')
56
+ })
57
+ })
58
+
59
+ describe('scanSolanaTx', () => {
60
+ it('should call mpc.blockaidScanSolanaTx with the correct arguments', async () => {
61
+ const spy = jest
62
+ .spyOn(mpc, 'blockaidScanSolanaTx')
63
+ .mockResolvedValue(mockBlockaidScanSolanaTxResponse)
64
+
65
+ const result = await blockaid.scanSolanaTx(mockBlockaidScanSolanaTxRequest)
66
+
67
+ expect(spy).toHaveBeenCalledWith(mockBlockaidScanSolanaTxRequest)
68
+ expect(result).toEqual(mockBlockaidScanSolanaTxResponse)
69
+ })
70
+
71
+ it('should propagate errors from mpc.blockaidScanSolanaTx', async () => {
72
+ const error = new Error('Test error')
73
+ jest.spyOn(mpc, 'blockaidScanSolanaTx').mockRejectedValue(error)
74
+
75
+ await expect(
76
+ blockaid.scanSolanaTx(mockBlockaidScanSolanaTxRequest),
77
+ ).rejects.toThrow('Test error')
78
+ })
79
+ })
80
+
81
+ describe('scanAddress', () => {
82
+ it('should call mpc.blockaidScanAddress with the correct arguments', async () => {
83
+ const spy = jest
84
+ .spyOn(mpc, 'blockaidScanAddress')
85
+ .mockResolvedValue(mockBlockaidScanAddressResponse)
86
+
87
+ const result = await blockaid.scanAddress(mockBlockaidScanAddressRequest)
88
+
89
+ expect(spy).toHaveBeenCalledWith(mockBlockaidScanAddressRequest)
90
+ expect(result).toEqual(mockBlockaidScanAddressResponse)
91
+ })
92
+
93
+ it('should propagate errors from mpc.blockaidScanAddress', async () => {
94
+ const error = new Error('Test error')
95
+ jest.spyOn(mpc, 'blockaidScanAddress').mockRejectedValue(error)
96
+
97
+ await expect(
98
+ blockaid.scanAddress(mockBlockaidScanAddressRequest),
99
+ ).rejects.toThrow('Test error')
100
+ })
101
+ })
102
+
103
+ describe('scanTokens', () => {
104
+ it('should call mpc.blockaidScanTokens with the correct arguments', async () => {
105
+ const spy = jest
106
+ .spyOn(mpc, 'blockaidScanTokens')
107
+ .mockResolvedValue(mockBlockaidScanTokensResponse)
108
+
109
+ const result = await blockaid.scanTokens(mockBlockaidScanTokensRequest)
110
+
111
+ expect(spy).toHaveBeenCalledWith(mockBlockaidScanTokensRequest)
112
+ expect(result).toEqual(mockBlockaidScanTokensResponse)
113
+ })
114
+
115
+ it('should propagate errors from mpc.blockaidScanTokens', async () => {
116
+ const error = new Error('Test error')
117
+ jest.spyOn(mpc, 'blockaidScanTokens').mockRejectedValue(error)
118
+
119
+ await expect(
120
+ blockaid.scanTokens(mockBlockaidScanTokensRequest),
121
+ ).rejects.toThrow('Test error')
122
+ })
123
+ })
124
+
125
+ describe('scanURL', () => {
126
+ it('should call mpc.blockaidScanUrl with the correct arguments', async () => {
127
+ const spy = jest
128
+ .spyOn(mpc, 'blockaidScanUrl')
129
+ .mockResolvedValue(mockBlockaidScanUrlResponse)
130
+
131
+ const result = await blockaid.scanURL(mockBlockaidScanUrlRequest)
132
+
133
+ expect(spy).toHaveBeenCalledWith(mockBlockaidScanUrlRequest)
134
+ expect(result).toEqual(mockBlockaidScanUrlResponse)
135
+ })
136
+
137
+ it('should propagate errors from mpc.blockaidScanUrl', async () => {
138
+ const error = new Error('Test error')
139
+ jest.spyOn(mpc, 'blockaidScanUrl').mockRejectedValue(error)
140
+
141
+ await expect(
142
+ blockaid.scanURL(mockBlockaidScanUrlRequest),
143
+ ).rejects.toThrow('Test error')
144
+ })
145
+ })
146
+ })
@@ -0,0 +1,81 @@
1
+ import Mpc from '../../../mpc'
2
+ import {
3
+ BlockaidScanEvmTxRequest,
4
+ BlockaidScanEvmTxResponse,
5
+ BlockaidScanSolanaTxRequest,
6
+ BlockaidScanSolanaTxResponse,
7
+ BlockaidAddressScanRequest,
8
+ BlockaidAddressScanResponse,
9
+ BlockaidBulkTokenScanRequest,
10
+ BlockaidBulkTokenScanResponse,
11
+ BlockaidSiteScanRequest,
12
+ BlockaidSiteScanResponse,
13
+ } from '../../../shared/types'
14
+
15
+ export default class Blockaid {
16
+ private mpc: Mpc
17
+
18
+ constructor({ mpc }: { mpc: Mpc }) {
19
+ this.mpc = mpc
20
+ }
21
+
22
+ /**
23
+ * Scans an EVM transaction for security risks using Blockaid.
24
+ * @param params - The parameters for the EVM transaction scan request.
25
+ * @returns A `BlockaidScanEvmTxResponse` promise.
26
+ * @throws An error if the operation fails.
27
+ */
28
+ public async scanEVMTx(
29
+ params: BlockaidScanEvmTxRequest,
30
+ ): Promise<BlockaidScanEvmTxResponse> {
31
+ return this.mpc.blockaidScanEvmTx(params)
32
+ }
33
+
34
+ /**
35
+ * Scans a Solana transaction for security risks using Blockaid.
36
+ * @param params - The parameters for the Solana transaction scan request.
37
+ * @returns A `BlockaidScanSolanaTxResponse` promise.
38
+ * @throws An error if the operation fails.
39
+ */
40
+ public async scanSolanaTx(
41
+ params: BlockaidScanSolanaTxRequest,
42
+ ): Promise<BlockaidScanSolanaTxResponse> {
43
+ return this.mpc.blockaidScanSolanaTx(params)
44
+ }
45
+
46
+ /**
47
+ * Scans an address for security risks using Blockaid.
48
+ * @param params - The parameters for the address scan request.
49
+ * @returns A `BlockaidAddressScanResponse` promise.
50
+ * @throws An error if the operation fails.
51
+ */
52
+ public async scanAddress(
53
+ params: BlockaidAddressScanRequest,
54
+ ): Promise<BlockaidAddressScanResponse> {
55
+ return this.mpc.blockaidScanAddress(params)
56
+ }
57
+
58
+ /**
59
+ * Scans tokens for security risks using Blockaid.
60
+ * @param params - The parameters for the token scan request.
61
+ * @returns A `BlockaidBulkTokenScanResponse` promise.
62
+ * @throws An error if the operation fails.
63
+ */
64
+ public async scanTokens(
65
+ params: BlockaidBulkTokenScanRequest,
66
+ ): Promise<BlockaidBulkTokenScanResponse> {
67
+ return this.mpc.blockaidScanTokens(params)
68
+ }
69
+
70
+ /**
71
+ * Scans a URL for malicious content using Blockaid.
72
+ * @param params - The parameters for the URL scan request.
73
+ * @returns A `BlockaidSiteScanResponse` promise.
74
+ * @throws An error if the operation fails.
75
+ */
76
+ public async scanURL(
77
+ params: BlockaidSiteScanRequest,
78
+ ): Promise<BlockaidSiteScanResponse> {
79
+ return this.mpc.blockaidScanUrl(params)
80
+ }
81
+ }
@@ -1,14 +1,17 @@
1
1
  import Mpc from '../../mpc'
2
+ import Blockaid from './blockaid'
2
3
  import Hypernative from './hypernative'
3
4
 
4
5
  /**
5
- * This class is a container for the Hypernative class.
6
+ * This class is a container for the Hypernative and Blockaid classes.
6
7
  * In the future, Security domain logic should be here.
7
8
  */
8
9
  export default class Security {
10
+ public blockaid: Blockaid
9
11
  public hypernative: Hypernative
10
12
 
11
13
  constructor({ mpc }: { mpc: Mpc }) {
14
+ this.blockaid = new Blockaid({ mpc })
12
15
  this.hypernative = new Hypernative({ mpc })
13
16
  }
14
17
  }