@portal-hq/web 3.6.2-alpha → 3.7.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.
- package/hypernative.d.ts +346 -0
- package/lib/commonjs/index.js +144 -2
- package/lib/commonjs/index.test.js +119 -2
- package/lib/commonjs/integrations/security/hypernative/index.js +101 -0
- package/lib/commonjs/integrations/security/hypernative/index.test.js +151 -0
- package/lib/commonjs/integrations/security/index.js +16 -0
- package/lib/commonjs/integrations/trading/zero-x/index.js +17 -4
- package/lib/commonjs/integrations/trading/zero-x/index.test.js +61 -15
- package/lib/commonjs/mpc/index.js +156 -5
- package/lib/commonjs/mpc/index.test.js +794 -5
- package/lib/commonjs/passkeys/index.js +394 -0
- package/lib/commonjs/passkeys/types.js +2 -0
- package/lib/commonjs/provider/index.js +5 -2
- package/lib/esm/index.js +144 -2
- package/lib/esm/index.test.js +119 -2
- package/lib/esm/integrations/security/hypernative/index.js +98 -0
- package/lib/esm/integrations/security/hypernative/index.test.js +146 -0
- package/lib/esm/integrations/security/index.js +10 -0
- package/lib/esm/integrations/trading/zero-x/index.js +17 -4
- package/lib/esm/integrations/trading/zero-x/index.test.js +62 -16
- package/lib/esm/mpc/index.js +156 -5
- package/lib/esm/mpc/index.test.js +795 -6
- package/lib/esm/passkeys/index.js +390 -0
- package/lib/esm/passkeys/types.js +1 -0
- package/lib/esm/provider/index.js +5 -2
- package/lifi-types.d.ts +1236 -0
- package/package.json +6 -3
- package/src/__mocks/constants.ts +422 -5
- package/src/__mocks/portal/mpc.ts +1 -0
- package/src/index.test.ts +179 -3
- package/src/index.ts +212 -4
- package/src/integrations/security/hypernative/index.test.ts +196 -0
- package/src/integrations/security/hypernative/index.ts +106 -0
- package/src/integrations/security/index.ts +14 -0
- package/src/integrations/trading/zero-x/index.test.ts +98 -19
- package/src/integrations/trading/zero-x/index.ts +29 -9
- package/src/mpc/index.test.ts +944 -7
- package/src/mpc/index.ts +200 -10
- package/src/passkeys/index.ts +536 -0
- package/src/passkeys/types.ts +78 -0
- package/src/provider/index.ts +5 -0
- package/tsconfig.json +7 -1
- package/types.d.ts +45 -12
- package/yieldxyz-types.d.ts +778 -0
- package/zero-x.d.ts +204 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Portal MPC Support for Web",
|
|
4
4
|
"author": "Portal Labs, Inc.",
|
|
5
5
|
"homepage": "https://portalhq.io/",
|
|
6
|
-
"version": "3.
|
|
6
|
+
"version": "3.7.0",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"main": "lib/commonjs/index",
|
|
9
9
|
"module": "lib/esm/index",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"src",
|
|
14
14
|
"lib",
|
|
15
15
|
"tsconfig.json",
|
|
16
|
+
"hypernative.d.ts",
|
|
17
|
+
"lifi-types.d.ts",
|
|
18
|
+
"yieldxyz-types.d.ts",
|
|
19
|
+
"zero-x.d.ts",
|
|
16
20
|
"types.d.ts",
|
|
17
21
|
"!src/iframe",
|
|
18
22
|
"!dist"
|
|
@@ -49,6 +53,5 @@
|
|
|
49
53
|
},
|
|
50
54
|
"dependencies": {
|
|
51
55
|
"@solana/web3.js": "^1.91.8"
|
|
52
|
-
}
|
|
53
|
-
"stableVersion": "3.5.2"
|
|
56
|
+
}
|
|
54
57
|
}
|
package/src/__mocks/constants.ts
CHANGED
|
@@ -730,11 +730,17 @@ export const mockQuoteRes = {
|
|
|
730
730
|
}
|
|
731
731
|
|
|
732
732
|
export const mockSourcesRes = {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
733
|
+
data: {
|
|
734
|
+
rawResponse: {
|
|
735
|
+
sources: ['0x', 'SushiSwap', 'Uniswap', 'Uniswap_V2', 'Uniswap_V3'],
|
|
736
|
+
zid: 'test-zid',
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
metadata: {
|
|
740
|
+
chainId: 'eip155:1',
|
|
741
|
+
clientId: 'test',
|
|
742
|
+
clientEip155Address: '0x1234567890123456789012345678901234567890',
|
|
743
|
+
},
|
|
738
744
|
}
|
|
739
745
|
|
|
740
746
|
export const mockZeroXQuoteResponse = {
|
|
@@ -1312,3 +1318,414 @@ export const mockLifiGetRouteStepResponse = {
|
|
|
1312
1318
|
},
|
|
1313
1319
|
},
|
|
1314
1320
|
}
|
|
1321
|
+
|
|
1322
|
+
// ZeroEx v2 mock data
|
|
1323
|
+
export const mockZeroExQuoteV2Request = {
|
|
1324
|
+
chainId: 'eip155:1',
|
|
1325
|
+
buyToken: 'UNI',
|
|
1326
|
+
sellToken: 'WETH',
|
|
1327
|
+
sellAmount: '1000000000000000000',
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
export const mockZeroExQuoteV2Response = {
|
|
1331
|
+
data: {
|
|
1332
|
+
rawResponse: {
|
|
1333
|
+
blockNumber: '18500000',
|
|
1334
|
+
buyAmount: '100000000000000000000',
|
|
1335
|
+
buyToken: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1336
|
+
fees: {
|
|
1337
|
+
integratorFee: null,
|
|
1338
|
+
zeroExFee: null,
|
|
1339
|
+
gasFee: {
|
|
1340
|
+
amount: '21000000000000',
|
|
1341
|
+
token: '0x0000000000000000000000000000000000000000',
|
|
1342
|
+
type: 'gas',
|
|
1343
|
+
},
|
|
1344
|
+
},
|
|
1345
|
+
issues: {
|
|
1346
|
+
allowance: {
|
|
1347
|
+
actual: '0',
|
|
1348
|
+
spender: '0x1234567890123456789012345678901234567890',
|
|
1349
|
+
},
|
|
1350
|
+
balance: {
|
|
1351
|
+
token: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1352
|
+
actual: '1000000000000000000',
|
|
1353
|
+
expected: '1000000000000000000',
|
|
1354
|
+
},
|
|
1355
|
+
simulationIncomplete: false,
|
|
1356
|
+
invalidSourcesPassed: [],
|
|
1357
|
+
},
|
|
1358
|
+
liquidityAvailable: true,
|
|
1359
|
+
minBuyAmount: '99000000000000000000',
|
|
1360
|
+
route: {
|
|
1361
|
+
fills: [
|
|
1362
|
+
{
|
|
1363
|
+
from: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1364
|
+
to: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1365
|
+
source: 'Uniswap_V3',
|
|
1366
|
+
proportionBps: '10000',
|
|
1367
|
+
},
|
|
1368
|
+
],
|
|
1369
|
+
tokens: [
|
|
1370
|
+
{
|
|
1371
|
+
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1372
|
+
symbol: 'WETH',
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1376
|
+
symbol: 'UNI',
|
|
1377
|
+
},
|
|
1378
|
+
],
|
|
1379
|
+
},
|
|
1380
|
+
sellAmount: '1000000000000000000',
|
|
1381
|
+
sellToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1382
|
+
tokenMetadata: {
|
|
1383
|
+
buyToken: {
|
|
1384
|
+
buyTaxBps: '0',
|
|
1385
|
+
sellTaxBps: '0',
|
|
1386
|
+
},
|
|
1387
|
+
sellToken: {
|
|
1388
|
+
buyTaxBps: '0',
|
|
1389
|
+
sellTaxBps: '0',
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
totalNetworkFee: '21000000000000',
|
|
1393
|
+
transaction: {
|
|
1394
|
+
to: '0x1234567890123456789012345678901234567890',
|
|
1395
|
+
data: '0xabcdef',
|
|
1396
|
+
gas: '200000',
|
|
1397
|
+
gasPrice: '30000000000',
|
|
1398
|
+
value: '0',
|
|
1399
|
+
},
|
|
1400
|
+
},
|
|
1401
|
+
},
|
|
1402
|
+
metadata: {
|
|
1403
|
+
buyToken: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1404
|
+
sellToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1405
|
+
sellAmount: '1000000000000000000',
|
|
1406
|
+
chainId: 'eip155:1',
|
|
1407
|
+
clientId: 'test-client-id',
|
|
1408
|
+
clientEip155Address: mockEip155Address,
|
|
1409
|
+
},
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
export const mockZeroExSourcesV2Request = {
|
|
1413
|
+
chainId: 'eip155:1',
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
export const mockZeroExSourcesV2Response = {
|
|
1417
|
+
data: {
|
|
1418
|
+
rawResponse: {
|
|
1419
|
+
sources: ['Uniswap_V2', 'Uniswap_V3', 'SushiSwap', '0x'],
|
|
1420
|
+
zid: 'test-zid',
|
|
1421
|
+
},
|
|
1422
|
+
},
|
|
1423
|
+
metadata: {
|
|
1424
|
+
chainId: 'eip155:1',
|
|
1425
|
+
clientId: 'test-client-id',
|
|
1426
|
+
},
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
export const mockZeroExPriceRequest = {
|
|
1430
|
+
chainId: 'eip155:1',
|
|
1431
|
+
buyToken: 'UNI',
|
|
1432
|
+
sellToken: 'WETH',
|
|
1433
|
+
sellAmount: '1000000000000000000',
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
export const mockZeroExPriceResponse = {
|
|
1437
|
+
data: {
|
|
1438
|
+
rawResponse: {
|
|
1439
|
+
blockNumber: '18500000',
|
|
1440
|
+
buyAmount: '100000000000000000000',
|
|
1441
|
+
buyToken: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1442
|
+
fees: {
|
|
1443
|
+
integratorFee: null,
|
|
1444
|
+
zeroExFee: null,
|
|
1445
|
+
gasFee: {
|
|
1446
|
+
amount: '21000000000000',
|
|
1447
|
+
token: '0x0000000000000000000000000000000000000000',
|
|
1448
|
+
type: 'gas',
|
|
1449
|
+
},
|
|
1450
|
+
},
|
|
1451
|
+
gas: '200000',
|
|
1452
|
+
gasPrice: '30000000000',
|
|
1453
|
+
issues: {
|
|
1454
|
+
allowance: {
|
|
1455
|
+
actual: '0',
|
|
1456
|
+
spender: '0x1234567890123456789012345678901234567890',
|
|
1457
|
+
},
|
|
1458
|
+
balance: {
|
|
1459
|
+
token: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1460
|
+
actual: '1000000000000000000',
|
|
1461
|
+
expected: '1000000000000000000',
|
|
1462
|
+
},
|
|
1463
|
+
simulationIncomplete: false,
|
|
1464
|
+
invalidSourcesPassed: [],
|
|
1465
|
+
},
|
|
1466
|
+
liquidityAvailable: true,
|
|
1467
|
+
minBuyAmount: '99000000000000000000',
|
|
1468
|
+
route: {
|
|
1469
|
+
fills: [
|
|
1470
|
+
{
|
|
1471
|
+
from: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1472
|
+
to: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1473
|
+
source: 'Uniswap_V3',
|
|
1474
|
+
proportionBps: '10000',
|
|
1475
|
+
},
|
|
1476
|
+
],
|
|
1477
|
+
tokens: [
|
|
1478
|
+
{
|
|
1479
|
+
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1480
|
+
symbol: 'WETH',
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1484
|
+
symbol: 'UNI',
|
|
1485
|
+
},
|
|
1486
|
+
],
|
|
1487
|
+
},
|
|
1488
|
+
sellAmount: '1000000000000000000',
|
|
1489
|
+
sellToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1490
|
+
tokenMetadata: {
|
|
1491
|
+
buyToken: {
|
|
1492
|
+
buyTaxBps: '0',
|
|
1493
|
+
sellTaxBps: '0',
|
|
1494
|
+
},
|
|
1495
|
+
sellToken: {
|
|
1496
|
+
buyTaxBps: '0',
|
|
1497
|
+
sellTaxBps: '0',
|
|
1498
|
+
},
|
|
1499
|
+
},
|
|
1500
|
+
totalNetworkFee: '21000000000000',
|
|
1501
|
+
},
|
|
1502
|
+
},
|
|
1503
|
+
metadata: {
|
|
1504
|
+
buyToken: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
|
|
1505
|
+
sellToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
1506
|
+
sellAmount: '1000000000000000000',
|
|
1507
|
+
chainId: 'eip155:1',
|
|
1508
|
+
clientId: 'test-client-id',
|
|
1509
|
+
clientEip155Address: mockEip155Address,
|
|
1510
|
+
},
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
export const mockZeroExOptions = {
|
|
1514
|
+
zeroXApiKey: 'test-0x-api-key',
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// Hypernative Security mock data
|
|
1518
|
+
export const mockScanAddressesRequest = {
|
|
1519
|
+
addresses: ['0x1234567890123456789012345678901234567890'],
|
|
1520
|
+
screenerPolicyId: 'test-policy-id',
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
export const mockScanAddressesResponse = {
|
|
1524
|
+
data: {
|
|
1525
|
+
rawResponse: [
|
|
1526
|
+
{
|
|
1527
|
+
address: '0x1234567890123456789012345678901234567890',
|
|
1528
|
+
recommendation: 'accept',
|
|
1529
|
+
severity: 'low',
|
|
1530
|
+
totalIncomingUsd: 1000,
|
|
1531
|
+
policyId: 'test-policy-id',
|
|
1532
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1533
|
+
flags: [],
|
|
1534
|
+
},
|
|
1535
|
+
],
|
|
1536
|
+
},
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
export const mockScanEVMTxRequest = {
|
|
1540
|
+
transaction: {
|
|
1541
|
+
chain: 'ethereum',
|
|
1542
|
+
fromAddress: '0x1234567890123456789012345678901234567890',
|
|
1543
|
+
toAddress: '0x0987654321098765432109876543210987654321',
|
|
1544
|
+
input: '0xabcdef',
|
|
1545
|
+
value: '1000000000000000000',
|
|
1546
|
+
},
|
|
1547
|
+
url: 'https://example.com',
|
|
1548
|
+
validateNonce: true,
|
|
1549
|
+
showFullFindings: true,
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
export const mockScanEVMTxResponse = {
|
|
1553
|
+
data: {
|
|
1554
|
+
rawResponse: {
|
|
1555
|
+
success: true,
|
|
1556
|
+
data: {
|
|
1557
|
+
assessmentId: 'test-assessment-id',
|
|
1558
|
+
assessmentTimestamp: '2024-01-01T00:00:00Z',
|
|
1559
|
+
recommendation: 'accept' as const,
|
|
1560
|
+
expectedStatus: 'success' as const,
|
|
1561
|
+
findings: [],
|
|
1562
|
+
involvedAssets: [],
|
|
1563
|
+
balanceChanges: null,
|
|
1564
|
+
},
|
|
1565
|
+
error: null,
|
|
1566
|
+
version: '1.0.0',
|
|
1567
|
+
service: 'hypernative',
|
|
1568
|
+
},
|
|
1569
|
+
},
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
export const mockScanEip712TxRequest = {
|
|
1573
|
+
walletAddress: '0x1234567890123456789012345678901234567890',
|
|
1574
|
+
chainId: '1',
|
|
1575
|
+
eip712Message: {
|
|
1576
|
+
primaryType: 'Transfer',
|
|
1577
|
+
types: {
|
|
1578
|
+
Transfer: [
|
|
1579
|
+
{ name: 'to', type: 'address' },
|
|
1580
|
+
{ name: 'amount', type: 'uint256' },
|
|
1581
|
+
],
|
|
1582
|
+
},
|
|
1583
|
+
domain: {
|
|
1584
|
+
name: 'Test',
|
|
1585
|
+
version: '1',
|
|
1586
|
+
chainId: 1,
|
|
1587
|
+
},
|
|
1588
|
+
message: {
|
|
1589
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
1590
|
+
amount: '1000000000000000000',
|
|
1591
|
+
},
|
|
1592
|
+
},
|
|
1593
|
+
showFullFindings: true,
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
export const mockScanEip712TxResponse = {
|
|
1597
|
+
data: {
|
|
1598
|
+
rawResponse: {
|
|
1599
|
+
success: true,
|
|
1600
|
+
data: {
|
|
1601
|
+
assessmentId: 'test-assessment-id',
|
|
1602
|
+
assessmentTimestamp: '2024-01-01T00:00:00Z',
|
|
1603
|
+
recommendation: 'accept' as const,
|
|
1604
|
+
findings: [],
|
|
1605
|
+
involvedAssets: [],
|
|
1606
|
+
},
|
|
1607
|
+
error: null,
|
|
1608
|
+
version: '1.0.0',
|
|
1609
|
+
service: 'hypernative',
|
|
1610
|
+
},
|
|
1611
|
+
},
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
export const mockScanSolanaTxRequest = {
|
|
1615
|
+
transaction: {
|
|
1616
|
+
message: {
|
|
1617
|
+
accountKeys: ['test-account-key'],
|
|
1618
|
+
header: {
|
|
1619
|
+
numRequiredSignatures: 1,
|
|
1620
|
+
numReadonlySignedAccounts: 0,
|
|
1621
|
+
numReadonlyUnsignedAccounts: 0,
|
|
1622
|
+
},
|
|
1623
|
+
instructions: [
|
|
1624
|
+
{
|
|
1625
|
+
accounts: [0],
|
|
1626
|
+
data: 'test-data',
|
|
1627
|
+
programIdIndex: 0,
|
|
1628
|
+
},
|
|
1629
|
+
],
|
|
1630
|
+
recentBlockhash: 'test-blockhash',
|
|
1631
|
+
},
|
|
1632
|
+
signatures: ['test-signature'],
|
|
1633
|
+
},
|
|
1634
|
+
url: 'https://example.com',
|
|
1635
|
+
validateRecentBlockHash: true,
|
|
1636
|
+
showFullFindings: true,
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
export const mockScanSolanaTxResponse = {
|
|
1640
|
+
data: {
|
|
1641
|
+
rawResponse: {
|
|
1642
|
+
success: true,
|
|
1643
|
+
data: {
|
|
1644
|
+
recommendation: 'accept' as const,
|
|
1645
|
+
expectedStatus: 'success' as const,
|
|
1646
|
+
findings: [],
|
|
1647
|
+
involvedAssets: [],
|
|
1648
|
+
balanceChanges: null,
|
|
1649
|
+
},
|
|
1650
|
+
error: null,
|
|
1651
|
+
version: '1.0.0',
|
|
1652
|
+
service: 'hypernative',
|
|
1653
|
+
},
|
|
1654
|
+
},
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
export const mockScanNftRequest = [
|
|
1658
|
+
{
|
|
1659
|
+
address: '0x1234567890123456789012345678901234567890',
|
|
1660
|
+
chain: 'ethereum',
|
|
1661
|
+
evmChainId: 1,
|
|
1662
|
+
},
|
|
1663
|
+
]
|
|
1664
|
+
|
|
1665
|
+
export const mockScanNftResponse = {
|
|
1666
|
+
data: {
|
|
1667
|
+
rawResponse: {
|
|
1668
|
+
success: true,
|
|
1669
|
+
data: {
|
|
1670
|
+
nfts: [
|
|
1671
|
+
{
|
|
1672
|
+
address: '0x1234567890123456789012345678901234567890',
|
|
1673
|
+
chain: 'ethereum',
|
|
1674
|
+
evmChainId: '1',
|
|
1675
|
+
accept: true,
|
|
1676
|
+
},
|
|
1677
|
+
],
|
|
1678
|
+
},
|
|
1679
|
+
error: null,
|
|
1680
|
+
version: '1.0.0',
|
|
1681
|
+
service: 'hypernative',
|
|
1682
|
+
},
|
|
1683
|
+
},
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
export const mockScanTokenRequest = [
|
|
1687
|
+
{
|
|
1688
|
+
address: '0x1234567890123456789012345678901234567890',
|
|
1689
|
+
chain: 'ethereum',
|
|
1690
|
+
evmChainId: 1,
|
|
1691
|
+
},
|
|
1692
|
+
]
|
|
1693
|
+
|
|
1694
|
+
export const mockScanTokenResponse = {
|
|
1695
|
+
data: {
|
|
1696
|
+
rawResponse: {
|
|
1697
|
+
success: true,
|
|
1698
|
+
data: {
|
|
1699
|
+
tokens: [
|
|
1700
|
+
{
|
|
1701
|
+
address: '0x1234567890123456789012345678901234567890',
|
|
1702
|
+
chain: 'ethereum',
|
|
1703
|
+
reputation: {
|
|
1704
|
+
recommendation: 'accept' as const,
|
|
1705
|
+
},
|
|
1706
|
+
},
|
|
1707
|
+
],
|
|
1708
|
+
},
|
|
1709
|
+
error: null,
|
|
1710
|
+
version: '1.0.0',
|
|
1711
|
+
service: 'hypernative',
|
|
1712
|
+
},
|
|
1713
|
+
},
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
export const mockScanUrlRequest = 'https://example.com'
|
|
1717
|
+
|
|
1718
|
+
export const mockScanUrlResponse = {
|
|
1719
|
+
data: {
|
|
1720
|
+
rawResponse: {
|
|
1721
|
+
success: true,
|
|
1722
|
+
data: {
|
|
1723
|
+
isMalicious: false,
|
|
1724
|
+
deepScanTriggered: false,
|
|
1725
|
+
},
|
|
1726
|
+
error: null,
|
|
1727
|
+
version: '1.0.0',
|
|
1728
|
+
service: 'hypernative',
|
|
1729
|
+
},
|
|
1730
|
+
},
|
|
1731
|
+
}
|
|
@@ -27,5 +27,6 @@ mpcMock.ejectPrivateKeys = jest
|
|
|
27
27
|
.fn()
|
|
28
28
|
.mockResolvedValue(mockEjectPrivateKeysResult)
|
|
29
29
|
mpcMock.checkSharesOnDevice = jest.fn().mockResolvedValue(mockSharesOnDevice)
|
|
30
|
+
mpcMock.setBackupStatus = jest.fn().mockResolvedValue(true)
|
|
30
31
|
|
|
31
32
|
export default mpcMock as jest.Mocked<Mpc>
|
package/src/index.test.ts
CHANGED
|
@@ -173,6 +173,182 @@ describe('Portal', () => {
|
|
|
173
173
|
})
|
|
174
174
|
})
|
|
175
175
|
|
|
176
|
+
describe('generateBackupShare', () => {
|
|
177
|
+
it('should request a custom backup and return cipherText and encryptionKey', async () => {
|
|
178
|
+
const storageCallback = jest.fn().mockResolvedValue(undefined)
|
|
179
|
+
;(portal.mpc.backup as jest.Mock).mockResolvedValueOnce({
|
|
180
|
+
cipherText: mockCipherText,
|
|
181
|
+
encryptionKey: 'manual-key',
|
|
182
|
+
storageCallback,
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const result = await portal.generateBackupShare()
|
|
186
|
+
|
|
187
|
+
expect(result).toEqual({
|
|
188
|
+
cipherText: mockCipherText,
|
|
189
|
+
encryptionKey: 'manual-key',
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
expect(portal.mpc.backup).toHaveBeenCalledWith(
|
|
193
|
+
{
|
|
194
|
+
backupMethod: BackupMethods.custom,
|
|
195
|
+
backupConfigs: {},
|
|
196
|
+
host: 'web.portalhq.io',
|
|
197
|
+
mpcVersion: 'v6',
|
|
198
|
+
featureFlags: {},
|
|
199
|
+
},
|
|
200
|
+
expect.any(Function),
|
|
201
|
+
)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('should throw if the iframe response does not contain an encryption key', async () => {
|
|
205
|
+
;(portal.mpc.backup as jest.Mock).mockResolvedValueOnce({
|
|
206
|
+
cipherText: mockCipherText,
|
|
207
|
+
storageCallback: jest.fn(),
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
await expect(portal.generateBackupShare()).rejects.toThrow(
|
|
211
|
+
'Custom backup did not return an encryption key',
|
|
212
|
+
)
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
describe('registerPasskeyAndStoreEncryptionKey', () => {
|
|
217
|
+
it('should delegate to the passkey service with computed relying party data', async () => {
|
|
218
|
+
const passkeyServiceMock = {
|
|
219
|
+
registerPasskeyAndStoreKey: jest.fn().mockResolvedValue(undefined),
|
|
220
|
+
}
|
|
221
|
+
;(portal as any).passkeyService = passkeyServiceMock
|
|
222
|
+
;(portal as any).passkeyServiceDefaultDomain = 'backup.web.portalhq.io'
|
|
223
|
+
;(portal as any).passkeyServiceApiKey = portal.apiKey
|
|
224
|
+
|
|
225
|
+
await portal.registerPasskeyAndStoreEncryptionKey(
|
|
226
|
+
mockCipherText,
|
|
227
|
+
'manual-key',
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
expect(
|
|
231
|
+
passkeyServiceMock.registerPasskeyAndStoreKey,
|
|
232
|
+
).toHaveBeenCalledTimes(1)
|
|
233
|
+
expect(
|
|
234
|
+
passkeyServiceMock.registerPasskeyAndStoreKey,
|
|
235
|
+
).toHaveBeenCalledWith(
|
|
236
|
+
expect.objectContaining({
|
|
237
|
+
customDomain: undefined,
|
|
238
|
+
encryptionKey: 'manual-key',
|
|
239
|
+
relyingPartyId: 'backup.web.portalhq.io',
|
|
240
|
+
relyingPartyName: 'Portal',
|
|
241
|
+
cipherText: mockCipherText,
|
|
242
|
+
}),
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('should throw when usePopup is requested', async () => {
|
|
247
|
+
await expect(
|
|
248
|
+
portal.registerPasskeyAndStoreEncryptionKey(
|
|
249
|
+
mockCipherText,
|
|
250
|
+
'manual-key',
|
|
251
|
+
{ usePopup: true },
|
|
252
|
+
),
|
|
253
|
+
).rejects.toThrow('does not support the popup flow')
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
describe('authenticatePasskeyAndRetrieveKey', () => {
|
|
258
|
+
it('should invoke the passkey service for direct authentication', async () => {
|
|
259
|
+
const passkeyServiceMock = {
|
|
260
|
+
authenticatePasskeyAndRetrieveKey: jest
|
|
261
|
+
.fn()
|
|
262
|
+
.mockResolvedValue('retrieved-key'),
|
|
263
|
+
}
|
|
264
|
+
;(portal as any).passkeyService = passkeyServiceMock
|
|
265
|
+
;(portal as any).passkeyServiceDefaultDomain = 'backup.web.portalhq.io'
|
|
266
|
+
;(portal as any).passkeyServiceApiKey = portal.apiKey
|
|
267
|
+
|
|
268
|
+
const key = await portal.authenticatePasskeyAndRetrieveKey()
|
|
269
|
+
|
|
270
|
+
expect(key).toEqual('retrieved-key')
|
|
271
|
+
expect(
|
|
272
|
+
passkeyServiceMock.authenticatePasskeyAndRetrieveKey,
|
|
273
|
+
).toHaveBeenCalledWith(
|
|
274
|
+
expect.objectContaining({
|
|
275
|
+
customDomain: undefined,
|
|
276
|
+
relyingPartyId: 'backup.web.portalhq.io',
|
|
277
|
+
relyingPartyName: 'Portal',
|
|
278
|
+
}),
|
|
279
|
+
)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('should throw when usePopup is true', async () => {
|
|
283
|
+
await expect(
|
|
284
|
+
portal.authenticatePasskeyAndRetrieveKey({ usePopup: true }),
|
|
285
|
+
).rejects.toThrow('does not support the popup flow')
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('backupWithPasskey', () => {
|
|
290
|
+
it('should orchestrate the direct passkey flow when usePopup is false', async () => {
|
|
291
|
+
const directShare = {
|
|
292
|
+
cipherText: mockCipherText,
|
|
293
|
+
encryptionKey: 'manual-key',
|
|
294
|
+
}
|
|
295
|
+
const generateSpy = jest
|
|
296
|
+
.spyOn(portal, 'generateBackupShare')
|
|
297
|
+
.mockResolvedValue(directShare)
|
|
298
|
+
const registerSpy = jest
|
|
299
|
+
.spyOn(portal, 'registerPasskeyAndStoreEncryptionKey')
|
|
300
|
+
.mockResolvedValue(undefined)
|
|
301
|
+
const storedClientBackupShareSpy = jest
|
|
302
|
+
.spyOn(portal, 'storedClientBackupShare')
|
|
303
|
+
.mockResolvedValue(undefined)
|
|
304
|
+
|
|
305
|
+
await portal.backupWithPasskey(
|
|
306
|
+
{
|
|
307
|
+
usePopup: false,
|
|
308
|
+
customDomain: 'passkeys.wigwam.app',
|
|
309
|
+
relyingPartyName: 'Wigwam',
|
|
310
|
+
},
|
|
311
|
+
undefined,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
expect(generateSpy).toHaveBeenCalledTimes(1)
|
|
315
|
+
expect(registerSpy).toHaveBeenCalledWith(
|
|
316
|
+
directShare.cipherText,
|
|
317
|
+
directShare.encryptionKey,
|
|
318
|
+
expect.objectContaining({
|
|
319
|
+
customDomain: 'passkeys.wigwam.app',
|
|
320
|
+
relyingPartyName: 'Wigwam',
|
|
321
|
+
usePopup: false,
|
|
322
|
+
}),
|
|
323
|
+
)
|
|
324
|
+
expect(storedClientBackupShareSpy).toHaveBeenCalledWith(
|
|
325
|
+
true,
|
|
326
|
+
BackupMethods.passkey,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
generateSpy.mockRestore()
|
|
330
|
+
registerSpy.mockRestore()
|
|
331
|
+
storedClientBackupShareSpy.mockRestore()
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
it('should fall back to the legacy popup flow when usePopup is true', async () => {
|
|
335
|
+
const progress = jest.fn()
|
|
336
|
+
|
|
337
|
+
await portal.backupWithPasskey({}, progress)
|
|
338
|
+
|
|
339
|
+
expect(portal.mpc.backup).toHaveBeenCalledWith(
|
|
340
|
+
{
|
|
341
|
+
backupMethod: BackupMethods.passkey,
|
|
342
|
+
backupConfigs: {},
|
|
343
|
+
host: 'web.portalhq.io',
|
|
344
|
+
mpcVersion: 'v6',
|
|
345
|
+
featureFlags: {},
|
|
346
|
+
},
|
|
347
|
+
progress,
|
|
348
|
+
)
|
|
349
|
+
})
|
|
350
|
+
})
|
|
351
|
+
|
|
176
352
|
describe('recoverWallet', () => {
|
|
177
353
|
it('should successfully recover a wallet and call mpc.recover correctly', async () => {
|
|
178
354
|
const mockProgressFn = jest.fn()
|
|
@@ -883,9 +1059,9 @@ describe('Portal', () => {
|
|
|
883
1059
|
|
|
884
1060
|
expect(portal.mpc.getQuote).toHaveBeenCalledTimes(1)
|
|
885
1061
|
expect(portal.mpc.getQuote).toHaveBeenCalledWith(
|
|
886
|
-
'test',
|
|
887
|
-
mockQuoteArgs,
|
|
888
1062
|
'eip155:1',
|
|
1063
|
+
mockQuoteArgs,
|
|
1064
|
+
'test',
|
|
889
1065
|
)
|
|
890
1066
|
})
|
|
891
1067
|
})
|
|
@@ -895,7 +1071,7 @@ describe('Portal', () => {
|
|
|
895
1071
|
await portal.getSources('test', 'eip155:1')
|
|
896
1072
|
|
|
897
1073
|
expect(portal.mpc.getSources).toHaveBeenCalledTimes(1)
|
|
898
|
-
expect(portal.mpc.getSources).toHaveBeenCalledWith('
|
|
1074
|
+
expect(portal.mpc.getSources).toHaveBeenCalledWith('eip155:1', 'test')
|
|
899
1075
|
})
|
|
900
1076
|
})
|
|
901
1077
|
|