From 095c654549f025a471ab7f9f136b2da8d10f5d3c Mon Sep 17 00:00:00 2001 From: Peterjah Date: Mon, 2 Dec 2024 16:02:53 +0100 Subject: [PATCH] update massa-web3 --- packages/dapp/package.json | 2 +- packages/dapp/src/components/NetworkMenu.tsx | 14 +- packages/dapp/src/components/OperationRow.tsx | 39 +- .../src/components/SendTransactionModal.tsx | 18 +- packages/dapp/src/components/TokenRow.tsx | 11 +- packages/dapp/src/components/TokenTab.tsx | 5 +- packages/dapp/src/hooks/useMassaClient.ts | 11 +- packages/dapp/src/hooks/useOperationsData.ts | 8 +- packages/dapp/src/hooks/useTransfer.ts | 2 +- packages/snap/package.json | 6 +- packages/snap/snap.manifest.json | 2 +- packages/snap/src/accounts/clients.ts | 29 -- packages/snap/src/accounts/hd-deriver.ts | 37 +- packages/snap/src/accounts/provider.ts | 10 + packages/snap/src/active-chain.ts | 18 +- packages/snap/src/components/CallSc.tsx | 18 +- packages/snap/src/components/HomePage.tsx | 21 +- packages/snap/src/components/index.tsx | 6 +- packages/snap/src/dto.ts | 19 - packages/snap/src/handlers/add-token.ts | 34 +- packages/snap/src/handlers/buy-rolls.ts | 48 +- .../snap/src/handlers/call-smart-contract.tsx | 92 ++-- .../snap/src/handlers/clear-operations.ts | 9 +- packages/snap/src/handlers/delete-token.ts | 16 +- .../snap/src/handlers/get-active-account.ts | 8 +- packages/snap/src/handlers/get-balance.ts | 36 +- packages/snap/src/handlers/get-operations.ts | 9 +- packages/snap/src/handlers/get-tokens.ts | 8 +- .../snap/src/handlers/read-smart-contract.ts | 89 ++-- packages/snap/src/handlers/sell-rolls.ts | 51 +- packages/snap/src/handlers/set-network.tsx | 17 +- .../src/handlers/show-account-credentials.tsx | 11 +- packages/snap/src/handlers/sign-message.ts | 52 +- packages/snap/src/handlers/transfer.ts | 61 +-- packages/snap/src/index.tsx | 64 +-- packages/snap/src/network.ts | 28 +- packages/snap/src/operations.ts | 7 +- packages/snap/src/tokens.ts | 16 +- packages/snap/test/add-token.test.ts | 104 ++-- packages/snap/test/buy-rolls.test.ts | 247 ++++----- packages/snap/test/call-sc.test.tsx | 480 ++++++++---------- packages/snap/test/clear-operations.test.ts | 91 ++-- packages/snap/test/delete-token.test.ts | 27 +- packages/snap/test/get-balance.test.ts | 134 +++-- packages/snap/test/get-network.test.ts | 50 +- packages/snap/test/read-sc.test.ts | 9 +- packages/snap/test/sell-rolls.test.ts | 247 ++++----- packages/snap/test/set-network.test.ts | 67 ++- packages/snap/test/show-credentials.test.tsx | 98 ++-- packages/snap/test/sign-message.test.ts | 111 ++-- packages/snap/test/transfer.test.ts | 473 ++++++++--------- packages/snap/test/utils/addTokens.ts | 20 - packages/snap/test/utils/constants.ts | 11 + packages/snap/test/utils/setNetwork.ts | 3 +- yarn.lock | 274 +++------- 55 files changed, 1421 insertions(+), 1957 deletions(-) delete mode 100644 packages/snap/src/accounts/clients.ts create mode 100644 packages/snap/src/accounts/provider.ts delete mode 100644 packages/snap/src/dto.ts delete mode 100644 packages/snap/test/utils/addTokens.ts create mode 100644 packages/snap/test/utils/constants.ts diff --git a/packages/dapp/package.json b/packages/dapp/package.json index aed0007..d50704b 100644 --- a/packages/dapp/package.json +++ b/packages/dapp/package.json @@ -15,7 +15,7 @@ "@chakra-ui/react": "^2.8.2", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", - "@massalabs/massa-web3": "^4.0.3", + "@massalabs/massa-web3": "^5.0.1-dev", "@metamask/providers": "^15.0.0", "framer-motion": "^11.0.8", "next": "14.1.1", diff --git a/packages/dapp/src/components/NetworkMenu.tsx b/packages/dapp/src/components/NetworkMenu.tsx index 9ee5f4d..4c5f025 100644 --- a/packages/dapp/src/components/NetworkMenu.tsx +++ b/packages/dapp/src/components/NetworkMenu.tsx @@ -7,19 +7,23 @@ import { Button, Spinner, } from '@chakra-ui/react'; -import { CHAIN_ID, DefaultProviderUrls } from '@massalabs/massa-web3'; import { invalidateNetwork, useNetwork } from '@/hooks/useNetwork'; import { invalidateOperations } from '@/hooks/useOperations'; import { useSetNetwork } from '@/hooks/useSetNetwork'; import { invalidateTokens } from '@/hooks/useTokens'; +import { CHAIN_ID, NetworkName, PublicApiUrl } from '@massalabs/massa-web3'; const networkList = [ - { id: CHAIN_ID.MainNet, name: 'Mainnet', url: DefaultProviderUrls.MAINNET }, { - id: CHAIN_ID.BuildNet, - name: 'Buildnet', - url: DefaultProviderUrls.BUILDNET, + id: CHAIN_ID.Mainnet, + name: NetworkName.Mainnet, + url: PublicApiUrl.Mainnet, + }, + { + id: CHAIN_ID.Buildnet, + name: NetworkName.Buildnet, + url: PublicApiUrl.Buildnet, }, ]; diff --git a/packages/dapp/src/components/OperationRow.tsx b/packages/dapp/src/components/OperationRow.tsx index d218dbc..24ab454 100644 --- a/packages/dapp/src/components/OperationRow.tsx +++ b/packages/dapp/src/components/OperationRow.tsx @@ -2,16 +2,14 @@ import { CheckCircleIcon, WarningIcon } from '@chakra-ui/icons'; import { AlertIcon, Link, Td, Tr } from '@chakra-ui/react'; -import type { IOperationData, ITransactionOpType } from '@massalabs/massa-web3'; -import type { - ICallSmartContractOpType, - IExecSmartContractOpType, - IRollBuyOpType, - IRollSellOpType, -} from '@massalabs/massa-web3/dist/esm/interfaces/OperationTypes'; +import { rpcTypes } from '@massalabs/massa-web3'; import { useMemo } from 'react'; -export const OperationRow = ({ operation }: { operation: IOperationData }) => { +export const OperationRow = ({ + operation, +}: { + operation: rpcTypes.OperationInfo; +}) => { const getStatusIcon = useMemo(() => { if (operation.op_exec_status === true) { return ; @@ -22,28 +20,17 @@ export const OperationRow = ({ operation }: { operation: IOperationData }) => { }, [operation]); const getOperationType = useMemo(() => { - if ( - (operation.operation.content.op as ITransactionOpType).Transaction !== - undefined - ) { + const { op } = operation.operation.content; + + if (!!op.Transaction) { return 'Transaction'; - } else if ( - (operation.operation.content.op as ICallSmartContractOpType).CallSC !== - undefined - ) { + } else if (!!op.CallSC) { return 'Smart Contract Call'; - } else if ( - (operation.operation.content.op as IExecSmartContractOpType).ExecuteSC !== - undefined - ) { + } else if (!!op.ExecutSC) { return 'Smart Contract Execution'; - } else if ( - (operation.operation.content.op as IRollBuyOpType).RollBuy !== undefined - ) { + } else if (!!op.RollBuy) { return 'Roll Buy'; - } else if ( - (operation.operation.content.op as IRollSellOpType).RollSell !== undefined - ) { + } else if (!!op.RollSell) { return 'Roll Sell'; } return 'Unknown'; diff --git a/packages/dapp/src/components/SendTransactionModal.tsx b/packages/dapp/src/components/SendTransactionModal.tsx index 9e245b7..4eb68a4 100644 --- a/packages/dapp/src/components/SendTransactionModal.tsx +++ b/packages/dapp/src/components/SendTransactionModal.tsx @@ -11,11 +11,11 @@ import { ModalHeader, ModalOverlay, } from '@chakra-ui/react'; -import { fromMAS } from '@massalabs/massa-web3'; import { useMemo, useRef, useState } from 'react'; import { invalidateOperations } from '@/hooks/useOperations'; import { useTransfer } from '@/hooks/useTransfer'; +import { Mas } from '@massalabs/massa-web3'; export const TxModal = ({ isOpen, @@ -29,22 +29,16 @@ export const TxModal = ({ const [recipientAddress, setReceiver] = useState(''); const [amount, setAmount] = useState('0'); - const [fee, setFee] = useState('0'); + const [fee, setFee] = useState(''); const transfer = useTransfer(); const isFormValid = useMemo(() => { - if (recipientAddress === '' || amount === '' || fee === '') { + if (recipientAddress === '' || amount === '') { // TODO: Show error message return false; } - try { - BigInt(amount); - BigInt(fee); - } catch (error) { - return false; - } return true; - }, [recipientAddress, amount, fee]); + }, [recipientAddress, amount]); return ( { await transfer({ recipientAddress, - amount: fromMAS(amount).toString(), - fee: fromMAS(fee).toString(), + amount: Mas.fromString(amount).toString(), + fee: fee !== '' ? Mas.fromString(fee).toString() : undefined, }); invalidateOperations(); onClose(false); diff --git a/packages/dapp/src/components/TokenRow.tsx b/packages/dapp/src/components/TokenRow.tsx index f85588c..e7b7bbd 100644 --- a/packages/dapp/src/components/TokenRow.tsx +++ b/packages/dapp/src/components/TokenRow.tsx @@ -2,7 +2,7 @@ import { DeleteIcon } from '@chakra-ui/icons'; import { IconButton, Td, Tr } from '@chakra-ui/react'; -import { Args, bytesToStr, bytesToU256 } from '@massalabs/massa-web3'; +import { Args, bytesToStr, U256 } from '@massalabs/massa-web3'; import { useEffect, useState, useCallback } from 'react'; import { useActiveAccount } from '@/hooks/useActiveAccount'; @@ -34,7 +34,7 @@ export const TokenRow = ({ token }: { token: string }) => { console.warn(`No response from readSC ${readData.functionName}`); return; } - const decimals = new Args(res.data).nextU8(); + const decimals = new Args(Uint8Array.from(res.data!)).nextU8(); readData.functionName = 'symbol'; res = await readSC(readData); @@ -45,15 +45,16 @@ export const TokenRow = ({ token }: { token: string }) => { const symbol = bytesToStr(Uint8Array.from(res.data!)); setTokenName(symbol); - const serAddr = new Args().addString(account.address).serialize(); - readData.args = serAddr; + readData.args = Array.from( + new Args().addString(account.address).serialize(), + ); readData.functionName = 'balanceOf'; res = await readSC(readData); if (!res) { console.warn(`No response from readSC ${readData.functionName}`); return; } - const rBalance = bytesToU256(Uint8Array.from(res.data!)); + const rBalance = U256.fromBytes(Uint8Array.from(res.data!)); const balanceNormalized = Number(rBalance / BigInt(10 ** (Number(decimals) - 3))) / 10 ** 3; diff --git a/packages/dapp/src/components/TokenTab.tsx b/packages/dapp/src/components/TokenTab.tsx index 010247e..5220c10 100644 --- a/packages/dapp/src/components/TokenTab.tsx +++ b/packages/dapp/src/components/TokenTab.tsx @@ -30,6 +30,7 @@ import { TokenRow } from './TokenRow'; import { useAccountBalance } from '@/hooks/useAccountBalance'; import { useActiveAccount } from '@/hooks/useActiveAccount'; import { useTokens } from '@/hooks/useTokens'; +import { Mas } from '@massalabs/massa-web3'; export type AccountToken = { name: string; address: string; decimals: number }; @@ -60,9 +61,7 @@ export const TokenTab = () => { if (isLoadingAccountBalance || !accountBalance) { return ; } - return ( - Number(BigInt(accountBalance.finalBalance) / BigInt(10 ** 6)) / 10 ** 3 - ); + return Mas.toString(BigInt(accountBalance.finalBalance)); }, [accountBalance, isLoadingAccountBalance]); return ( diff --git a/packages/dapp/src/hooks/useMassaClient.ts b/packages/dapp/src/hooks/useMassaClient.ts index c856d78..dfe2b9b 100644 --- a/packages/dapp/src/hooks/useMassaClient.ts +++ b/packages/dapp/src/hooks/useMassaClient.ts @@ -1,9 +1,8 @@ -import type { Client } from '@massalabs/massa-web3'; -import { ClientFactory } from '@massalabs/massa-web3'; import { useCallback, useEffect, useState } from 'react'; import type { NetworkInfos } from './useNetwork'; import { useNetwork } from './useNetwork'; +import { JsonRPCClient } from '@massalabs/massa-web3'; /** * @description Hook that creates a massa client from 'massa-web3' using the current network (updates when the network changes) @@ -11,14 +10,10 @@ import { useNetwork } from './useNetwork'; */ export const useMassaClient = () => { const { data: network } = useNetwork(); - const [client, setClient] = useState(); + const [client, setClient] = useState(); const createClient = useCallback( async (net: NetworkInfos) => { - const newClient = await ClientFactory.createDefaultClient( - net.rpcUrl as any, - BigInt(net.chainId), - ); - setClient(newClient); + setClient(new JsonRPCClient(net.rpcUrl)); }, [setClient], ); diff --git a/packages/dapp/src/hooks/useOperationsData.ts b/packages/dapp/src/hooks/useOperationsData.ts index 09b3e36..12b2c63 100644 --- a/packages/dapp/src/hooks/useOperationsData.ts +++ b/packages/dapp/src/hooks/useOperationsData.ts @@ -1,7 +1,7 @@ -import type { IOperationData } from '@massalabs/massa-web3'; import { useCallback, useEffect, useState } from 'react'; import { useMassaClient } from './useMassaClient'; +import { rpcTypes } from '@massalabs/massa-web3'; /** * @description Hook that calls the massa client to get the operations data @@ -9,7 +9,9 @@ import { useMassaClient } from './useMassaClient'; * @returns The operations data (@see `IOperationData` for more information) */ export const useOperationsData = (operationIds: string[]) => { - const [operationsData, setOperationsData] = useState([]); + const [operationsData, setOperationsData] = useState< + rpcTypes.OperationInfo[] + >([]); const client = useMassaClient(); const setOperationsInfos = useCallback(async () => { @@ -17,7 +19,7 @@ export const useOperationsData = (operationIds: string[]) => { return; } try { - const res = await client.publicApi().getOperations(operationIds); + const res = await client.getOperations(operationIds); setOperationsData(res); } catch (error) { console.error(error); diff --git a/packages/dapp/src/hooks/useTransfer.ts b/packages/dapp/src/hooks/useTransfer.ts index b8b8475..7e1a23d 100644 --- a/packages/dapp/src/hooks/useTransfer.ts +++ b/packages/dapp/src/hooks/useTransfer.ts @@ -7,7 +7,7 @@ import { defaultSnapOrigin } from '@/config'; export type TransferParams = { recipientAddress: string; amount: string; - fee: string; + fee?: string; }; export type TransferResponse = { diff --git a/packages/snap/package.json b/packages/snap/package.json index 6cdf6c4..8d0c830 100644 --- a/packages/snap/package.json +++ b/packages/snap/package.json @@ -27,10 +27,11 @@ "test": "jest" }, "dependencies": { - "@massalabs/massa-web3": "^4.0.3", + "@massalabs/massa-web3": "^5.0.1-dev", "@metamask/key-tree": "^9.0.0", "@metamask/snaps-sdk": "^6.10.0", - "buffer": "^6.0.3" + "buffer": "^6.0.3", + "varint": "^6.0.0" }, "devDependencies": { "@jest/globals": "^29.5.0", @@ -44,6 +45,7 @@ "@types/jest": "^29.5.12", "@types/react": "18.2.14", "@types/react-dom": "18.2.4", + "@types/varint": "^6.0.3", "@typescript-eslint/eslint-plugin": "^5.42.1", "@typescript-eslint/parser": "^5.42.1", "eslint": "^8.45.0", diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 8f665cf..b0853d7 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/massalabs/metamask-massa.git" }, "source": { - "shasum": "Yj5vc0Btmwc469HpD7oRnhRAXLXh+XGnxX4mWP421fU=", + "shasum": "KHYaXuehXQ9AmSorULWLkNqB1RlycfosKAiS3+f2Upg=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/accounts/clients.ts b/packages/snap/src/accounts/clients.ts deleted file mode 100644 index 8f3b737..0000000 --- a/packages/snap/src/accounts/clients.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Client, WalletClient } from '@massalabs/massa-web3'; -import { ClientFactory, ProviderType } from '@massalabs/massa-web3'; - -import { getHDAccount } from './hd-deriver'; -import { getActiveNetwork } from '../active-chain'; - -export async function getClient(): Promise { - const account = await getHDAccount(); - const networkInfos = await getActiveNetwork(); - - if (!account) { - return undefined; - } - - return ClientFactory.createCustomClient( - [{ url: networkInfos.rpcUrl, type: ProviderType.PUBLIC }], - BigInt(networkInfos.chainId), - true, - account, - ); -} - -export async function getClientWallet(): Promise { - const client = await getClient(); - if (!client) { - return undefined; - } - return client.wallet(); -} diff --git a/packages/snap/src/accounts/hd-deriver.ts b/packages/snap/src/accounts/hd-deriver.ts index f70a06b..1946451 100644 --- a/packages/snap/src/accounts/hd-deriver.ts +++ b/packages/snap/src/accounts/hd-deriver.ts @@ -1,24 +1,15 @@ -import type { IAccount } from '@massalabs/massa-web3'; -import { - utils, - KEYS_VERSION_NUMBER, - SECRET_KEY_PREFIX, - WalletClient, -} from '@massalabs/massa-web3'; +import { Account, PrivateKey } from '@massalabs/massa-web3'; import type { JsonSLIP10Node } from '@metamask/key-tree'; +import varint from 'varint'; -/** - * - */ -export async function getHDAccount(): Promise { +const KEYS_VERSION_NUMBER = 0; + +export async function getHDAccount(): Promise { const secretKey = await retrieveSecretKey(); - return WalletClient.getAccountFromSecretKey(secretKey); + return Account.fromPrivateKey(secretKey); } -/** - * - */ -async function retrieveSecretKey(): Promise { +async function retrieveSecretKey(): Promise { const account = await retrieveSlip10Path(); if (!account?.privateKey) { @@ -27,18 +18,12 @@ async function retrieveSecretKey(): Promise { const bytes = new TextEncoder().encode(account.privateKey.slice(0, 32)); - const version = Uint8Array.from( - utils.crypto.varintEncode(KEYS_VERSION_NUMBER), - ); - const encoded = utils.crypto.base58Encode( - Uint8Array.from([...version, ...bytes]), - ); - return SECRET_KEY_PREFIX + encoded; + // add version number to the key bytes + const versionBytes = varint.encode(KEYS_VERSION_NUMBER); + const keyBytes = new Uint8Array([...versionBytes, ...bytes]); + return PrivateKey.fromBytes(keyBytes); } -/** - * - */ async function retrieveSlip10Path(): Promise { const entropy = await snap.request({ method: 'snap_getBip32Entropy', diff --git a/packages/snap/src/accounts/provider.ts b/packages/snap/src/accounts/provider.ts new file mode 100644 index 0000000..d2c62b0 --- /dev/null +++ b/packages/snap/src/accounts/provider.ts @@ -0,0 +1,10 @@ +import { Provider, Web3Provider } from '@massalabs/massa-web3'; + +import { getHDAccount } from './hd-deriver'; +import { getActiveNetwork } from '../active-chain'; + +export async function getProvider(): Promise { + const account = await getHDAccount(); + const networkInfos = await getActiveNetwork(); + return Web3Provider.fromRPCUrl(networkInfos.rpcUrl, account); +} diff --git a/packages/snap/src/active-chain.ts b/packages/snap/src/active-chain.ts index a085ef7..d4e3095 100644 --- a/packages/snap/src/active-chain.ts +++ b/packages/snap/src/active-chain.ts @@ -1,20 +1,20 @@ +import { StateManager } from './state-manager'; +import { NetworkInfos } from './network'; import { CHAIN_ID, - DefaultProviderUrls, - fromMAS, - MAINNET, + Mas, + NetworkName, + PublicApiUrl, } from '@massalabs/massa-web3'; -import { StateManager } from './state-manager'; -import { NetworkInfos } from './network'; const NETWORK_INFO_KEY = 'network_info'; -export const DEFAULT_MINIMAL_FEES = fromMAS('0.01').toString(); +export const DEFAULT_MINIMAL_FEES = Mas.fromString('0.01').toString(); export const DEFAULT_NETWORK = { - rpcUrl: DefaultProviderUrls.MAINNET, - chainId: CHAIN_ID.MainNet.toString(), + rpcUrl: PublicApiUrl.Mainnet, + chainId: CHAIN_ID.Mainnet.toString(), minimalFees: DEFAULT_MINIMAL_FEES, - networkName: MAINNET, + networkName: NetworkName.Mainnet, }; /** * @description Get the current network diff --git a/packages/snap/src/components/CallSc.tsx b/packages/snap/src/components/CallSc.tsx index 99daf56..148a8df 100644 --- a/packages/snap/src/components/CallSc.tsx +++ b/packages/snap/src/components/CallSc.tsx @@ -1,4 +1,4 @@ -import { toMAS } from '@massalabs/massa-web3'; +import { Mas } from '@massalabs/massa-web3'; import { SnapComponent, Container, @@ -36,16 +36,20 @@ export const CallSc: SnapComponent = (params: CallScProps) => { Coins: - {toMAS(params.coins).toString()} MAS + {Mas.toString(BigInt(params.coins))} MAS Fee: - {toMAS(params.fee).toString()} MAS - - - Arguments: - {params.args.toString()} + {Mas.toString(BigInt(params.fee))} MAS + {params.args.length ? ( + + Arguments: + {params.args.toString()} + + ) : ( + <> + )} diff --git a/packages/snap/src/components/HomePage.tsx b/packages/snap/src/components/HomePage.tsx index 1b1cca8..be9f9c8 100644 --- a/packages/snap/src/components/HomePage.tsx +++ b/packages/snap/src/components/HomePage.tsx @@ -1,9 +1,3 @@ -import { - BUILDNET, - CHAIN_ID_TO_NETWORK_NAME, - LABNET, - MAINNET, -} from '@massalabs/massa-web3'; import { SnapComponent, Container, @@ -21,6 +15,7 @@ import { Input, } from '@metamask/snaps-sdk/jsx'; import type { NetworkInfos } from '../network'; +import { NetworkName } from '@massalabs/massa-web3'; type HomePageProps = { networkInfo: NetworkInfos; @@ -33,12 +28,10 @@ export const HomePage: SnapComponent = ({ address, balance, }) => { - const networkName = CHAIN_ID_TO_NETWORK_NAME[networkInfo.chainId] ?? 'Custom'; - const networkList = - networkName === MAINNET - ? [MAINNET, BUILDNET, LABNET] - : [BUILDNET, MAINNET, LABNET]; + networkInfo.networkName === NetworkName.Mainnet + ? [NetworkName.Mainnet, NetworkName.Buildnet] + : [NetworkName.Buildnet, NetworkName.Mainnet]; const dropDown = ( @@ -55,7 +48,11 @@ export const HomePage: SnapComponent = ({ Network: - + Select a network: {dropDown}
diff --git a/packages/snap/src/components/index.tsx b/packages/snap/src/components/index.tsx index 2cee69c..343031f 100644 --- a/packages/snap/src/components/index.tsx +++ b/packages/snap/src/components/index.tsx @@ -20,9 +20,9 @@ export async function showKeys(id: string) { id, ui: ( ), }, diff --git a/packages/snap/src/dto.ts b/packages/snap/src/dto.ts deleted file mode 100644 index b528447..0000000 --- a/packages/snap/src/dto.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - Parameter specified by massa standard with an additionnal fee field -*/ -export type CallSCParameters = { - nickname: string; - fee: bigint; - functionName: string; - at: string; - args: number[]; - coins: string; - nonPersistentExecution?: { - isNPE: boolean; - maxGas: string; - }; -}; - -export type CallSCResponse = { - operationId: string; -}; diff --git a/packages/snap/src/handlers/add-token.ts b/packages/snap/src/handlers/add-token.ts index 331a69b..521aa5b 100644 --- a/packages/snap/src/handlers/add-token.ts +++ b/packages/snap/src/handlers/add-token.ts @@ -1,26 +1,21 @@ -import { getHDAccount } from '../accounts/hd-deriver'; +import { Address } from '@massalabs/massa-web3'; import { addAccountToken } from '../tokens'; import type { Handler } from './handler'; +import { getProvider } from '../accounts/provider'; export type AddTokenParams = { address: string; }; export type AddTokenResponse = { - address: string; - accountAddress: string; + response: 'OK'; }; -/** - * @description Coerces the add token parameters to the correct types - * @param params - The add token parameters - * @returns The coerced add token parameters - * @throws An error if the address is not a string - */ -const coerceParams = (params: AddTokenParams): AddTokenParams => { + +const validate = (params: AddTokenParams) => { if (!params.address || typeof params.address !== 'string') { throw new Error('Invalid params: address must be a string'); } - return params; + Address.fromString(params.address); }; /** @@ -32,17 +27,8 @@ const coerceParams = (params: AddTokenParams): AddTokenParams => { export const addToken: Handler = async ( params, ) => { - const { address } = coerceParams(params); - const account = await getHDAccount(); - - if (!account) { - throw new Error('Not logged in to metamask. Please log in and try again.'); - } - - await addAccountToken(account.address!, address); - - return { - address, - accountAddress: account.address!, - }; + validate(params); + const provider = await getProvider(); + await addAccountToken(provider.address, params.address); + return { response: 'OK' }; }; diff --git a/packages/snap/src/handlers/buy-rolls.ts b/packages/snap/src/handlers/buy-rolls.ts index bbe13f5..de1918d 100644 --- a/packages/snap/src/handlers/buy-rolls.ts +++ b/packages/snap/src/handlers/buy-rolls.ts @@ -1,13 +1,13 @@ -import type { IRollsData, WalletClient } from '@massalabs/massa-web3'; import { panel, text } from '@metamask/snaps-sdk'; -import { getClientWallet } from '../accounts/clients'; import type { Handler } from './handler'; import { addAccountOperation } from '../operations'; -import { getHDAccount } from '../accounts/hd-deriver'; +import { getProvider } from '../accounts/provider'; +import { Mas } from '@massalabs/massa-web3'; +import { getActiveNetwork } from '../active-chain'; export type BuyRollsParams = { - fee: string; + fee?: string; amount: string; }; @@ -15,18 +15,16 @@ export type BuyRollsResponse = { operationId: string; }; -const coerceParams = (params: BuyRollsParams): IRollsData => { - if (!params.fee || typeof params.fee !== 'string') { - throw new Error('Invalid params: fee must be a string'); - } +const validate = (params: BuyRollsParams) => { if (!params.amount || typeof params.amount !== 'string') { throw new Error('Invalid params: amount must be a string'); } - return { - fee: BigInt(params.fee), - amount: BigInt(params.amount), - }; + // optionnal parameters + if (params.fee && typeof params.fee !== 'string') { + throw new Error('Invalid params: fee must be a string'); + } }; + /** * @description Buys rolls with the given amount and fee * @param params - The buy rolls parameters (fee and amount) @@ -35,13 +33,11 @@ const coerceParams = (params: BuyRollsParams): IRollsData => { export const buyRolls: Handler = async ( params, ) => { - const rollsData = coerceParams(params); - const wallet: WalletClient | undefined = await getClientWallet(); - const account = await getHDAccount(); - - if (!account) { - throw new Error('Account not found or client not logged in'); - } + validate(params); + const provider = await getProvider(); + const networkInfos = await getActiveNetwork(); + const amount = BigInt(params.amount); + const fee = BigInt(params.fee ? params.fee : networkInfos.minimalFees); const confirm = await snap.request({ method: 'snap_dialog', @@ -49,8 +45,8 @@ export const buyRolls: Handler = async ( type: 'confirmation', content: panel([ text('**Do you want to buy rolls ?**'), - text(`**Amount:** ${rollsData.amount.toString()}`), - text(`**Fee:** ${rollsData.fee.toString()}`), + text(`**Amount:** ${params.amount.toString()}`), + text(`**Fee:** ${Mas.toString(fee)} MAS`), ]), }, }); @@ -59,13 +55,9 @@ export const buyRolls: Handler = async ( throw new Error('User denied buy rolls'); } - if (!wallet) { - throw new Error('Wallet not found'); - } - - const operationId = await wallet.buyRolls(rollsData); + const operation = await provider.buyRolls(amount, { fee }); - await addAccountOperation(account.address!, operationId[0]!); + await addAccountOperation(provider.address, operation.id); - return { operationId: operationId[0]! }; + return { operationId: operation.id }; }; diff --git a/packages/snap/src/handlers/call-smart-contract.tsx b/packages/snap/src/handlers/call-smart-contract.tsx index 60af5a5..ed1f6de 100644 --- a/packages/snap/src/handlers/call-smart-contract.tsx +++ b/packages/snap/src/handlers/call-smart-contract.tsx @@ -1,16 +1,16 @@ -import type { ICallData } from '@massalabs/massa-web3'; -import { getClient } from '../accounts/clients'; -import { getHDAccount } from '../accounts/hd-deriver'; +import { getProvider } from '../accounts/provider'; import { addAccountOperation } from '../operations'; import type { Handler } from './handler'; import { CallSc } from '../components/CallSc'; +import { Address, CallSCParams } from '@massalabs/massa-web3'; +import { getActiveNetwork } from '../active-chain'; export type CallSCParameters = { - fee: string; + fee?: string; functionName: string; at: string; - args: number[]; - coins: string; + args?: number[]; + coins?: string; maxGas?: string; }; @@ -18,41 +18,30 @@ export type CallSCResponse = { operationId: string; }; -/** - * Coerce the call smart contract parameters by ensuring the parameters are present and are the correct type - * @param params - The call smart contract parameters - * @returns The call smart contract parameters - * @throws If the nickname, fee, functionName, at, args, or coins is missing or not a string - */ -const coerceParams = (params: CallSCParameters): ICallData => { +const validate = (params: CallSCParameters) => { // mandatory parameters - if (!params.fee || typeof params.fee !== 'string') { - throw new Error('Invalid params: fee must be a string'); - } else if (!params.functionName || typeof params.functionName !== 'string') { + + if (!params.functionName || typeof params.functionName !== 'string') { throw new Error('Invalid params: functionName must be a string'); - } else if (!params.at || typeof params.at !== 'string') { + } + if (!params.at || typeof params.at !== 'string') { throw new Error('Invalid params: at must be a string'); - } else if (!params.args || !Array.isArray(params.args)) { + } + Address.fromString(params.at); + + // optionnal parameters + if (params.args && !Array.isArray(params.args)) { throw new Error('Invalid params: args must be an array'); - // optionnal parameters - } else if (params?.coins && typeof params.coins !== 'string') { - throw new Error('Invalid params: coins must be a string'); - } else if (params?.maxGas && typeof params.maxGas !== 'string') { - throw new Error('Invalid params: maxGas must be a string'); } - const req = { - fee: BigInt(params.fee), - targetAddress: params.at, - targetFunction: params.functionName, - parameter: params.args, - } as ICallData; - if (params.maxGas) { - req.maxGas = BigInt(params.maxGas); + if (params.fee && typeof params.fee !== 'string') { + throw new Error('Invalid params: fee must be a string'); } - if (params.coins) { - req.coins = BigInt(params.coins); + if (params?.coins && typeof params.coins !== 'string') { + throw new Error('Invalid params: coins must be a string'); + } + if (params?.maxGas && typeof params.maxGas !== 'string') { + throw new Error('Invalid params: maxGas must be a string'); } - return req; }; /** * @description Calls a smart contract with the given parameters @@ -65,13 +54,11 @@ export const callSmartContract: Handler< CallSCParameters, CallSCResponse > = async (params) => { - const client = await getClient(); - const account = await getHDAccount(); - const callData = coerceParams(params); + validate(params); + const provider = await getProvider(); - if (!account || !client) { - throw new Error('Client not found or not logged in'); - } + const networkInfos = await getActiveNetwork(); + const fee = params.fee ? params.fee : networkInfos.minimalFees; const confirm = await snap.request({ method: 'snap_dialog', @@ -79,11 +66,11 @@ export const callSmartContract: Handler< type: 'confirmation', content: ( ), }, @@ -92,9 +79,22 @@ export const callSmartContract: Handler< if (!confirm) { throw new Error('User denied calling smart contract'); } - const operationId = await client.smartContracts().callSmartContract(callData); - await addAccountOperation(account.address!, operationId); + const callSCParams: CallSCParams = { + func: params.functionName, + target: params.at, + parameter: Uint8Array.from(params.args ?? []), + fee: BigInt(fee), + }; + + if (params.coins) { + callSCParams.coins = BigInt(params.coins); + } + if (params.maxGas) { + callSCParams.maxGas = BigInt(params.maxGas); + } + const operation = await provider.callSC(callSCParams); + await addAccountOperation(provider.address, operation.id); return { - operationId, + operationId: operation.id, }; }; diff --git a/packages/snap/src/handlers/clear-operations.ts b/packages/snap/src/handlers/clear-operations.ts index 04129bf..29941ba 100644 --- a/packages/snap/src/handlers/clear-operations.ts +++ b/packages/snap/src/handlers/clear-operations.ts @@ -17,13 +17,6 @@ export const clearOperations: Handler< ClearOperationsResponse > = async () => { const account = await getHDAccount(); - - if (!account) { - return { - response: 'ERROR', - message: `Not logged in to metamask. Please log in and try again.`, - }; - } - await clearAccountOperations(account.address!); + await clearAccountOperations(account.address.toString()); return { response: 'OK' }; }; diff --git a/packages/snap/src/handlers/delete-token.ts b/packages/snap/src/handlers/delete-token.ts index d6dfa05..0a8915d 100644 --- a/packages/snap/src/handlers/delete-token.ts +++ b/packages/snap/src/handlers/delete-token.ts @@ -11,16 +11,10 @@ export type DeleteTokenResponse = { message?: string; }; -/** - * @description Coerces the delete token parameters to the correct types - * @param params - The delete token parameters - * @returns The response of the operation - */ -const coerceParams = (params: DeleteTokenParams): DeleteTokenParams => { +const validate = (params: DeleteTokenParams) => { if (!params.address || typeof params.address !== 'string') { throw new Error('Invalid params: address must be a string'); } - return params; }; /** @@ -32,11 +26,11 @@ export const deleteToken: Handler< DeleteTokenParams, DeleteTokenResponse > = async (params) => { - const { address } = coerceParams(params); - const account = (await getHDAccount()).address!; - const res = await removeAccountToken(account, address); + validate(params); + const { address } = await getHDAccount(); + const ok = await removeAccountToken(address.toString(), params.address); - if (res) { + if (ok) { return { response: 'OK' }; } return { response: 'ERROR', message: 'Token not found' }; diff --git a/packages/snap/src/handlers/get-active-account.ts b/packages/snap/src/handlers/get-active-account.ts index 082e6a6..4161879 100644 --- a/packages/snap/src/handlers/get-active-account.ts +++ b/packages/snap/src/handlers/get-active-account.ts @@ -13,13 +13,9 @@ export const getActiveAccount: Handler< void, GetActiveAccountResponse > = async () => { - const account = await getHDAccount(); - - if (!account) { - throw new Error(`Not logged in to metamask. Please log in and try again.`); - } + const { address } = await getHDAccount(); return { - address: account.address!, + address: address.toString(), }; }; diff --git a/packages/snap/src/handlers/get-balance.ts b/packages/snap/src/handlers/get-balance.ts index 783572b..67a0992 100644 --- a/packages/snap/src/handlers/get-balance.ts +++ b/packages/snap/src/handlers/get-balance.ts @@ -1,6 +1,6 @@ -import { getClientWallet } from '../accounts/clients'; -import { getHDAccount } from '../accounts/hd-deriver'; +import { getProvider } from '../accounts/provider'; import type { Handler } from './handler'; +import { Address } from '@massalabs/massa-web3'; export type GetBalanceParams = { address: string; @@ -11,17 +11,11 @@ export type GetBalanceResponse = { candidateBalance: string; }; -/** - * @description Coerces the get balance parameters to the expected format - * @param params - The get balance parameters - * @returns The coerced parameters - * @throws If the parameters are invalid - */ -const coerceParams = (params: GetBalanceParams): string => { +const validate = (params: GetBalanceParams) => { if (!params.address || typeof params.address !== 'string') { throw new Error('Invalid params: address must be a string'); } - return params.address; + Address.fromString(params.address); }; /** @@ -33,20 +27,20 @@ const coerceParams = (params: GetBalanceParams): string => { export const getBalance: Handler = async ( params, ) => { - const wallet = await getClientWallet(); - const { address } = await getHDAccount(); - const requestedAddress = coerceParams(params); + validate(params); - if (!wallet || !address) { - throw new Error(`Not logged in to metamask. Please log in and try again.`); - } - if (address !== requestedAddress) { - throw new Error(`Account not found: ${requestedAddress}`); + const provider = await getProvider(); + + if (provider.address !== params.address) { + throw new Error(`Account not found: ${params.address}`); } - const balance = await wallet.getAccountBalance(address); + const [final, candidate] = await Promise.all([ + provider.balance(true), + provider.balance(false), + ]); return { - finalBalance: balance?.final?.toString() || '0', - candidateBalance: balance?.candidate?.toString() || '0', + finalBalance: final.toString(), + candidateBalance: candidate.toString(), }; }; diff --git a/packages/snap/src/handlers/get-operations.ts b/packages/snap/src/handlers/get-operations.ts index fe6a7cf..243e98e 100644 --- a/packages/snap/src/handlers/get-operations.ts +++ b/packages/snap/src/handlers/get-operations.ts @@ -17,14 +17,9 @@ export const getOperations: Handler< GetOperationsParams, GetOperationsResponse > = async () => { - const account = await getHDAccount(); + const { address } = await getHDAccount(); - if (!account) { - throw new Error( - `Account not found: please log into the metamask and try again.`, - ); - } return { - operations: await getAccountOperations(account.address!), + operations: await getAccountOperations(address.toString()), }; }; diff --git a/packages/snap/src/handlers/get-tokens.ts b/packages/snap/src/handlers/get-tokens.ts index c7ea8e3..720f72d 100644 --- a/packages/snap/src/handlers/get-tokens.ts +++ b/packages/snap/src/handlers/get-tokens.ts @@ -17,12 +17,8 @@ export const getTokens: Handler< GetTokensParams, GetTokensResponse > = async () => { - const account = await getHDAccount(); - - if (!account) { - throw new Error(`Not logged in to metamask. Please log in and try again.`); - } + const { address } = await getHDAccount(); return { - tokens: await getAccountTokens(account.address!), + tokens: await getAccountTokens(address.toString()), }; }; diff --git a/packages/snap/src/handlers/read-smart-contract.ts b/packages/snap/src/handlers/read-smart-contract.ts index f4a01bc..f16e1cc 100644 --- a/packages/snap/src/handlers/read-smart-contract.ts +++ b/packages/snap/src/handlers/read-smart-contract.ts @@ -1,14 +1,12 @@ -import type { IReadData } from '@massalabs/massa-web3'; -import { getClient } from '../accounts/clients'; -import { getHDAccount } from '../accounts/hd-deriver'; +import { Address, ReadSCParams } from '@massalabs/massa-web3'; import type { Handler } from './handler'; -import { SnapError } from '@metamask/snaps-sdk'; +import { getProvider } from '../accounts/provider'; export type ReadSCParameters = { fee?: string; functionName: string; at: string; - args: number[]; + args?: number[]; coins?: string; maxGas?: string; caller?: string; @@ -21,50 +19,35 @@ export type ReadSCResponse = { }; }; -/** - * Coerce the call smart contract parameters by ensuring the parameters are present and are the correct type - * @param params - The call smart contract parameters - * @returns The call smart contract parameters - * @throws If the nickname, fee, functionName, at, args, or coins is missing or not a string - */ -const coerceParams = (params: ReadSCParameters): IReadData => { +const validate = (params: ReadSCParameters) => { // mandatory parameters if (!params.functionName || typeof params.functionName !== 'string') { throw new Error('Invalid params: functionName must be a string'); - } else if (!params.at || typeof params.at !== 'string') { + } + if (!params.at || typeof params.at !== 'string') { throw new Error('Invalid params: at must be a string'); - } else if (!params.args || !Array.isArray(params.args)) { - throw new Error('Invalid params: args must be an array'); - // optionnal parameters - } else if (params?.fee && typeof params.fee !== 'string') { - throw new Error('Invalid params: fee must be a string'); - } else if (params?.coins && typeof params.coins !== 'string') { - throw new Error('Invalid params: coins must be a string'); - } else if (params?.maxGas && typeof params.maxGas !== 'string') { - throw new Error('Invalid params: maxGas must be a string'); - } else if (params?.caller && typeof params.caller !== 'string') { - throw new Error('Invalid params: caller must be a string'); } + Address.fromString(params.at); - const req = { - targetAddress: params.at, - targetFunction: params.functionName, - parameter: params.args, - } as IReadData; - - if (params.fee) { - req.fee = BigInt(params.fee); + // optionnal parameters + if (params.args && !Array.isArray(params.args)) { + throw new Error('Invalid params: args must be an Uint8Array'); } - if (params.coins) { - req.coins = BigInt(params.coins); + if (params.fee && typeof params.fee !== 'string') { + throw new Error('Invalid params: fee must be a string'); } - if (params.maxGas) { - req.maxGas = BigInt(params.maxGas); + if (params.coins && typeof params.coins !== 'string') { + throw new Error('Invalid params: coins must be a string'); + } + if (params.maxGas && typeof params.maxGas !== 'string') { + throw new Error('Invalid params: maxGas must be a string'); + } + if (params.caller && typeof params.caller !== 'string') { + throw new Error('Invalid params: caller must be a string'); } if (params.caller) { - req.callerAddress = params.caller; + Address.fromString(params.caller); } - return req; }; /** * @description Calls a smart contract with the given parameters @@ -77,20 +60,32 @@ export const readSmartContract: Handler< ReadSCParameters, ReadSCResponse > = async (params) => { - const client = await getClient(); - const account = await getHDAccount(); - const callData = coerceParams(params); + validate(params); + const provider = await getProvider(); - if (!account || !client) { - throw new SnapError('Client not found or not logged in'); + const readSCParams: ReadSCParams = { + func: params.functionName, + target: params.at, + parameter: Uint8Array.from(params.args ?? []), + }; + if (params.fee) { + readSCParams.fee = BigInt(params.fee); + } + if (params.coins) { + readSCParams.coins = BigInt(params.coins); + } + if (params.maxGas) { + readSCParams.maxGas = BigInt(params.maxGas); + } + if (params.caller) { + readSCParams.caller = params.caller; } - const res = await client.smartContracts().readSmartContract(callData); - + const res = await provider.readSC(readSCParams); return { - data: Array.from(res.returnValue), + data: Array.from(res.value), infos: { - gasCost: res.info.gas_cost, + gasCost: res.info.gasCost, }, }; }; diff --git a/packages/snap/src/handlers/sell-rolls.ts b/packages/snap/src/handlers/sell-rolls.ts index 777b920..4567321 100644 --- a/packages/snap/src/handlers/sell-rolls.ts +++ b/packages/snap/src/handlers/sell-rolls.ts @@ -1,10 +1,10 @@ -import type { IRollsData } from '@massalabs/massa-web3'; import { panel, text } from '@metamask/snaps-sdk'; -import { getClientWallet } from '../accounts/clients'; import type { Handler } from './handler'; import { addAccountOperation } from '../operations'; -import { getHDAccount } from '../accounts/hd-deriver'; +import { getProvider } from '../accounts/provider'; +import { getActiveNetwork } from '../active-chain'; +import { Mas } from '@massalabs/massa-web3'; export type SellRollsParams = { fee: string; @@ -15,23 +15,14 @@ export type SellRollsResponse = { operationId: string; }; -/** - * @description Coerce the sell rolls parameters by ensuring the parameters are present and are the correct type - * @param params - The sell rolls parameters - * @returns The sell rolls parameters - * @throws If the fee or amount is missing or not a string - */ -const coerceParams = (params: SellRollsParams): IRollsData => { - if (!params.fee || typeof params.fee !== 'string') { - throw new Error('Invalid params: fee must be a string'); - } +const validate = (params: SellRollsParams) => { if (!params.amount || typeof params.amount !== 'string') { throw new Error('Invalid params: amount must be a string'); } - return { - fee: BigInt(params.fee), - amount: BigInt(params.amount), - }; + // optionnal parameters + if (params.fee && typeof params.fee !== 'string') { + throw new Error('Invalid params: fee must be a string'); + } }; /** * @description Sells rolls using 'massa-web3' and adds the operation to the account @@ -41,17 +32,11 @@ const coerceParams = (params: SellRollsParams): IRollsData => { export const sellRolls: Handler = async ( params, ) => { - const rollsData = coerceParams(params); - const wallet = await getClientWallet(); - const account = await getHDAccount(); - - if (!wallet) { - throw new Error('Not logged in to metamask. Please log in and try again.'); - } - - if (!account) { - throw new Error('Account not found or client not logged in'); - } + validate(params); + const provider = await getProvider(); + const networkInfos = await getActiveNetwork(); + const amount = BigInt(params.amount); + const fee = BigInt(params.fee ? params.fee : networkInfos.minimalFees); const confirm = await snap.request({ method: 'snap_dialog', @@ -59,8 +44,8 @@ export const sellRolls: Handler = async ( type: 'confirmation', content: panel([ text('**Do you want to sell rolls ?**'), - text(`**Amount:** ${rollsData.amount.toString()}`), - text(`**Fee:** ${rollsData.fee.toString()}`), + text(`**Amount:** ${params.amount}`), + text(`**Fee:** ${Mas.toString(fee)} MAS`), ]), }, }); @@ -69,9 +54,9 @@ export const sellRolls: Handler = async ( throw new Error('User denied sell rolls'); } - const operationId = await wallet.sellRolls(rollsData); + const operation = await provider.sellRolls(amount, { fee }); - await addAccountOperation(account.address!, operationId[0]!); + await addAccountOperation(provider.address, operation.id); - return { operationId: operationId[0]! }; + return { operationId: operation.id }; }; diff --git a/packages/snap/src/handlers/set-network.tsx b/packages/snap/src/handlers/set-network.tsx index 82fbf48..90e6a19 100644 --- a/packages/snap/src/handlers/set-network.tsx +++ b/packages/snap/src/handlers/set-network.tsx @@ -1,7 +1,7 @@ import { setActiveNetwork } from '../active-chain'; import type { Handler } from './handler'; import { SwitchNetwork } from '../components/SwitchNetwork'; -import { fetchNetworkInfos } from '../network'; +import { fetchNetworkInfosFromUrl } from '../network'; export type SetNetworkParams = { network: string; @@ -11,17 +11,10 @@ export type SetNetworkResponse = { network: string; // url }; -/** - * @description Coerce the network parameter - * @param params - The network parameters - * @returns The network url as a bigint - */ -const coerceParams = (params: SetNetworkParams): string => { +const validate = (params: SetNetworkParams) => { if (!params.network || typeof params.network !== 'string') { throw new Error('Invalid params: network must be a string'); } - - return params.network; }; /** @@ -32,9 +25,9 @@ const coerceParams = (params: SetNetworkParams): string => { export const setNetwork: Handler = async ( params, ) => { - const network = coerceParams(params); + validate(params); - const networkInfos = await fetchNetworkInfos(network); + const networkInfos = await fetchNetworkInfosFromUrl(params.network); const confirm = await snap.request({ method: 'snap_dialog', @@ -50,5 +43,5 @@ export const setNetwork: Handler = async ( await setActiveNetwork(networkInfos); - return { network }; + return { network: params.network }; }; diff --git a/packages/snap/src/handlers/show-account-credentials.tsx b/packages/snap/src/handlers/show-account-credentials.tsx index ccb933a..e54e054 100644 --- a/packages/snap/src/handlers/show-account-credentials.tsx +++ b/packages/snap/src/handlers/show-account-credentials.tsx @@ -21,10 +21,7 @@ export const showAccountCredentials: Handler< > = async (params) => { const account = await getHDAccount(); - if (!account) { - throw new Error(`Not logged in to metamask. Please log in and try again.`); - } - if (params.address !== account.address) { + if (params.address !== account.address.toString()) { throw new Error(`Account not found: ${params.address}`); } @@ -51,9 +48,9 @@ export const showAccountCredentials: Handler< type: 'alert', content: ( ), }, diff --git a/packages/snap/src/handlers/sign-message.ts b/packages/snap/src/handlers/sign-message.ts index 59253f3..a124ae7 100644 --- a/packages/snap/src/handlers/sign-message.ts +++ b/packages/snap/src/handlers/sign-message.ts @@ -1,13 +1,9 @@ import { panel, text } from '@metamask/snaps-sdk'; - -import { getClientWallet } from '../accounts/clients'; -import { getHDAccount } from '../accounts/hd-deriver'; import type { Handler } from './handler'; -import { getActiveNetwork } from '../active-chain'; +import { getProvider } from '../accounts/provider'; export type SignMessageParams = { - data: number[]; - address: string; + data: number[] | string; }; export type SignMessageResponse = { @@ -15,21 +11,13 @@ export type SignMessageResponse = { publicKey: string; }; -/** - * @description Coerce the sign message parameters by ensuring the parameters are present and are the correct type - * @param params - The sign message parameters - * @returns The sign message parameters - */ -const coerceParams = (params: SignMessageParams): SignMessageParams => { +const validate = (params: SignMessageParams) => { if (!params.data) { - throw new Error('Data to sign is required!'); - } else if (!Array.isArray(params.data)) { - throw new Error('Data must be an array!'); - } else if (!params.address) { - throw new Error('Address to sign with is required!'); + throw new Error('No data provided'); + } + if (!(Array.isArray(params.data) || typeof params.data === 'string')) { + throw new Error('Invalid data type. Must be a Uint8Array or a string'); } - - return params; }; /** @@ -42,16 +30,8 @@ export const signMessage: Handler< SignMessageParams, SignMessageResponse > = async (params) => { - const { data, address: signingAddress } = coerceParams(params); - const wallet = await getClientWallet(); - const { address } = await getHDAccount(); - - if (!wallet || !address) { - throw new Error(`Not logged in to metamask. Please log in and try again.`); - } - if (address !== signingAddress) { - throw new Error(`Account not found: ${signingAddress}`); - } + validate(params); + const provider = await getProvider(); const confirm = await snap.request({ method: 'snap_dialog', @@ -59,7 +39,7 @@ export const signMessage: Handler< type: 'confirmation', content: panel([ text('Do you want to sign the following message ?'), - text(data.toString()), + text(params.data.toString()), ]), }, }); @@ -68,15 +48,7 @@ export const signMessage: Handler< throw new Error('User denied signing message'); } - const { chainId } = await getActiveNetwork(); - - const sig = await wallet.signMessage( - Buffer.from(data), - BigInt(chainId), - address, + return provider.sign( + Array.isArray(params.data) ? Uint8Array.from(params.data) : params.data, ); - return { - signature: sig.base58Encoded, - publicKey: sig.publicKey, - }; }; diff --git a/packages/snap/src/handlers/transfer.ts b/packages/snap/src/handlers/transfer.ts index 4769e1d..113f86f 100644 --- a/packages/snap/src/handlers/transfer.ts +++ b/packages/snap/src/handlers/transfer.ts @@ -1,40 +1,33 @@ -import { toMAS, type ITransactionData } from '@massalabs/massa-web3'; import { panel, text } from '@metamask/snaps-sdk'; - -import { getClient } from '../accounts/clients'; -import { getHDAccount } from '../accounts/hd-deriver'; import { addAccountOperation } from '../operations'; import type { Handler } from './handler'; +import { Address, Mas } from '@massalabs/massa-web3'; +import { getProvider } from '../accounts/provider'; +import { getActiveNetwork } from '../active-chain'; export type TransferParams = { recipientAddress: string; - amount: bigint; - fee: bigint; + amount: string; + fee?: string; }; export type TransferResponse = { operationId: string; }; -/** - * Coerce the transfer parameters by ensuring the parameters are present and are the correct type - * @param params - The transfer parameters - * @returns The transaction data - * @throws If the recipient address, amount, or fee is missing or not a string - */ -const coerceParams = (params: TransferParams): ITransactionData => { +const validate = (params: TransferParams) => { if (!params.recipientAddress || typeof params.recipientAddress !== 'string') { throw new Error('Invalid params: recipientAddress must be a string'); - } else if (!params.amount || typeof params.amount !== 'string') { + } + Address.fromString(params.recipientAddress); + + if (!params.amount || typeof params.amount !== 'string') { throw new Error('Invalid params: amount must be a string'); - } else if (!params.fee || typeof params.fee !== 'string') { + } + // optionnal parameters + if (params.fee && typeof params.fee !== 'string') { throw new Error('Invalid params: fee must be a string'); } - return { - recipientAddress: params.recipientAddress, - amount: BigInt(params.amount), - fee: BigInt(params.fee), - }; }; /** @@ -47,13 +40,11 @@ const coerceParams = (params: TransferParams): ITransactionData => { export const transfer: Handler = async ( params, ) => { - const account = await getHDAccount(); - const client = await getClient(); - const deserialized = coerceParams(params); - - if (!account || !client) { - throw new Error('Not logged in to metamask. Please log in and try again.'); - } + validate(params); + const provider = await getProvider(); + const networkInfos = await getActiveNetwork(); + const amount = BigInt(params.amount); + const fee = BigInt(params.fee ? params.fee : networkInfos.minimalFees); const confirm = await snap.request({ method: 'snap_dialog', @@ -62,8 +53,8 @@ export const transfer: Handler = async ( content: panel([ text('**Do you want to send the following transaction?**'), text(`**Recipient:** ${params.recipientAddress}`), - text(`**Amount:** ${toMAS(params.amount)}`), - text(`**Fee:** ${toMAS(params.fee)}`), + text(`**Amount:** ${Mas.toString(amount)} MAS`), + text(`**Fee:** ${Mas.toString(fee)} MAS`), ]), }, }); @@ -72,13 +63,13 @@ export const transfer: Handler = async ( throw new Error('User denied sending transaction'); } - const operations = await client.wallet().sendTransaction(deserialized); - if (!operations.length) { - throw new Error('No operations returned'); - } - await addAccountOperation(account.address!, operations[0]!); + const operations = await provider.transfer(params.recipientAddress, amount, { + fee, + }); + + await addAccountOperation(provider.address, operations.id); return { - operationId: operations[0]!, + operationId: operations.id, }; }; diff --git a/packages/snap/src/index.tsx b/packages/snap/src/index.tsx index 137f82e..d5b3819 100644 --- a/packages/snap/src/index.tsx +++ b/packages/snap/src/index.tsx @@ -3,7 +3,6 @@ import { OnHomePageHandler, OnUserInputHandler, UserInputEventType, - type Json, type OnRpcRequestHandler, } from '@metamask/snaps-sdk'; @@ -41,16 +40,11 @@ import { clearOperations, } from './handlers'; import { getActiveAccount } from './handlers/get-active-account'; -import { - BUILDNET, - DefaultProviderUrls, - LABNET, - MAINNET, - toMAS, -} from '@massalabs/massa-web3'; -import { getHDAccount } from './accounts/hd-deriver'; + import { showKeysConfirmation, showKeys } from './components'; import { HomePage } from './components/HomePage'; +import { Mas, NetworkName, PublicApiUrl } from '@massalabs/massa-web3'; +import { getProvider } from './accounts/provider'; /** * Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`. * @@ -64,43 +58,39 @@ import { HomePage } from './components/HomePage'; export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { switch (request.method) { case 'account.balance': - return getBalance(request.params as unknown as GetBalanceParams); + return getBalance(request.params as GetBalanceParams); case 'account.sign': - return signMessage( - request.params as unknown as SignMessageParams, - ) as unknown as Promise; + return signMessage(request.params as SignMessageParams); case 'account.callSC': - return callSmartContract(request.params as unknown as CallSCParameters); + return callSmartContract(request.params as CallSCParameters); case 'account.readSC': - return readSmartContract(request.params as unknown as ReadSCParameters); + return readSmartContract(request.params as ReadSCParameters); case 'account.sendTransaction': - return transfer(request.params as unknown as TransferParams); + return transfer(request.params as TransferParams); case 'account.sellRolls': - return sellRolls(request.params as unknown as SellRollsParams); + return sellRolls(request.params as SellRollsParams); case 'account.buyRolls': - return buyRolls(request.params as unknown as BuyRollsParams); + return buyRolls(request.params as BuyRollsParams); case 'Provider.getNetwork': return getNetwork(); case 'Provider.setNetwork': - return setNetwork(request.params as unknown as SetNetworkParams); + return setNetwork(request.params as SetNetworkParams); case 'account.showCredentials': return showAccountCredentials( - request.params as unknown as ShowAccountCredentialsParams, + request.params as ShowAccountCredentialsParams, ); case 'account.getActive': return getActiveAccount(); case 'account.addToken': - return addToken(request.params as unknown as AddTokenParams); + return addToken(request.params as AddTokenParams); case 'account.deleteToken': - return deleteToken(request.params as unknown as DeleteTokenParams); + return deleteToken(request.params as DeleteTokenParams); case 'account.getTokens': - return getTokens(request.params as unknown as GetTokensParams); + return getTokens(request.params as GetTokensParams); case 'account.getOperations': - return getOperations(request.params as unknown as GetOperationsParams); + return getOperations(request.params as GetOperationsParams); case 'account.clearOperations': - return clearOperations( - request.params as unknown as ClearOperationsParams, - ); + return clearOperations(request.params as ClearOperationsParams); default: throw new Error('Method not found.'); } @@ -114,15 +104,16 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { */ export const onHomePage: OnHomePageHandler = async () => { const networkInfo = await getNetwork(); - const account = await getHDAccount(); - const balance = await getBalance({ address: account.address || '' }); + const provider = await getProvider(); + const address = provider.address; + const balance = await provider.balance(false); return { content: ( ), }; @@ -149,14 +140,11 @@ export const onUserInput: OnUserInputHandler = async ({ event, id }) => { assert(event.type === UserInputEventType.InputChangeEvent); let network = ''; switch (event.value) { - case MAINNET: - network = DefaultProviderUrls.MAINNET; - break; - case BUILDNET: - network = DefaultProviderUrls.BUILDNET; + case NetworkName.Mainnet: + network = PublicApiUrl.Mainnet; break; - case LABNET: - network = DefaultProviderUrls.LABNET; + case NetworkName.Buildnet: + network = PublicApiUrl.Buildnet; break; } await setNetwork({ network }); diff --git a/packages/snap/src/network.ts b/packages/snap/src/network.ts index e066fdf..e47c44b 100644 --- a/packages/snap/src/network.ts +++ b/packages/snap/src/network.ts @@ -1,9 +1,9 @@ import { - CHAIN_ID_TO_NETWORK_NAME, - fromMAS, - ProviderType, - PublicApiClient, + getNetworkNameByChainId, + Mas, + Web3Provider, } from '@massalabs/massa-web3'; +import { getHDAccount } from './accounts/hd-deriver'; export type NetworkInfos = { rpcUrl: string; @@ -12,19 +12,19 @@ export type NetworkInfos = { networkName: string; }; -export async function fetchNetworkInfos(url: string): Promise { - const client = new PublicApiClient({ - providers: [{ url, type: ProviderType.PUBLIC }], - }); +export async function fetchNetworkInfosFromUrl( + rpcUrl: string, +): Promise { + const account = await getHDAccount(); + const provider = Web3Provider.fromRPCUrl(rpcUrl, account); + const networkInfo = await provider.getNodeStatus(); - const node_status = await client.getNodeStatus(); - - const networkName = CHAIN_ID_TO_NETWORK_NAME[node_status.chain_id.toString()]; + const networkName = getNetworkNameByChainId(BigInt(networkInfo.chainId)); return { - rpcUrl: client.clientConfig.providers[0]!.url!, - chainId: node_status.chain_id.toString(), - minimalFees: fromMAS(node_status.minimal_fees!).toString(), + rpcUrl, + chainId: networkInfo.chainId.toString(), + minimalFees: Mas.fromString(networkInfo.minimalFees!).toString(), networkName: networkName ?? 'Custom', }; } diff --git a/packages/snap/src/operations.ts b/packages/snap/src/operations.ts index 565d186..eaccefd 100644 --- a/packages/snap/src/operations.ts +++ b/packages/snap/src/operations.ts @@ -1,3 +1,4 @@ +import { Address } from '@massalabs/massa-web3'; import { StateManager } from './state-manager'; // Account address -> OperationId[] @@ -32,13 +33,13 @@ export async function getAccountOperations(address: string): Promise { * @param operation - Operation id as a string prefixed with 'O' */ export async function addAccountOperation(address: string, operation: string) { - if (!address || !address.startsWith('AU')) { + if (!Address.fromString(address).isEOA) { throw new Error( - 'Invalid params: address must be a string and start with AU', + 'Invalid params: address must be a EOA address (prefixed with AU)', ); } - if (!operation || !operation.startsWith('O')) { + if (!operation.startsWith('O')) { throw new Error( 'Invalid params: operation must be a string and start with O', ); diff --git a/packages/snap/src/tokens.ts b/packages/snap/src/tokens.ts index b87a4d8..f70b5da 100644 --- a/packages/snap/src/tokens.ts +++ b/packages/snap/src/tokens.ts @@ -30,26 +30,26 @@ export async function getAccountTokens(address: string): Promise { * @param address - Account address as a string prefixed with 'AU' * @param token - Token smart contract address as a string prefixed with 'AS' */ -export async function addAccountToken(address: string, token: string) { - if (!address || !address.startsWith('AU')) { +export async function addAccountToken(account: string, token: string) { + if (!account.startsWith('AU')) { throw new Error( 'Invalid params: address must be a string and start with AU', ); } - if (!token || !token.startsWith('AS')) { + if (!token.startsWith('AS')) { throw new Error('Invalid params: token must be a string and start with AS'); } const accountsTokens: AccountsTokens = (await StateManager.getState('accountTokens')) || {}; - const tokens = accountsTokens[address] || []; + const tokens = accountsTokens[account] || []; - if (tokens.find((t) => t === token)) { + if (tokens.some((t) => t === token)) { return; } tokens.push(token); - accountsTokens[address] = tokens; + accountsTokens[account] = tokens; await StateManager.setState('accountTokens', accountsTokens); } @@ -63,13 +63,13 @@ export async function removeAccountToken( account: string, tokenAddress: string, ) { - if (!account || !account.startsWith('AU')) { + if (!account.startsWith('AU')) { throw new Error( 'Invalid params: address must be a string and start with AU', ); } - if (!tokenAddress || !tokenAddress.startsWith('AS')) { + if (!tokenAddress.startsWith('AS')) { throw new Error('Invalid params: token must be a string and start with AS'); } diff --git a/packages/snap/test/add-token.test.ts b/packages/snap/test/add-token.test.ts index 2b26872..0b44cbf 100644 --- a/packages/snap/test/add-token.test.ts +++ b/packages/snap/test/add-token.test.ts @@ -1,74 +1,60 @@ import { expect } from '@jest/globals'; import { installSnap } from '@metamask/snaps-jest'; -import type { GetActiveAccountResponse } from 'src/handlers/get-active-account'; +import { TOKEN } from './utils/constants'; + +const origin = 'Jest'; + +describe('add-token', () => { + it('should add a token for the default account', async () => { + const { request } = await installSnap(); + const response = await request({ + method: 'account.addToken', + origin, + params: { + address: TOKEN, + }, + }); -const tokens = ['AS1sKBEGsqtm8vQhQzi7KJ4YhyaKTSkhJrLkRc7mQtPqme3VcFHm']; + expect(response).toRespondWith({ response: 'OK' }); -describe('onRpcRequest', () => { - describe('add-token', () => { - it('should add a token for the default account', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const defaultAccount: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; + const getTokens = await request({ + method: 'account.getTokens', + origin, + }); + expect((getTokens.response as any).result.tokens).toEqual([TOKEN]); + }); - const response = await request({ - method: 'account.addToken', - origin, - params: { - //eslint-disable-next-line @typescript-eslint/no-non-null-assertion - address: tokens[0]!, - }, - }); + it('should throw an error when address is not a string', async () => { + const { request } = await installSnap(); - expect(response).toRespondWith({ - address: tokens[0], - accountAddress: defaultAccount.address, - }); + const response = request({ + method: 'account.addToken', + origin, + params: { + address: 123, + }, + }); - const getTokens = await request({ - method: 'account.getTokens', - origin, - }); - expect((getTokens.response as any).result.tokens).toEqual([tokens[0]]); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: address must be a string', + stack: expect.any(String), }); + }); - it('should throw an error when address is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const response = request({ - method: 'account.addToken', - origin, - params: { - address: 123, - }, - }); + it('should throw an error when address is missing', async () => { + const { request } = await installSnap(); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: address must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.addToken', + origin, + params: {}, }); - it('should throw an error when address is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const response = request({ - method: 'account.addToken', - origin, - params: {}, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: address must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: address must be a string', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/buy-rolls.test.ts b/packages/snap/test/buy-rolls.test.ts index 7438b4a..25d80e5 100644 --- a/packages/snap/test/buy-rolls.test.ts +++ b/packages/snap/test/buy-rolls.test.ts @@ -3,159 +3,120 @@ import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; import { panel, text } from '@metamask/snaps-sdk'; -import { setNetwork } from './utils/setNetwork'; -import { DefaultProviderUrls } from '@massalabs/massa-web3'; - -describe('onRpcRequest', () => { - describe('buy-rolls', () => { - it('should return an operation id', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.buyRolls', - origin, - params: { - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('**Do you want to buy rolls ?**'), - text('**Amount:** 1000000000000000'), - text('**Fee:** 1000000000000000'), - ]), - ); - - await ui.ok(); - expect(await response).toRespondWith({ - operationId: expect.any(String), - }); +describe('buy-rolls', () => { + const origin = 'Jest'; + + it('should return an operation id', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.buyRolls', + origin, + params: { + fee: '1000000000000000', + amount: '1000000000000000', + }, }); - it('should throw an error if the user deny the request', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.buyRolls', - origin, - params: { - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('**Do you want to buy rolls ?**'), - text('**Amount:** 1000000000000000'), - text('**Fee:** 1000000000000000'), - ]), - ); - - await ui.cancel(); - expect(await response).toRespondWithError({ - code: -32603, - message: 'User denied buy rolls', - stack: expect.any(String), - }); + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to buy rolls ?**'), + text('**Amount:** 1000000000000000'), + text('**Fee:** 1000000 MAS'), + ]), + ); + + await ui.ok(); + expect(await response).toRespondWith({ + operationId: expect.any(String), }); + }); + + it('should throw an error if the user deny the request', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.buyRolls', + origin, + params: { + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to buy rolls ?**'), + text('**Amount:** 1000000000000000'), + text('**Fee:** 1000000 MAS'), + ]), + ); + + await ui.cancel(); + expect(await response).toRespondWithError({ + code: -32603, + message: 'User denied buy rolls', + stack: expect.any(String), + }); + }); + + it('should throw an error if the fee is not a string', async () => { + const { request } = await installSnap(); - it('should throw an error if the fee is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.buyRolls', - origin, - params: { - fee: 100000000, - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.buyRolls', + origin, + params: { + fee: 100000000, + amount: '1000000000000000', + }, }); - it('should throw an error if the amount is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.buyRolls', - origin, - params: { - fee: '1000000000000000', - amount: 100000000, - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: amount must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: fee must be a string', + stack: expect.any(String), }); + }); + + it('should throw an error if the amount is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.buyRolls', + origin, + params: { + fee: '1000000000000000', + amount: 100000000, + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: amount must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the amount is missing', async () => { + const { request } = await installSnap(); - it('should throw an error if the fee is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.buyRolls', - origin, - params: { - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.buyRolls', + origin, + params: { + fee: '1000000000000000', + }, }); - it('should throw an error if the amount is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.buyRolls', - origin, - params: { - fee: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: amount must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: amount must be a string', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/call-sc.test.tsx b/packages/snap/test/call-sc.test.tsx index bb02d8e..044cf4d 100644 --- a/packages/snap/test/call-sc.test.tsx +++ b/packages/snap/test/call-sc.test.tsx @@ -2,8 +2,6 @@ import { expect } from '@jest/globals'; import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; -import { setNetwork } from './utils/setNetwork'; -import { DefaultProviderUrls } from '@massalabs/massa-web3'; import { CallSc } from '../src/components/CallSc'; const baseParams = { @@ -21,298 +19,236 @@ const baseParams = { maxGas: 10000000n.toString(), }; -describe('onRpcRequest', () => { - describe('call-sc', () => { - it('should return an operation id', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: baseParams, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - , - ); - - await ui.ok(); - expect(await response).toRespondWith({ - operationId: expect.any(String), - }); - - const operations = await request({ - method: 'account.getOperations', - origin, - params: {}, - }); - expect((operations.response as any).result.operations).toHaveLength(1); +describe('call-sc', () => { + const origin = 'Jest'; + + it('should return an operation id', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: baseParams, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + , + ); + + await ui.ok(); + expect(await response).toRespondWith({ + operationId: expect.any(String), + }); + + const operations = await request({ + method: 'account.getOperations', + origin, + params: {}, + }); + expect((operations.response as any).result.operations).toHaveLength(1); + }); + + it('should throw an error if the user deny the request', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: baseParams, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + , + ); + + await ui.cancel(); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'User denied calling smart contract', + stack: expect.any(String), + }); + }); + + it('should throw an error if the fee is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + fee: 1000000, + }, + }); + + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: fee must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the coins is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + coins: 1000000, + }, }); - it('should throw an error if the user deny the request', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: baseParams, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - , - ); - - await ui.cancel(); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'User denied calling smart contract', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: coins must be a string', + stack: expect.any(String), }); + }); + + it('should throw an error if the functionName is not a string', async () => { + const { request } = await installSnap(); - it('should throw an error if the fee is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - fee: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + functionName: 1000000, + }, }); - it('should throw an error if the coins is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - coins: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: coins must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: functionName must be a string', + stack: expect.any(String), }); + }); + + it('should throw an error if the at is not a string', async () => { + const { request } = await installSnap(); - it('should throw an error if the functionName is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - functionName: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: functionName must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + at: 1000000, + }, }); - it('should throw an error if the at is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - at: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: at must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: at must be a string', + stack: expect.any(String), }); + }); - it('should throw an error if the args is not an array', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - args: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: args must be an array', - stack: expect.any(String), - }); + it('should throw an error if the args is not an array', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + args: 1000000, + }, }); - it('should throw an error if the maxGas is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - maxGas: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: maxGas must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: args must be an array', + stack: expect.any(String), }); + }); - it('should throw an error if fee is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - fee: null, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); + it('should throw an error if the maxGas is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + maxGas: 1000000, + }, + }); + + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: maxGas must be a string', + stack: expect.any(String), }); + }); + + it('should throw an error if functionName is missing', async () => { + const { request } = await installSnap(); - it('should throw an error if functionName is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - functionName: null, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: functionName must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + functionName: null, + }, }); - it('should throw an error if at is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - at: null, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: at must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: functionName must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if at is missing', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.callSC', + origin, + params: { + ...baseParams, + at: null, + }, }); - it('should throw an error if args is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.callSC', - origin, - params: { - ...baseParams, - args: null, - }, - }); - - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: args must be an array', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: at must be a string', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/clear-operations.test.ts b/packages/snap/test/clear-operations.test.ts index 29be42e..3368fcf 100644 --- a/packages/snap/test/clear-operations.test.ts +++ b/packages/snap/test/clear-operations.test.ts @@ -1,54 +1,51 @@ import { expect } from '@jest/globals'; -import { DefaultProviderUrls, WalletClient } from '@massalabs/massa-web3'; import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; -import { setNetwork } from './utils/setNetwork'; - -describe('onRpcRequest', () => { - describe('clear-operations', () => { - it('should clear operations for account', async () => { - const { request } = await installSnap(); - const newAccount = await WalletClient.walletGenerateNewAccount(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', - origin, - params: { - recipientAddress: newAccount.address, - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - - await ui.ok(); - await response; - - const operations = await request({ - method: 'account.getOperations', - origin, - }); - expect((operations.response as any).result.operations).toHaveLength(1); - - const clearResponse = request({ - method: 'account.clearOperations', - origin, - }); - expect(await clearResponse).toRespondWith({ - response: 'OK', - }); - - const operationsAfterClear = await request({ - method: 'account.getOperations', - origin, - }); - expect( - (operationsAfterClear.response as any).result.operations, - ).toHaveLength(0); +import { Account } from '@massalabs/massa-web3'; + +describe('clear-operations', () => { + const origin = 'Jest'; + + it('should clear operations for account', async () => { + const { request } = await installSnap(); + const { address } = await Account.generate(); + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: address.toString(), + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + + await ui.ok(); + await response; + + const operations = await request({ + method: 'account.getOperations', + origin, + }); + expect((operations.response as any).result.operations).toHaveLength(1); + + const clearResponse = request({ + method: 'account.clearOperations', + origin, + }); + expect(await clearResponse).toRespondWith({ + response: 'OK', + }); + + const operationsAfterClear = await request({ + method: 'account.getOperations', + origin, }); + expect( + (operationsAfterClear.response as any).result.operations, + ).toHaveLength(0); }); }); diff --git a/packages/snap/test/delete-token.test.ts b/packages/snap/test/delete-token.test.ts index 004df61..dcd6ae1 100644 --- a/packages/snap/test/delete-token.test.ts +++ b/packages/snap/test/delete-token.test.ts @@ -1,17 +1,25 @@ import { expect } from '@jest/globals'; import { installSnap } from '@metamask/snaps-jest'; -import { addTokens } from './utils/addTokens'; -import type { GetActiveAccountResponse } from 'src/handlers/get-active-account'; +import type { GetActiveAccountResponse } from '../src/handlers/get-active-account'; +import { TOKEN } from './utils/constants'; -const tokens = ['AS1sKBEGsqtm8vQhQzi7KJ4YhyaKTSkhJrLkRc7mQtPqme3VcFHm']; +const origin = 'Jest'; describe('onRpcRequest', () => { describe('delete-token', () => { - it('should delete a token for the account', async () => { + it('should add and delete a token for the account', async () => { const { request } = await installSnap(); - await addTokens(request, tokens); - const origin = 'Jest'; + + const addResponse = await request({ + method: 'account.addToken', + origin, + params: { + address: TOKEN, + }, + }); + + expect(addResponse).toRespondWith({ response: 'OK' }); const defaultAccount: GetActiveAccountResponse = ( (await request({ @@ -26,8 +34,7 @@ describe('onRpcRequest', () => { method: 'account.deleteToken', origin, params: { - //eslint-disable-next-line @typescript-eslint/no-non-null-assertion - address: tokens[0]!, + address: TOKEN, }, }); @@ -44,9 +51,7 @@ describe('onRpcRequest', () => { it('should return an error when the token does not exist', async () => { const { request } = await installSnap(); - const origin = 'Jest'; - await addTokens(request, tokens); const response = request({ method: 'account.deleteToken', origin, @@ -63,7 +68,6 @@ describe('onRpcRequest', () => { it('should throw an error when address is not a string', async () => { const { request } = await installSnap(); - const origin = 'Jest'; const response = request({ method: 'account.deleteToken', origin, @@ -81,7 +85,6 @@ describe('onRpcRequest', () => { it('should throw an error when address is missing', async () => { const { request } = await installSnap(); - const origin = 'Jest'; const response = request({ method: 'account.deleteToken', origin, diff --git a/packages/snap/test/get-balance.test.ts b/packages/snap/test/get-balance.test.ts index 0a2b37f..cf88a22 100644 --- a/packages/snap/test/get-balance.test.ts +++ b/packages/snap/test/get-balance.test.ts @@ -1,89 +1,83 @@ import { expect } from '@jest/globals'; import { installSnap } from '@metamask/snaps-jest'; +import type { GetActiveAccountResponse } from '../src/handlers/get-active-account'; -import { setNetwork } from './utils/setNetwork'; -import type { GetActiveAccountResponse } from 'src/handlers/get-active-account'; -import { DefaultProviderUrls } from '@massalabs/massa-web3'; +describe('get-balance', () => { + const origin = 'Jest'; -describe('onRpcRequest', () => { - describe('get-balance', () => { - it('should get the balance of an account', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; + it('should get the balance of an account', async () => { + const { request } = await installSnap(); - const defaultAccount: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.balance', + const defaultAccount: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - address: defaultAccount.address, - }, - }); + })) as any + ).response.result; - expect(await response).toRespondWith({ - finalBalance: expect.any(String), - candidateBalance: expect.any(String), - }); + const response = request({ + method: 'account.balance', + origin, + params: { + address: defaultAccount.address, + }, }); - it('should throw an error account when address is invalid', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const response = request({ - method: 'account.balance', - origin, - params: { - address: 'AU00000000000000000000000000000000000000000000000000', // invalid address - }, - }); + expect(await response).toRespondWith({ + finalBalance: expect.any(String), + candidateBalance: expect.any(String), + }); + }); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: - 'Account not found: AU00000000000000000000000000000000000000000000000000', - stack: expect.any(String), - }); + it('should throw an error account when address is invalid', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.balance', + origin, + params: { + address: 'AU00000000000000000000000000000000000000000000000000', // invalid address + }, }); - it('should throw an error when address is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const response = request({ - method: 'account.balance', - origin, - params: { - address: 123, - }, - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'invalid address string: Non-base58 character', + stack: expect.any(String), + }); + }); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: address must be a string', - stack: expect.any(String), - }); + it('should throw an error when address is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.balance', + origin, + params: { + address: 123, + }, }); - it('should throw an error when address is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const response = request({ - method: 'account.balance', - origin, - params: {}, - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: address must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error when address is missing', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.balance', + origin, + params: {}, + }); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: 'Invalid params: address must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: 'Invalid params: address must be a string', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/get-network.test.ts b/packages/snap/test/get-network.test.ts index b89ff05..b611aa4 100644 --- a/packages/snap/test/get-network.test.ts +++ b/packages/snap/test/get-network.test.ts @@ -2,39 +2,33 @@ import { expect } from '@jest/globals'; import { installSnap } from '@metamask/snaps-jest'; import { setNetwork } from './utils/setNetwork'; -import { BUILDNET, CHAIN_ID, DefaultProviderUrls } from '@massalabs/massa-web3'; -import { DEFAULT_MINIMAL_FEES, DEFAULT_NETWORK } from '../src/active-chain'; +import { DEFAULT_NETWORK } from '../src/active-chain'; +import { PublicApiUrl } from '@massalabs/massa-web3'; +import { NETWORK } from './utils/constants'; -describe('onRpcRequest', () => { - describe('get-network', () => { - it('should get the default network', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; +describe('get-network', () => { + const origin = 'Jest'; - const response = request({ - method: 'Provider.getNetwork', - origin, - }); + it('should get the default network', async () => { + const { request } = await installSnap(); - expect(await response).toRespondWith(DEFAULT_NETWORK); + const response = request({ + method: 'Provider.getNetwork', + origin, }); - it('should get the url for the buildnet network', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); - const response = request({ - method: 'Provider.getNetwork', - origin, - }); - - expect(await response).toRespondWith({ - rpcUrl: DefaultProviderUrls.BUILDNET, - chainId: CHAIN_ID.BuildNet.toString(), - networkName: BUILDNET, - minimalFees: DEFAULT_MINIMAL_FEES, - }); + expect(await response).toRespondWith(DEFAULT_NETWORK); + }); + + it('should get the url for the buildnet network', async () => { + const { request } = await installSnap(); + + await setNetwork(request, PublicApiUrl.Buildnet); + const response = request({ + method: 'Provider.getNetwork', + origin, }); + + expect(await response).toRespondWith(NETWORK); }); }); diff --git a/packages/snap/test/read-sc.test.ts b/packages/snap/test/read-sc.test.ts index 2e1ae37..e0619af 100644 --- a/packages/snap/test/read-sc.test.ts +++ b/packages/snap/test/read-sc.test.ts @@ -1,12 +1,13 @@ import { expect } from '@jest/globals'; import { installSnap } from '@metamask/snaps-jest'; import { setNetwork } from './utils/setNetwork'; -import { Args, DefaultProviderUrls, u256ToBytes } from '@massalabs/massa-web3'; +import { Args, PublicApiUrl, U256 } from '@massalabs/massa-web3'; describe('read-sc', () => { + const origin = 'Jest'; + it('should call readSC', async () => { const { request } = await installSnap(); - const origin = 'Jest'; const baseParams = { fee: '100000000', @@ -21,7 +22,7 @@ describe('read-sc', () => { maxGas: 10000000n.toString(), }; - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet + await setNetwork(request, PublicApiUrl.Buildnet); const response = request({ method: 'account.readSC', origin, @@ -29,7 +30,7 @@ describe('read-sc', () => { }); expect(await response).toRespondWith({ - data: Array.from(u256ToBytes(0n)), + data: Array.from(U256.toBytes(0n)), infos: { gasCost: 2100000 }, }); }); diff --git a/packages/snap/test/sell-rolls.test.ts b/packages/snap/test/sell-rolls.test.ts index 812bb73..c5f6da9 100644 --- a/packages/snap/test/sell-rolls.test.ts +++ b/packages/snap/test/sell-rolls.test.ts @@ -3,159 +3,120 @@ import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; import { panel, text } from '@metamask/snaps-sdk'; -import { setNetwork } from './utils/setNetwork'; -import { DefaultProviderUrls } from '@massalabs/massa-web3'; - -describe('onRpcRequest', () => { - describe('sell-rolls', () => { - it('should return an operation id', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.sellRolls', - origin, - params: { - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('**Do you want to sell rolls ?**'), - text('**Amount:** 1000000000000000'), - text('**Fee:** 1000000000000000'), - ]), - ); - - await ui.ok(); - expect(await response).toRespondWith({ - operationId: expect.any(String), - }); +describe('sell-rolls', () => { + const origin = 'Jest'; + + it('should return an operation id', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.sellRolls', + origin, + params: { + fee: '1000000000000000', + amount: '1000000000000000', + }, }); - it('should throw an error if the user deny the request', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.sellRolls', - origin, - params: { - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('**Do you want to sell rolls ?**'), - text('**Amount:** 1000000000000000'), - text('**Fee:** 1000000000000000'), - ]), - ); - - await ui.cancel(); - expect(await response).toRespondWithError({ - code: -32603, - message: 'User denied sell rolls', - stack: expect.any(String), - }); + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to sell rolls ?**'), + text('**Amount:** 1000000000000000'), + text('**Fee:** 1000000 MAS'), + ]), + ); + + await ui.ok(); + expect(await response).toRespondWith({ + operationId: expect.any(String), }); + }); + + it('should throw an error if the user deny the request', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.sellRolls', + origin, + params: { + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to sell rolls ?**'), + text('**Amount:** 1000000000000000'), + text('**Fee:** 1000000 MAS'), + ]), + ); + + await ui.cancel(); + expect(await response).toRespondWithError({ + code: -32603, + message: 'User denied sell rolls', + stack: expect.any(String), + }); + }); + + it('should throw an error if the fee is not a string', async () => { + const { request } = await installSnap(); - it('should throw an error if the fee is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.sellRolls', - origin, - params: { - fee: 100000000, - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.sellRolls', + origin, + params: { + fee: 100000000, + amount: '1000000000000000', + }, }); - it('should throw an error if the amount is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.sellRolls', - origin, - params: { - fee: '1000000000000000', - amount: 100000000, - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: amount must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: fee must be a string', + stack: expect.any(String), }); + }); + + it('should throw an error if the amount is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.sellRolls', + origin, + params: { + fee: '1000000000000000', + amount: 100000000, + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: amount must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the amount is missing', async () => { + const { request } = await installSnap(); - it('should throw an error if the fee is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.sellRolls', - origin, - params: { - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); + const response = request({ + method: 'account.sellRolls', + origin, + params: { + fee: '1000000000000000', + }, }); - it('should throw an error if the amount is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - - const response = request({ - method: 'account.sellRolls', - origin, - params: { - fee: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: amount must be a string', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: amount must be a string', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/set-network.test.ts b/packages/snap/test/set-network.test.ts index c894794..83f162f 100644 --- a/packages/snap/test/set-network.test.ts +++ b/packages/snap/test/set-network.test.ts @@ -1,45 +1,40 @@ import { expect } from '@jest/globals'; import { installSnap } from '@metamask/snaps-jest'; -import { setNetwork } from './utils/setNetwork'; -import { BUILDNET, CHAIN_ID, DefaultProviderUrls } from '@massalabs/massa-web3'; +import { NETWORK } from './utils/constants'; +import { CHAIN_ID, NetworkName, PublicApiUrl } from '@massalabs/massa-web3'; import { DEFAULT_MINIMAL_FEES } from '../src/active-chain'; +import { setNetwork } from './utils/setNetwork'; + +const origin = 'Jest'; -describe('onRpcRequest', () => { - describe('set-network', () => { - it('should set the network to buildnet', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'Provider.getNetwork', - origin, - }); - - expect(await response).toRespondWith({ - rpcUrl: DefaultProviderUrls.BUILDNET, - chainId: CHAIN_ID.BuildNet.toString(), - networkName: BUILDNET, - minimalFees: DEFAULT_MINIMAL_FEES, - }); +describe('set-network', () => { + it('should get default Network', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'Provider.getNetwork', + origin, }); - it('should set the network from default to buildnet', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'Provider.getNetwork', - origin, - }); - - expect(await response).toRespondWith({ - rpcUrl: DefaultProviderUrls.BUILDNET, - chainId: CHAIN_ID.BuildNet.toString(), - networkName: BUILDNET, - minimalFees: DEFAULT_MINIMAL_FEES, - }); + + expect(await response).toRespondWith({ + chainId: CHAIN_ID.Mainnet.toString(), + networkName: NetworkName.Mainnet, + rpcUrl: PublicApiUrl.Mainnet, + minimalFees: DEFAULT_MINIMAL_FEES, }); }); + + it('should set the network to buildnet', async () => { + const { request } = await installSnap(); + + await setNetwork(request, PublicApiUrl.Buildnet); + + const response = request({ + method: 'Provider.getNetwork', + origin, + }); + + expect(await response).toRespondWith(NETWORK); + }); }); diff --git a/packages/snap/test/show-credentials.test.tsx b/packages/snap/test/show-credentials.test.tsx index 7537899..3801320 100644 --- a/packages/snap/test/show-credentials.test.tsx +++ b/packages/snap/test/show-credentials.test.tsx @@ -2,67 +2,65 @@ import { expect } from '@jest/globals'; import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; import { panel, text } from '@metamask/snaps-sdk'; -import type { GetActiveAccountResponse } from 'src/handlers/get-active-account'; +import type { GetActiveAccountResponse } from '../src/handlers/get-active-account'; -describe('onRpcRequest', () => { - describe('show-credentials', () => { - it('should show credentials', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; +describe('show-credentials', () => { + const origin = 'Jest'; - const defaultAccount: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; + it('should show credentials', async () => { + const { request } = await installSnap(); - const response = request({ - method: 'account.showCredentials', + const defaultAccount: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - address: defaultAccount.address, - }, - }); + })) as any + ).response.result; - const confirmationUi = - (await response.getInterface()) as SnapConfirmationInterface; + const response = request({ + method: 'account.showCredentials', + origin, + params: { + address: defaultAccount.address, + }, + }); - expect(confirmationUi.type).toBe('confirmation'); - expect(confirmationUi).toRender( - panel([ - text('**Are you sure you want to display your credentials?**'), - text( - `Make sure no one else sees them, and don't show them in crowded or public places !`, - ), - ]), - ); - await confirmationUi.ok(); + const confirmationUi = + (await response.getInterface()) as SnapConfirmationInterface; - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('alert'); + expect(confirmationUi.type).toBe('confirmation'); + expect(confirmationUi).toRender( + panel([ + text('**Are you sure you want to display your credentials?**'), + text( + `Make sure no one else sees them, and don't show them in crowded or public places !`, + ), + ]), + ); + await confirmationUi.ok(); - await ui.ok(); - }); + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('alert'); + + await ui.ok(); + }); - it('should not show credentials for not imported account', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; + it('should not show credentials for not imported account', async () => { + const { request } = await installSnap(); - const response = request({ - method: 'account.showCredentials', - origin, - params: { - address: 'AU199wi4sBM2DyBeje88WQveDdTWGCs461VocsHpbT7FWiPyfqxD', - }, - }); + const response = request({ + method: 'account.showCredentials', + origin, + params: { + address: 'AU199wi4sBM2DyBeje88WQveDdTWGCs461VocsHpbT7FWiPyfqxD', + }, + }); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: - 'Account not found: AU199wi4sBM2DyBeje88WQveDdTWGCs461VocsHpbT7FWiPyfqxD', - stack: expect.any(String), - }); + expect(await response).toRespondWithError({ + code: expect.any(Number), + message: + 'Account not found: AU199wi4sBM2DyBeje88WQveDdTWGCs461VocsHpbT7FWiPyfqxD', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/sign-message.test.ts b/packages/snap/test/sign-message.test.ts index 4f45536..cd4cbd5 100644 --- a/packages/snap/test/sign-message.test.ts +++ b/packages/snap/test/sign-message.test.ts @@ -3,74 +3,65 @@ import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; import { panel, text } from '@metamask/snaps-sdk'; -import { setNetwork } from './utils/setNetwork'; -import type { GetActiveAccountResponse } from 'src/handlers/get-active-account'; -import { DefaultProviderUrls } from '@massalabs/massa-web3'; +describe('sign-message', () => { + const origin = 'Jest'; -describe('onRpcRequest', () => { - describe('sign-message', () => { - it('should sign a message', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; + it('should sign a byte message', async () => { + const { request } = await installSnap(); - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - const response = request({ - method: 'account.sign', - origin, - params: { - address: account.address, - data: [10, 0, 0, 0, 77, 121, 32, 77, 101, 115, 115, 97, 103, 101], // My Message in bytes - }, - }); + const data = 'My Message'; - const ui = (await response.getInterface()) as SnapConfirmationInterface; + const response = request({ + method: 'account.sign', + origin, + params: { + data: Array.from(new TextEncoder().encode(data)), + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('Do you want to sign the following message ?'), + text(new TextEncoder().encode(data).toString()), + ]), + ); + + await ui.ok(); + expect(await response).toRespondWith({ + publicKey: 'P12BYyRbBF72Ft1N87e5JaVg4Ua7LkmTGBSm6hhQC7M5L2KNJiSt', + signature: + '1R34YLo2jZUANsehSLddauxjgDhTQUr1MNnP6u3Q14V2Xg2ZHiVsqa5JqRvxjSgPjtSx8dFYrYTSb7ogM9vC8zNXDtC2gp', + }); + }); - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('Do you want to sign the following message ?'), - text( - [ - 10, 0, 0, 0, 77, 121, 32, 77, 101, 115, 115, 97, 103, 101, - ].toString(), - ), - ]), - ); + it('should sign a string message', async () => { + const { request } = await installSnap(); - await ui.ok(); - expect(await response).toRespondWith({ - publicKey: 'P12BYyRbBF72Ft1N87e5JaVg4Ua7LkmTGBSm6hhQC7M5L2KNJiSt', - signature: - '122SBUmi3cJhZh4a3a73bxe4VMhJiSsbNFp3q8WA5SeC4Do6BMtmqZ1NXv9JeCnKCJABN2HYHMQpX7NGQm2MZ5f1AbdQaN', - }); + const data = 'My Message'; + + const response = request({ + method: 'account.sign', + origin, + params: { + data, + }, }); - it('should not sign a message with another account', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; + const ui = (await response.getInterface()) as SnapConfirmationInterface; + + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([text('Do you want to sign the following message ?'), text(data)]), + ); - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sign', - origin, - params: { - address: - 'AU123GG5gg45Wbf4TC8jm2RkTLz1q63tcfdfdsfsdymy2pY6fTaYcdejvfsdsd', - data: [10, 0, 0, 0, 77, 121, 32, 77, 101, 115, 115, 97, 103, 101], // My Message in bytes - }, - }); - expect(await response).toRespondWithError({ - code: expect.any(Number), - message: - 'Account not found: AU123GG5gg45Wbf4TC8jm2RkTLz1q63tcfdfdsfsdymy2pY6fTaYcdejvfsdsd', - stack: expect.any(String), - }); + await ui.ok(); + expect(await response).toRespondWith({ + publicKey: 'P12BYyRbBF72Ft1N87e5JaVg4Ua7LkmTGBSm6hhQC7M5L2KNJiSt', + signature: + '1R34YLo2jZUANsehSLddauxjgDhTQUr1MNnP6u3Q14V2Xg2ZHiVsqa5JqRvxjSgPjtSx8dFYrYTSb7ogM9vC8zNXDtC2gp', }); }); }); diff --git a/packages/snap/test/transfer.test.ts b/packages/snap/test/transfer.test.ts index d9a754f..7805809 100644 --- a/packages/snap/test/transfer.test.ts +++ b/packages/snap/test/transfer.test.ts @@ -3,248 +3,249 @@ import type { SnapConfirmationInterface } from '@metamask/snaps-jest'; import { installSnap } from '@metamask/snaps-jest'; import { panel, text } from '@metamask/snaps-sdk'; -import { setNetwork } from './utils/setNetwork'; -import type { GetActiveAccountResponse } from 'src/handlers/get-active-account'; -import { DefaultProviderUrls } from '@massalabs/massa-web3'; - -describe('onRpcRequest', () => { - describe('transfer', () => { - it('should return an operation id', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', - origin, - params: { - recipientAddress: account.address, - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('**Do you want to send the following transaction?**'), - text(`**Recipient:** ${account.address as string}`), - text('**Amount:** 1000000'), - text('**Fee:** 1000000'), - ]), - ); - - await ui.ok(); - expect(await response).toRespondWith({ - operationId: expect.any(String), - }); - - const operations = await request({ - method: 'account.getOperations', - origin, - }); - expect((operations.response as any).result.operations).toHaveLength(1); - }); - - it('should throw an error if the user deny the request', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', - origin, - params: { - recipientAddress: account.address, - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - const ui = (await response.getInterface()) as SnapConfirmationInterface; - expect(ui.type).toBe('confirmation'); - expect(ui).toRender( - panel([ - text('**Do you want to send the following transaction?**'), - text(`**Recipient:** ${account.address as string}`), - text('**Amount:** 1000000'), - text('**Fee:** 1000000'), - ]), - ); - - await ui.cancel(); - expect(await response).toRespondWithError({ - code: -32603, - message: 'User denied sending transaction', - stack: expect.any(String), - }); - }); - - it('should throw an error if the fee is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', +import type { GetActiveAccountResponse } from '../src/handlers/get-active-account'; + +describe('transfer', () => { + const origin = 'Jest'; + + it('should return an operation id', async () => { + const { request } = await installSnap(); + const account: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - recipientAddress: account.address, - fee: 1000000, - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); - }); - - it('should throw an error if the amount is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', + })) as any + ).response.result; + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: account.address, + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to send the following transaction?**'), + text(`**Recipient:** ${account.address}`), + text('**Amount:** 1000000 MAS'), + text('**Fee:** 1000000 MAS'), + ]), + ); + + await ui.ok(); + expect(await response).toRespondWith({ + operationId: expect.any(String), + }); + + const operations = await request({ + method: 'account.getOperations', + origin, + }); + expect((operations.response as any).result.operations).toHaveLength(1); + }); + + it('should return an operation id (fee missing)', async () => { + const { request } = await installSnap(); + const account: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - recipientAddress: account.address, - fee: '1000000000000000', - amount: 1000000, - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: amount must be a string', - stack: expect.any(String), - }); - }); - - it('should throw an error if the recipientAddress is not a string', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', + })) as any + ).response.result; + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: account.address, + amount: '1000000000000000', + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to send the following transaction?**'), + text(`**Recipient:** ${account.address}`), + text('**Amount:** 1000000 MAS'), + text('**Fee:** 0.01 MAS'), + ]), + ); + + await ui.ok(); + expect(await response).toRespondWith({ + operationId: expect.any(String), + }); + + const operations = await request({ + method: 'account.getOperations', + origin, + }); + expect((operations.response as any).result.operations).toHaveLength(1); + }); + + it('should throw an error if the user deny the request', async () => { + const { request } = await installSnap(); + const account: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - recipientAddress: 123, - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: recipientAddress must be a string', - stack: expect.any(String), - }); - }); - - it('should throw an error if the fee is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', + })) as any + ).response.result; + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: account.address, + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + const ui = (await response.getInterface()) as SnapConfirmationInterface; + expect(ui.type).toBe('confirmation'); + expect(ui).toRender( + panel([ + text('**Do you want to send the following transaction?**'), + text(`**Recipient:** ${account.address}`), + text('**Amount:** 1000000 MAS'), + text('**Fee:** 1000000 MAS'), + ]), + ); + + await ui.cancel(); + expect(await response).toRespondWithError({ + code: -32603, + message: 'User denied sending transaction', + stack: expect.any(String), + }); + }); + + it('should throw an error if the fee is not a string', async () => { + const { request } = await installSnap(); + const account: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - recipientAddress: account.address, - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: fee must be a string', - stack: expect.any(String), - }); - }); - - it('should throw an error if the amount is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - const account: GetActiveAccountResponse = ( - (await request({ - method: 'account.getActive', - origin, - })) as any - ).response.result; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', + })) as any + ).response.result; + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: account.address, + fee: 1000000, + amount: '1000000000000000', + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: fee must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the amount is not a string', async () => { + const { request } = await installSnap(); + + const account: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - recipientAddress: account.address, - fee: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: amount must be a string', - stack: expect.any(String), - }); - }); - - it('should throw an error if the recipientAddress is missing', async () => { - const { request } = await installSnap(); - const origin = 'Jest'; - - await setNetwork(request, DefaultProviderUrls.BUILDNET); // BuildNet - const response = request({ - method: 'account.sendTransaction', + })) as any + ).response.result; + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: account.address, + fee: '1000000000000000', + amount: 1000000, + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: amount must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the recipientAddress is not a string', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: 123, + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: recipientAddress must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the amount is missing', async () => { + const { request } = await installSnap(); + + const account: GetActiveAccountResponse = ( + (await request({ + method: 'account.getActive', origin, - params: { - fee: '1000000000000000', - amount: '1000000000000000', - }, - }); - - expect(await response).toRespondWithError({ - code: -32603, - message: 'Invalid params: recipientAddress must be a string', - stack: expect.any(String), - }); + })) as any + ).response.result; + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + recipientAddress: account.address, + fee: '1000000000000000', + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: amount must be a string', + stack: expect.any(String), + }); + }); + + it('should throw an error if the recipientAddress is missing', async () => { + const { request } = await installSnap(); + + const response = request({ + method: 'account.sendTransaction', + origin, + params: { + fee: '1000000000000000', + amount: '1000000000000000', + }, + }); + + expect(await response).toRespondWithError({ + code: -32603, + message: 'Invalid params: recipientAddress must be a string', + stack: expect.any(String), }); }); }); diff --git a/packages/snap/test/utils/addTokens.ts b/packages/snap/test/utils/addTokens.ts deleted file mode 100644 index 6467f82..0000000 --- a/packages/snap/test/utils/addTokens.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { RequestOptions, SnapRequest } from '@metamask/snaps-jest'; - -export const addTokens = async ( - request: (opt: RequestOptions) => SnapRequest, - tokens: string[], -) => { - const origin = 'Jest'; - return Promise.all( - tokens.map(async (token) => { - const res = await request({ - method: 'account.addToken', - origin, - params: { - address: token, - }, - }); - return (res.response as any).result; - }), - ); -}; diff --git a/packages/snap/test/utils/constants.ts b/packages/snap/test/utils/constants.ts new file mode 100644 index 0000000..4848e47 --- /dev/null +++ b/packages/snap/test/utils/constants.ts @@ -0,0 +1,11 @@ +import { CHAIN_ID, NetworkName, PublicApiUrl } from '@massalabs/massa-web3'; +import { DEFAULT_MINIMAL_FEES } from '../../src/active-chain'; + +export const TOKEN = 'AS1sKBEGsqtm8vQhQzi7KJ4YhyaKTSkhJrLkRc7mQtPqme3VcFHm'; + +export const NETWORK = { + rpcUrl: PublicApiUrl.Buildnet, + chainId: CHAIN_ID.Buildnet.toString(), + networkName: NetworkName.Buildnet, + minimalFees: DEFAULT_MINIMAL_FEES, +}; diff --git a/packages/snap/test/utils/setNetwork.ts b/packages/snap/test/utils/setNetwork.ts index fad57b1..410eac1 100644 --- a/packages/snap/test/utils/setNetwork.ts +++ b/packages/snap/test/utils/setNetwork.ts @@ -3,6 +3,7 @@ import type { SnapConfirmationInterface, SnapRequest, } from '@metamask/snaps-jest'; +import { scheduler } from 'node:timers/promises'; export const setNetwork = async ( request: (opt: RequestOptions) => SnapRequest, @@ -19,5 +20,5 @@ export const setNetwork = async ( const ui = (await req.getInterface()) as SnapConfirmationInterface; await ui.ok(); - await new Promise((resolve) => setTimeout(resolve, 50)); + await scheduler.wait(50); }; diff --git a/yarn.lock b/yarn.lock index 6be64ad..b604886 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1723,13 +1723,6 @@ __metadata: languageName: node linkType: hard -"@hicaru/bearby.js@npm:^0.5.7": - version: 0.5.9 - resolution: "@hicaru/bearby.js@npm:0.5.9" - checksum: 25868ec1bf0d1ddfdbbdbf55ac5b1f1e8b2f88fd1fdc9948c50b37835373dae3e1593a0a50b1a320c8d877f0081502ec5e85c1ce6a6003207ce975d894134611 - languageName: node - linkType: hard - "@humanwhocodes/config-array@npm:^0.13.0": version: 0.13.0 resolution: "@humanwhocodes/config-array@npm:0.13.0" @@ -2106,43 +2099,28 @@ __metadata: languageName: node linkType: hard -"@lukeed/csprng@npm:^1.0.0": - version: 1.1.0 - resolution: "@lukeed/csprng@npm:1.1.0" - checksum: 926f5f7fc629470ca9a8af355bfcd0271d34535f7be3890f69902432bddc3262029bb5dbe9025542cf6c9883d878692eef2815fc2f3ba5b92e9da1f9eba2e51b - languageName: node - linkType: hard - -"@massalabs/massa-web3@npm:^4.0.3": - version: 4.0.3 - resolution: "@massalabs/massa-web3@npm:4.0.3" +"@massalabs/massa-web3@npm:^5.0.1-dev": + version: 5.0.1-dev.20241202145307 + resolution: "@massalabs/massa-web3@npm:5.0.1-dev.20241202145307" dependencies: - "@massalabs/wallet-provider": ^2.0.0 - "@massalabs/web3-utils": ^1.4.11 "@noble/ed25519": ^1.7.3 "@noble/hashes": ^1.2.0 - "@types/ws": ^8.5.4 - "@web3pack/base58-check": ^1.0.3 - axios: ^0.26.1 - bignumber.js: ^9.1.1 - bip39: ^3.0.4 - bs58check: ^3.0.1 - buffer: ^6.0.3 + bs58check: ^4.0.0 bufferutil: ^4.0.7 - crypto-js: ^4.1.1 + decimal.js: ^10.4.3 dotenv: ^16.0.3 - js-base64: ^3.7.5 - string_decoder: ^1.3.0 - tslib: ^2.5.2 + eventemitter3: ^5.0.1 + lodash.isequal: ^4.5.0 + secure-random: ^1.1.2 + tslib: ^2.8.0 utf-8-validate: ^6.0.2 - util: ^0.12.5 varint: ^6.0.0 dependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: 3ffcab1cd13414a7f568924f750c085620a3f1a83cfff0cf22498191ab093c7e7c43d03bd68bb701652ff47399aa7bf3220b53f47d2ffd338e2c8e991feee640 + checksum: ce4e065b0e87a870f962cb83c855809aaa635c7eb5982926e929d9e9372658a3d563bcd871949e68e52c20323d7ef71f9e3189de5cf0f5bed4ec35fdce78c72a languageName: node linkType: hard @@ -2151,7 +2129,7 @@ __metadata: resolution: "@massalabs/metamask-snap@workspace:packages/snap" dependencies: "@jest/globals": ^29.5.0 - "@massalabs/massa-web3": ^4.0.3 + "@massalabs/massa-web3": ^5.0.1-dev "@metamask/auto-changelog": ^3.4.2 "@metamask/eslint-config": ^12.0.0 "@metamask/eslint-config-jest": ^12.0.0 @@ -2164,6 +2142,7 @@ __metadata: "@types/jest": ^29.5.12 "@types/react": 18.2.14 "@types/react-dom": 18.2.4 + "@types/varint": ^6.0.3 "@typescript-eslint/eslint-plugin": ^5.42.1 "@typescript-eslint/parser": ^5.42.1 buffer: ^6.0.3 @@ -2181,42 +2160,10 @@ __metadata: rimraf: ^3.0.2 ts-jest: ^29.1.0 typescript: ^4.7.4 + varint: ^6.0.0 languageName: unknown linkType: soft -"@massalabs/wallet-provider@npm:^2.0.0": - version: 2.0.0 - resolution: "@massalabs/wallet-provider@npm:2.0.0" - dependencies: - "@hicaru/bearby.js": ^0.5.7 - "@massalabs/web3-utils": ^1.4.9-dev - axios: ^0.28.0 - bs58check: ^3.0.1 - buffer: ^6.0.3 - bufferutil: ^4.0.7 - uid: ^2.0.1 - utf-8-validate: ^6.0.2 - dependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 5d2a3e81bb791cca9aa3e67b3846a58e10b61a89bab532db8cbeb35a0b1a58ba809dc4b9b8c9bfc9f807b248b4037f4b3198450368df8504059f3ded46abb9de - languageName: node - linkType: hard - -"@massalabs/web3-utils@npm:^1.4.11, @massalabs/web3-utils@npm:^1.4.9-dev": - version: 1.4.11 - resolution: "@massalabs/web3-utils@npm:1.4.11" - dependencies: - bignumber.js: ^9.1.2 - buffer: ^6.0.3 - events: ^3.3.0 - string_decoder: ^1.3.0 - checksum: 359d3a56604f63f3fdd03ed755b65595fc4d347c224f43d86b378685c463686004d992c94cabef90dcf05268d74e430ff3669ee6225682a897dbc79a0eb76af8 - languageName: node - linkType: hard - "@metamask/abi-utils@npm:^2.0.4": version: 2.0.4 resolution: "@metamask/abi-utils@npm:2.0.4" @@ -3747,12 +3694,12 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.5.4": - version: 8.5.13 - resolution: "@types/ws@npm:8.5.13" +"@types/varint@npm:^6.0.3": + version: 6.0.3 + resolution: "@types/varint@npm:6.0.3" dependencies: "@types/node": "*" - checksum: f17023ce7b89c6124249c90211803a4aaa02886e12bc2d0d2cd47fa665eeb058db4d871ce4397d8e423f6beea97dd56835dd3fdbb921030fe4d887601e37d609 + checksum: cfec85c15e24becb360be6466a41c97b5b6370aec49a403ed28ae52e96b7ef692e9e5aee981ccebab3b7afdf9b84d3809e6ab5bb38cf2e926711c6aebeb8a68d languageName: node linkType: hard @@ -3964,24 +3911,6 @@ __metadata: languageName: node linkType: hard -"@web3pack/base-x@npm:^1.0.1": - version: 1.0.2 - resolution: "@web3pack/base-x@npm:1.0.2" - checksum: b85c9e799944796c48a2f219264cdc00726c897072d54b6cbc0e781bbb76b7a2394d5b1e4a9ea5fc7f508c48baeb308b7fcd9c4386636a05449b8fed211b1d04 - languageName: node - linkType: hard - -"@web3pack/base58-check@npm:^1.0.3": - version: 1.0.3 - resolution: "@web3pack/base58-check@npm:1.0.3" - dependencies: - "@web3pack/base-x": ^1.0.1 - buffer: ^6.0.3 - hash.js: ^1.1.7 - checksum: c954030451bae585d9de285785aafc185f3656b730bfb8d7caafb969032f6214215bff1e6969ad676164d58fc7a4adef401fcb8c84bd402159d5a422b6c2950a - languageName: node - linkType: hard - "@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.12.1": version: 1.14.1 resolution: "@webassemblyjs/ast@npm:1.14.1" @@ -4583,13 +4512,6 @@ __metadata: languageName: node linkType: hard -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be - languageName: node - linkType: hard - "autoprefixer@npm:^10.0.1": version: 10.4.20 resolution: "autoprefixer@npm:10.4.20" @@ -4624,26 +4546,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.26.1": - version: 0.26.1 - resolution: "axios@npm:0.26.1" - dependencies: - follow-redirects: ^1.14.8 - checksum: d9eb58ff4bc0b36a04783fc9ff760e9245c829a5a1052ee7ca6013410d427036b1d10d04e7380c02f3508c5eaf3485b1ae67bd2adbfec3683704745c8d7a6e1a - languageName: node - linkType: hard - -"axios@npm:^0.28.0": - version: 0.28.1 - resolution: "axios@npm:0.28.1" - dependencies: - follow-redirects: ^1.15.0 - form-data: ^4.0.0 - proxy-from-env: ^1.1.0 - checksum: 5115a38d79064d07437c5a28f15841e3607634040e3120ec06a2c4367a7d07cf213b16496eab53b6f58ebc5fb377a440ba9ed4782529b14449a1e285734bfb54 - languageName: node - linkType: hard - "axobject-query@npm:^4.1.0": version: 4.1.0 resolution: "axobject-query@npm:4.1.0" @@ -4843,10 +4745,10 @@ __metadata: languageName: node linkType: hard -"base-x@npm:^4.0.0": - version: 4.0.0 - resolution: "base-x@npm:4.0.0" - checksum: b25db9e07eb1998472a20557c7f00c797dc0595f79df95155ab74274e7fa98b9f2659b3ee547ac8773666b7f69540656793aeb97ad2b1ceccdb6fa5faaf69ac0 +"base-x@npm:^5.0.0": + version: 5.0.0 + resolution: "base-x@npm:5.0.0" + checksum: fa82bc9a963f7a765a3287ba632661669fe553d06ee0d4d4e282640335bff30ec685e3c3b1714e265f697b234facd02a310f1e2465db88f4f1a448e6267fbc65 languageName: node linkType: hard @@ -4857,7 +4759,7 @@ __metadata: languageName: node linkType: hard -"bignumber.js@npm:^9.1.1, bignumber.js@npm:^9.1.2": +"bignumber.js@npm:^9.1.2": version: 9.1.2 resolution: "bignumber.js@npm:9.1.2" checksum: 582c03af77ec9cb0ebd682a373ee6c66475db94a4325f92299621d544aa4bd45cb45fd60001610e94aef8ae98a0905fa538241d9638d4422d57abbeeac6fadaf @@ -4883,15 +4785,6 @@ __metadata: languageName: node linkType: hard -"bip39@npm:^3.0.4": - version: 3.1.0 - resolution: "bip39@npm:3.1.0" - dependencies: - "@noble/hashes": ^1.2.0 - checksum: 1224e763ffc6b097052ed8abd57f0e521ad6d31f1645be0d0a15f4417c13f8461f00e47e9cf7c8c784bd533f4fb1ee3ab020f258c7df45ee5dc722b4b0336cfc - languageName: node - linkType: hard - "bl@npm:^4.0.3, bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -5153,22 +5046,22 @@ __metadata: languageName: node linkType: hard -"bs58@npm:^5.0.0": - version: 5.0.0 - resolution: "bs58@npm:5.0.0" +"bs58@npm:^6.0.0": + version: 6.0.0 + resolution: "bs58@npm:6.0.0" dependencies: - base-x: ^4.0.0 - checksum: 2475cb0684e07077521aac718e604a13e0f891d58cff923d437a2f7e9e28703ab39fce9f84c7c703ab369815a675f11e3bd394d38643bfe8969fbe42e6833d45 + base-x: ^5.0.0 + checksum: 820334f9513bba6195136dfc9dfbd1f5aded6c7864639f3ee7b63c2d9d6f9f2813b9949b1f6beb9c161237be2a461097444c2ff587c8c3b824fe18878fa22448 languageName: node linkType: hard -"bs58check@npm:^3.0.1": - version: 3.0.1 - resolution: "bs58check@npm:3.0.1" +"bs58check@npm:^4.0.0": + version: 4.0.0 + resolution: "bs58check@npm:4.0.0" dependencies: "@noble/hashes": ^1.2.0 - bs58: ^5.0.0 - checksum: dbbecc7a09f3836e821149266c864c4bbd545539cea43c35f23f4c3c46b54c86c52b65d224b9ea2e916fa6d93bd2ce9fac5b6c6bfcf19621a9c209a5602f71c8 + bs58: ^6.0.0 + checksum: 416131b647563e9c7daf5d18222862b40dfd39110f8635e9e1d19805d624e96cc12ba03c8e6fdc1f9c0e364dd2918877fb8a02671caeef0de9beeb33c1fb0ed4 languageName: node linkType: hard @@ -5565,15 +5458,6 @@ __metadata: languageName: node linkType: hard -"combined-stream@npm:^1.0.8": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" - dependencies: - delayed-stream: ~1.0.0 - checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c - languageName: node - linkType: hard - "commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -5856,13 +5740,6 @@ __metadata: languageName: node linkType: hard -"crypto-js@npm:^4.1.1": - version: 4.2.0 - resolution: "crypto-js@npm:4.2.0" - checksum: f051666dbc077c8324777f44fbd3aaea2986f198fe85092535130d17026c7c2ccf2d23ee5b29b36f7a4a07312db2fae23c9094b644cc35f7858b1b4fcaf27774 - languageName: node - linkType: hard - "cssesc@npm:^3.0.0": version: 3.0.0 resolution: "cssesc@npm:3.0.0" @@ -5895,7 +5772,7 @@ __metadata: "@chakra-ui/react": ^2.8.2 "@emotion/react": ^11.11.4 "@emotion/styled": ^11.11.0 - "@massalabs/massa-web3": ^4.0.3 + "@massalabs/massa-web3": ^5.0.1-dev "@metamask/providers": ^15.0.0 "@types/node": ^20 "@types/react": ^18 @@ -5984,6 +5861,13 @@ __metadata: languageName: node linkType: hard +"decimal.js@npm:^10.4.3": + version: 10.4.3 + resolution: "decimal.js@npm:10.4.3" + checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -6071,13 +5955,6 @@ __metadata: languageName: node linkType: hard -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 - languageName: node - linkType: hard - "depd@npm:2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" @@ -7059,6 +6936,13 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:^5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 543d6c858ab699303c3c32e0f0f47fc64d360bf73c3daf0ac0b5079710e340d6fe9f15487f94e66c629f5f82cd1a8678d692f3dbb6f6fcd1190e1b97fcad36f8 + languageName: node + linkType: hard + "events@npm:^3.0.0, events@npm:^3.2.0, events@npm:^3.3.0": version: 3.3.0 resolution: "events@npm:3.3.0" @@ -7384,16 +7268,6 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.15.0": - version: 1.15.9 - resolution: "follow-redirects@npm:1.15.9" - peerDependenciesMeta: - debug: - optional: true - checksum: 859e2bacc7a54506f2bf9aacb10d165df78c8c1b0ceb8023f966621b233717dab56e8d08baadc3ad3b9db58af290413d585c999694b7c146aaf2616340c3d2a6 - languageName: node - linkType: hard - "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -7436,17 +7310,6 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.0": - version: 4.0.1 - resolution: "form-data@npm:4.0.1" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.8 - mime-types: ^2.1.12 - checksum: ccee458cd5baf234d6b57f349fe9cc5f9a2ea8fd1af5ecda501a18fd1572a6dd3bf08a49f00568afd995b6a65af34cb8dec083cf9d582c4e621836499498dd84 - languageName: node - linkType: hard - "forwarded@npm:0.2.0": version: 0.2.0 resolution: "forwarded@npm:0.2.0" @@ -7915,7 +7778,7 @@ __metadata: languageName: node linkType: hard -"hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": +"hash.js@npm:^1.0.0, hash.js@npm:^1.0.3": version: 1.1.7 resolution: "hash.js@npm:1.1.7" dependencies: @@ -9177,13 +9040,6 @@ __metadata: languageName: node linkType: hard -"js-base64@npm:^3.7.5": - version: 3.7.7 - resolution: "js-base64@npm:3.7.7" - checksum: d1b02971db9dc0fd35baecfaf6ba499731fb44fe3373e7e1d6681fbd3ba665f29e8d9d17910254ef8104e2cb8b44117fe4202d3dc54c7cafe9ba300fe5433358 - languageName: node - linkType: hard - "js-sha3@npm:^0.5.7": version: 0.5.7 resolution: "js-sha3@npm:0.5.7" @@ -9464,6 +9320,13 @@ __metadata: languageName: node linkType: hard +"lodash.isequal@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.isequal@npm:4.5.0" + checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644 + languageName: node + linkType: hard + "lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" @@ -9697,7 +9560,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -10868,13 +10731,6 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 - languageName: node - linkType: hard - "public-encrypt@npm:^4.0.3": version: 4.0.3 resolution: "public-encrypt@npm:4.0.3" @@ -11610,6 +11466,13 @@ __metadata: languageName: node linkType: hard +"secure-random@npm:^1.1.2": + version: 1.1.2 + resolution: "secure-random@npm:1.1.2" + checksum: 44744464a2cb41dd812d482aff1a01b05842359480f2b0cbd6466d1da8cab8ebb2a84f070b0ddee34ab3867f1f775b2bc34ef3e860f27dc8177791595d6debc9 + languageName: node + linkType: hard + "semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -12751,7 +12614,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.2, tslib@npm:^2.6.2": +"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a @@ -12956,15 +12819,6 @@ __metadata: languageName: node linkType: hard -"uid@npm:^2.0.1": - version: 2.0.2 - resolution: "uid@npm:2.0.2" - dependencies: - "@lukeed/csprng": ^1.0.0 - checksum: 98aabddcd6fe46f9b331b0378a93ee9cc51474348ada02006df9d10b4abc783ed596748ed9f20d7f6c5ff395dbcd1e764a65a68db6f39a31c95ae85ef13fe979 - languageName: node - linkType: hard - "umd@npm:^3.0.0": version: 3.0.3 resolution: "umd@npm:3.0.3"