diff --git a/README.md b/README.md index 08ebaca..e9638d1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,665 @@ # coti-ethers +In order to provide easy access to all the features of COTI, the coti-ethers JavaScript SDK was created, which is made in a way that has an interface very similar to those of ethers. In fact, ethers is a peer dependency of our library and all of the objects exported by coti-ethers ( e.g. Wallet, BrowserProvider, etc.) inherit from the corresponding ethers objects and extend their functionality where needed. + +While most of the existing SDKs should work out of the box, using unique COTI features like encrypting transaction inputs, requires executing the onboarding procedure and encrypting using the defined protocol. + +The library is made in such a way that after replacing ethers with coti-ethers most client apps will work out of box. + +# `BrowserProvider` Class + +The `BrowserProvider` class extends the `JsonRpcApiPollingProvider` and provides an interface for interacting with an EIP-1193 compatible browser provider (such as MetaMask). This class enables the sending of JSON-RPC requests to Ethereum nodes via browser extensions and handles account management and signer creation. + +## **Constructor** + +```typescript +constructor(ethereum: Eip1193Provider, network?: Networkish, _options?: BrowserProviderOptions) +``` + +- **Parameters**: + - `ethereum`: An `Eip1193Provider` (typically a browser extension like MetaMask) that implements the `request` method for sending JSON-RPC requests. + - `network?`: Optional. A `Networkish` object representing the network configuration (e.g., mainnet, testnet). + - `_options?`: Optional. `BrowserProviderOptions` that are merged into the `JsonRpcApiProviderOptions` for additional configuration. + +- **Description**: Initializes the `BrowserProvider` by setting up the underlying provider and validating the `ethereum` object. It sets the default configuration for handling JSON-RPC requests and provides error handling and debugging features. + +- **Throws**: + - An error if the provided `ethereum` object is not a valid EIP-1193 provider. + +## **Private Fields** + +### **`#request`** + +- **Type**: `(method: string, params: Array | Record) => Promise` + +- **Description**: A private method used to send EIP-1193 JSON-RPC requests to the Ethereum provider. This method emits debugging information about the request and handles errors by attaching the error code, data, and payload for better error management. + +## **Public Methods** + +### 1. **`send(method: string, params: Array | Record): Promise`** + +- **Parameters**: + - `method`: A string representing the JSON-RPC method (e.g., `eth_accounts`, `eth_sendTransaction`). + - `params`: An array or object containing the parameters for the JSON-RPC method. + +- **Returns**: A `Promise` resolving to the result of the JSON-RPC method. + +- **Description**: Sends a JSON-RPC request to the Ethereum provider using the inherited `send` method after initializing the provider via `_start()`. + +### 2. **`_send(payload: JsonRpcPayload | Array): Promise>`** + +- **Parameters**: + - `payload`: A `JsonRpcPayload` object or an array of such objects representing the JSON-RPC request(s). + +- **Returns**: A `Promise>`, resolving to an array containing the results or errors from the JSON-RPC request. + +- **Description**: Sends a single JSON-RPC request using the EIP-1193 protocol. This method does not support batch requests as EIP-1193 does not allow them. If an error occurs, the method returns the error details including the code, message, and data. + +- **Throws**: Throws an error if batch requests are attempted. + +### 3. **`getRpcError(payload: JsonRpcPayload, error: JsonRpcError): Error`** + +- **Parameters**: + - `payload`: The original JSON-RPC payload that triggered the error. + - `error`: A `JsonRpcError` object containing error details such as the error code, message, and data. + +- **Returns**: An `Error` object with additional information based on the error code. + +- **Description**: Enhances the error message based on known EIP-1193 error codes. For example, it rewrites the error message for: + - `4001`: User denied the request. + - `4200`: Unsupported request. + +- **Example**: + - `4001` becomes `ethers-user-denied: {message}` + - `4200` becomes `ethers-unsupported: {message}` + +### 4. **`hasSigner(address: number | string): Promise`** + +- **Parameters**: + - `address`: A `number` (account index) or `string` (Ethereum address). + +- **Returns**: A `Promise`, resolving to `true` if the provider manages the given address. + +- **Description**: Checks if the provider manages the given account. If an account index is passed, it checks if the account exists at that index. If an address is passed, it verifies whether the address is managed by the provider. + +- **Example**: + ```typescript + const isSigner = await provider.hasSigner("0xYourAddress"); + ``` + +### 5. **`getSigner(address?: number | string, userOnboardInfo?: OnboardInfo): Promise`** + +- **Parameters**: + - `address?`: An optional `number` or `string` representing the account index or Ethereum address. Defaults to the first account if not provided. + - `userOnboardInfo?`: Optional `OnboardInfo` object containing user-specific data such as AES keys and RSA key pairs for the signer. + +- **Returns**: A `Promise`, resolving to a custom `JsonRpcSigner` instance associated with the given address. + +- **Description**: Retrieves the `JsonRpcSigner` for the specified account. If the provider doesn't manage the specified account, it triggers a request to the Ethereum provider to access accounts (e.g., MetaMask's `eth_requestAccounts` method). After confirming account access, it returns the signer. + +## **Private Methods** + +### **`#request`** + +- **Type**: `(method: string, params: Array | Record) => Promise` + +- **Description**: This method sends JSON-RPC requests to the Ethereum provider via EIP-1193. It emits debugging information for requests and responses and includes enhanced error handling by augmenting errors with additional metadata such as code and data. + +## **Error Handling** + +- **Batch Request Errors**: The class does not support batch JSON-RPC requests. Attempting to send a batch will throw an error. + +- **EIP-1193 Error Codes**: Custom error handling is provided for common EIP-1193 errors such as: + - `4001`: User denied the request. + - `4200`: Unsupported request. + + These errors are intercepted and rewritten into more descriptive messages before being thrown. + +## Example Usage + +```typescript +import { BrowserProvider } from "./BrowserProvider"; +import { JsonRpcSigner } from "./JsonRpcSigner"; +import { Eip1193Provider } from "ethers"; + +// Example: Connect to MetaMask provider and retrieve the signer +const ethereumProvider = window.ethereum as Eip1193Provider; +const provider = new BrowserProvider(ethereumProvider); + +// Retrieve the signer for the first account +const signer: JsonRpcSigner = await provider.getSigner(0); + +// Send a request using the provider +const blockNumber = await provider.send("eth_blockNumber", []); +console.log("Current Block Number:", blockNumber); + +// Check if an account is managed by the provider +const hasSigner = await provider.hasSigner("0xYourEthereumAddress"); +console.log("Has Signer:", hasSigner); +``` + +# `JsonRpcApiProvider` Class + +The `JsonRpcApiProvider` class extends the base `JsonRpcApiProvider` from the `ethers.js` library. It adds custom functionality for interacting with JSON-RPC APIs and provides an implementation for retrieving a `JsonRpcSigner`, which includes onboarding user information in the Coti network. + +## **Constructor** + +```typescript +constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) +``` + +- **Parameters**: + - `network?`: An optional `Networkish` object that specifies the network to connect to. + - `options?`: Optional configuration options for the JSON-RPC provider (of type `JsonRpcApiProviderOptions`). + +- **Description**: Initializes a new instance of the `JsonRpcApiProvider` class. It extends the base provider from `ethers.js`, allowing additional functionality for managing signers and user-specific onboarding. + +## **Public Methods** + +### 1. **`getSigner(address?: number | string, userOnboardInfo?: OnboardInfo): Promise`** + +- **Parameters**: + - `address?`: An optional `number` or `string` that specifies which account to use. If not provided, defaults to the first account (`0`). + - If a `number` is provided, it refers to the account index. + - If a `string` is provided, it refers to an Ethereum address. + - `userOnboardInfo?`: Optional `OnboardInfo` object that contains user-specific information, such as AES keys, RSA keys, and transaction hashes. + +- **Returns**: A `Promise`, resolving to a custom `JsonRpcSigner` instance associated with the given account. + +- **Description**: This method retrieves a `JsonRpcSigner` instance for the specified account. The method handles two cases: + 1. **Account Index**: If the `address` is a number, the method fetches the list of accounts and returns the signer for the account at that index. + 2. **Account Address**: If the `address` is a string, it checks the list of accounts for the corresponding address and returns the signer for that address. + +- **Account Resolution**: + - The function makes a call to the JSON-RPC API method `eth_accounts` to retrieve the available accounts. + - The `resolveProperties` utility is used to ensure that both the network and accounts are resolved before the account matching begins. + +- **Error Handling**: + - Throws an error if the specified account index is out of range. + - Throws an error if the provided address is invalid or not found in the list of accounts. + +## Example Usage + +```typescript +import { JsonRpcApiProvider } from "./JsonRpcApiProvider"; +import { OnboardInfo } from "../types"; + +// Create an instance of the provider for a specific network +const provider = new JsonRpcApiProvider("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID"); + +// Example: Fetch the signer for the first account +const signer = await provider.getSigner(0); + +// Example: Fetch the signer for a specific address with onboarding info +const userOnboardInfo: OnboardInfo = { + aesKey: "user-aes-key", + rsaKey: { publicKey: "rsa-public-key", privateKey: "rsa-private-key" }, + txHash: "transaction-hash" +}; + +const signerWithOnboarding = await provider.getSigner("0xYourEthereumAddress", userOnboardInfo); +``` + +# `JsonRpcSigner` Class + +The `JsonRpcSigner` class extends the base `JsonRpcSigner` from `ethers.js` and adds additional functionality for onboarding users and managing encryption using AES keys within the Coti Network. It includes methods for securely encrypting and decrypting data, generating/recovering AES keys, and handling onboarding procedures. + +## **Constructor** + +```typescript +constructor(provider: JsonRpcApiProvider, address: string, userOnboardInfo?: OnboardInfo) +``` + +- **Parameters**: + - `provider`: An instance of `JsonRpcApiProvider` for interacting with the blockchain. + - `address`: A string representing the Ethereum address for this signer. + - `userOnboardInfo?`: Optional `OnboardInfo` object containing user-specific data such as AES keys, RSA keys, and transaction hashes. + +- **Description**: Initializes a new instance of the `JsonRpcSigner` class, optionally including user-specific onboarding information. It extends the functionality of the base `JsonRpcSigner` from `ethers` by incorporating encryption-related operations and user onboarding data. + +## **Private Fields** + +- **`_autoOnboard: boolean`**: + - Determines whether the signer should automatically initiate onboarding if required. + - Default value is `true`. + +- **`_userOnboardInfo?: OnboardInfo`**: + - Stores the user’s onboarding information, which may include the AES key, RSA key pair, and transaction hash. + +## **Private Methods** + +### **`#buildInputText(plaintext: bigint, userKey: string, contractAddress: string, functionSelector: string): Promise`** + +- **Parameters**: + - `plaintext`: The plaintext value to encrypt, as a `bigint`. + - `userKey`: The AES key for encrypting the plaintext. + - `contractAddress`: The contract address associated with the transaction. + - `functionSelector`: A string identifying the function to be called on the contract. + +- **Returns**: A `Promise` containing the encrypted data. + +- **Description**: Encrypts the given plaintext using the user's AES key, ensuring the data size is within the 64-bit limit. It uses utility functions to encode the plaintext and the key, then encrypts the data. It prepares the encrypted value for transmission by packing it into a cryptographically signed message. + +## **Public Methods** + +### **`encryptValue(plaintextValue: bigint | number | string, contractAddress: string, functionSelector: string): Promise`** + +- **Parameters**: + - `plaintextValue`: The value to encrypt, which can be of type `bigint`, `number`, or `string`. + - `contractAddress`: The smart contract address to which the encryption is related. + - `functionSelector`: The function identifier for the contract interaction. + +- **Returns**: A `Promise`, depending on the type of the plaintext value. + +- **Description**: Encrypts the provided plaintext using the user’s AES key. If the AES key is not available, it attempts to generate or recover it via onboarding. The function handles both integer and string values and returns the encrypted result accordingly. + +### **`decryptValue(ciphertext: ctUint | ctString): Promise`** + +- **Parameters**: + - `ciphertext`: The encrypted value, which can either be of type `ctUint` (for integers) or `ctString` (for strings). + +- **Returns**: A `Promise`, depending on the ciphertext type. + +- **Description**: Decrypts the provided ciphertext using the AES key stored in the user’s onboarding information. If the AES key is missing, it attempts to onboard the user or recover the key. The method supports decryption for both integers and strings. + +### **`generateOrRecoverAes(onboardContractAddress: string = ONBOARD_CONTRACT_ADDRESS): Promise`** + +- **Parameters**: + - `onboardContractAddress`: The contract address used for onboarding purposes. Defaults to `ONBOARD_CONTRACT_ADDRESS`. + +- **Returns**: A `Promise`. + +- **Description**: This function attempts to generate or recover the user's AES key. If the AES key already exists in the onboarding information, it returns immediately. If the user’s RSA key and transaction hash are available, the AES key is recovered from the blockchain using the `recoverAesFromTx` function. If no onboarding info exists, it checks the user's account balance and initiates the onboarding process if the balance is sufficient. + +- **Error Handling**: + - Throws an error if the user's account balance is `0`, preventing onboarding. + +## **Auto Onboarding Control** + +- **Automatic onboarding**: This class supports automatic onboarding of users if their AES key is not available. The `_autoOnboard` flag controls whether the process is initiated automatically when needed. + +## Example Usage + +```typescript +import { JsonRpcProvider } from "ethers"; +import { JsonRpcSigner } from "./JsonRpcSigner"; +import { CotiNetwork, OnboardInfo } from "../types"; + +// Create a provider +const provider = new JsonRpcProvider(CotiNetwork.Devnet); + +// Create a signer with user onboard info +const userOnboardInfo: OnboardInfo = { + aesKey: "user-aes-key", + rsaKey: { publicKey: "rsa-public-key", privateKey: "rsa-private-key" }, + txHash: "transaction-hash" +}; + +const signer = new JsonRpcSigner(provider, "0xUserAddress", userOnboardInfo); + +// Encrypt a value +const encryptedValue = await signer.encryptValue(BigInt(1000), "0xContractAddress", "0xFunctionSelector"); + +// Decrypt a value +const decryptedValue = await signer.decryptValue(encryptedValue); +``` + +# `Account Utilities` Module + +This module provides utility functions for managing and interacting with accounts in an Ethereum-compatible blockchain using `ethers.js`. It includes functions for retrieving account details, checking balances, validating addresses, handling nonces, and transferring native tokens between accounts. + +## Imports + +- **`ethers`**: + - `formatEther`: Converts a value in wei (the smallest unit in Ethereum) to ether. + - `getAddress`: Normalizes and checksums an Ethereum address. + - `isAddress`: Checks if a given string is a valid Ethereum address. + - `Provider`: An abstraction of a connection to the Ethereum network. + - `TransactionRequest`: An object representing a transaction request to be sent to the blockchain. + - `Wallet`: An object representing an Ethereum wallet that holds keys for signing transactions. + +- **Local Imports**: + - `isProviderConnected`: Checks if a provider is connected to the network. + - `validateGasEstimation`: Validates the gas estimation of a transaction. + +## Functions + +### 1. **`printAccountDetails(provider: Provider, address: string): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider` to interact with the blockchain. + - `address`: A string representing the account’s address. + +- **Returns**: A `Promise` that resolves once the account details are printed. + +- **Description**: This function prints the details of a given account to the console, including: + - The account's address. + - The account's balance in both wei and ether. + - The account's transaction nonce. + +- **Error Handling**: + - Throws an error if the provider is not connected or the address is invalid. + +### 2. **`getAccountBalance(address: string, provider: Provider): Promise`** + +- **Parameters**: + - `address`: A string representing the account’s address. + - `provider`: An instance of `Provider` to interact with the blockchain. + +- **Returns**: A `Promise` that resolves to the balance of the account in wei. + +- **Description**: This function retrieves the balance of the specified account in wei from the blockchain. + +- **Error Handling**: + - Throws an error if the provider is not connected or the address is invalid. + +### 3. **`validateAddress(address: string): { valid: boolean, safe: string }`** + +- **Parameters**: + - `address`: A string representing the account’s address. + +- **Returns**: An object containing: + - `valid`: A boolean indicating if the address is valid. + - `safe`: A checksummed version of the address (a safer, standardized format). + +- **Description**: This function validates the format of a given Ethereum address and returns both a boolean (`valid`) and a safe, checksummed version (`safe`) of the address. + +### 4. **`getNonce(provider: Provider, address: string): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider` to interact with the blockchain. + - `address`: A string representing the account’s address. + +- **Returns**: A `Promise` that resolves to the account's nonce, which represents the number of transactions sent from the address. + +- **Description**: This function retrieves the current transaction nonce for the given account, which is essential for ensuring the correct order of transactions on the blockchain. + +- **Error Handling**: + - Throws an error if the provider is not connected or the address is invalid. + +### 5. **`addressValid(address: string): boolean`** + +- **Parameters**: + - `address`: A string representing the account’s address. + +- **Returns**: A boolean indicating whether the address is valid. + +- **Description**: This function validates an Ethereum address by returning a boolean (`true` if valid, `false` otherwise). + +### 6. **`getNativeBalance(provider: Provider, address: string): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider` to interact with the blockchain. + - `address`: A string representing the account’s address. + +- **Returns**: A `Promise` that resolves to the account balance in ether (as a formatted string). + +- **Description**: This function retrieves the account’s balance in ether (instead of wei) by formatting the balance using `formatEther`. + +- **Error Handling**: + - Throws an error if the provider is not connected or the address is invalid. + +### 7. **`getEoa(accountPrivateKey: string): Promise`** + +- **Parameters**: + - `accountPrivateKey`: A string representing the private key of the account. + +- **Returns**: A `Promise` that resolves to the Ethereum address generated from the private key. + +- **Description**: This function generates an Ethereum address (EOA) from the given private key and returns it. + +- **Error Handling**: + - Throws an error if the generated address is invalid. + +### 8. **`transferNative(provider: Provider, wallet: Wallet, recipientAddress: string, amountToTransferInWei: BigInt, nativeGasUnit: number): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider` to interact with the blockchain. + - `wallet`: An instance of `Wallet` that represents the sender's account. + - `recipientAddress`: A string representing the recipient's Ethereum address. + - `amountToTransferInWei`: The amount of native tokens to transfer, in wei. + - `nativeGasUnit`: The gas limit for the transaction. + +- **Returns**: A `Promise`. + +- **Description**: This function transfers native tokens (e.g., ETH) from the sender's wallet to a recipient. It constructs a transaction, validates the gas estimation, and sends the transaction using the sender’s wallet. + +- **Error Handling**: + - Throws an error if the transaction fails. + - Logs the transaction hash on success or error details if it fails. + +- **Transaction Details**: + - The transaction includes details like `to` (recipient address), `from` (sender address), `value` (amount in wei), `nonce`, `gasLimit`, and `gasPrice`. + +## Error Handling + +All functions handle errors related to: +- **Invalid Provider**: Several functions check if the `Provider` is connected using `isProviderConnected`. If the provider is disconnected or invalid, an error is thrown. +- **Invalid Address**: Functions that accept an address validate it using `isAddress` and throw an error if the address is invalid. +- **Transaction Failures**: The `transferNative` function catches errors during transaction execution and logs the failure, ensuring that the error details are visible. + +## Example Usage + +```typescript +import { getDefaultProvider, Wallet } from "ethers"; +import { printAccountDetails, transferNative, getEoa, getNativeBalance } from "./accountUtils"; +import { CotiNetwork } from "../types"; + +// Example: Printing account details +const provider = getDefaultProvider(CotiNetwork.Devnet); +const address = "0xYourEthereumAddress"; + +await printAccountDetails(provider, address); + +// Example: Transferring native tokens +const senderPrivateKey = "0xYourPrivateKey"; +const senderWallet = new Wallet(senderPrivateKey, provider); +const recipientAddress = "0xRecipientAddress"; +const amountToTransferInWei = BigInt("1000000000000000000"); // 1 ether in wei +const gasLimit = 21000; + +await transferNative(provider, senderWallet, recipientAddress, amountToTransferInWei, gasLimit); +``` + +# `Network Utilities` module + +This module provides utility functions for interacting with the COTI network through `ethers` providers. It includes functions to fetch the default provider, check if a provider is connected, print network details, and retrieve the latest block number. + +## Functions + +### 1. **`getDefaultProvider(cotiNetwork: CotiNetwork): JsonRpcProvider`** + +- **Parameters**: + - `cotiNetwork`: An instance of `CotiNetwork` that specifies the network (Devnet, Testnet, Mainnet, etc.) the provider should connect to. + +- **Returns**: An instance of `JsonRpcProvider`. + +- **Description**: This function returns a `JsonRpcProvider` configured to connect to the specified `CotiNetwork`. It uses the `cotiNetwork` URL to set up the provider for the specified environment. + +### 2. **`async printNetworkDetails(provider: Provider): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider` that is connected to the Coti network. + +- **Returns**: A `Promise`, which resolves after network details are printed to the console. + +- **Description**: This function prints the details of the network to which the provider is connected, including: + - The provider's connection URL (if using a `JsonRpcProvider`). + - The `chainId` of the network. + - The number of the latest block on the blockchain. + +- **Error Handling**: + - Throws an error if the provider is not connected. + +- **Usage**: + This function logs the following details: + - Provider URL (`url`) + - Chain ID (`chainId`) + - Latest block number + + Example: + ```typescript + const provider = getDefaultProvider(CotiNetwork.Mainnet); + await printNetworkDetails(provider); + ``` + +### 3. **`async getLatestBlock(provider: Provider): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider` that is connected to the Coti network. + +- **Returns**: A `Promise`, which resolves to the block number of the latest block in the network. + +- **Description**: This function retrieves the block number of the most recent block on the blockchain. It first checks if the provider is connected, then queries the provider for the latest block. + +- **Error Handling**: + - Throws an error if the provider is not connected or if the provider’s address is invalid. + +### 4. **`async isProviderConnected(provider: Provider): Promise`** + +- **Parameters**: + - `provider`: An instance of `Provider`. + +- **Returns**: A `Promise`, which resolves to `true` if the provider is connected to a network, or `false` if the connection is unsuccessful. + +- **Description**: This function checks if a given provider is connected to a valid network by querying the network information. If the provider's network cannot be fetched, it returns `false`. This function also throws an error if the provider is undefined. + +- **Error Handling**: + - Throws an error if the `provider` object is undefined. + +## Example Usage + +```typescript +import { getDefaultProvider, printNetworkDetails, getLatestBlock, isProviderConnected } from './providerUtils'; +import { CotiNetwork } from '../types'; + +// Get the default provider for Devnet +const provider = getDefaultProvider(CotiNetwork.Devnet); + +// Check if the provider is connected +const isConnected = await isProviderConnected(provider); +if (isConnected) { + // Print the network details + await printNetworkDetails(provider); + + // Get and log the latest block number + const latestBlock = await getLatestBlock(provider); + console.log(`The latest block number is: ${latestBlock}`); +} else { + console.log('Provider is not connected.'); +} +``` + +# Class `Wallet` + +The `Wallet` class extends the base `Wallet` from the `ethers` library, adding features specific to the COTI network. It handles user onboarding, key management, and encryption/decryption of values using AES and RSA keys. The class also supports the process of automatically onboarding users if needed. + +## Constructor + +```typescript +constructor( + privateKey: string | SigningKey, + provider?: Provider | null, + userOnboardInfo?: OnboardInfo +) +``` + +- **Parameters**: + - `privateKey`: A `string` or `SigningKey` used to initialize the wallet. + - `provider?`: An optional `Provider` object or `null`. Defaults to `null` if not provided. + - `userOnboardInfo?`: An optional `OnboardInfo` object that contains the user's onboarding data (e.g., AES key, RSA key). + +- **Description**: Initializes a new `Wallet` instance with a given private key, provider, and optional user onboarding information. This class extends the `BaseWallet` from the `ethers` library, inheriting its functionality. + + +## Private Fields + +- **`_autoOnboard: boolean`**: + - Description: This flag determines whether automatic onboarding is enabled or disabled. By default, it is set to `true`. + +- **`_userOnboardInfo?: OnboardInfo`**: + - Description: Stores the user's onboarding information, which may include the AES key, RSA key, and transaction hash for secure operations on the Coti network. + +## Methods + +### 1. **`getAutoOnboard(): boolean`** + +- **Returns**: `boolean` +- **Description**: Returns the current state of the `_autoOnboard` flag, which indicates whether automatic onboarding is enabled. + +### 2. **`getUserOnboardInfo(): OnboardInfo | undefined`** + +- **Returns**: `OnboardInfo | undefined` +- **Description**: Retrieves the user's onboarding information, or `undefined` if no onboarding info is present. + +### 3. **`setUserOnboardInfo(onboardInfo?: Partial | undefined | null)`** + +- **Parameters**: + - `onboardInfo`: An optional object of type `Partial` to update or modify the existing onboarding information. + +- **Description**: Updates the current user's onboarding info by merging the new `onboardInfo` values with the existing ones. + +### 4. **`setAesKey(key: string)`** + +- **Parameters**: + - `key`: The AES encryption key to set in the user's onboarding information. + +- **Description**: Assigns the AES key to the user’s onboarding information. If onboarding info doesn’t exist, it creates a new onboarding object with the provided key. + +### 5. **`setOnboardTxHash(hash: string)`** + +- **Parameters**: + - `hash`: The transaction hash associated with the user's onboarding process. + +- **Description**: Sets the transaction hash in the user’s onboarding info. If onboarding info is absent, it creates a new one with the hash. + +### 6. **`setRsaKeyPair(rsa: RsaKeyPair)`** + +- **Parameters**: + - `rsa`: The RSA key pair for encryption/decryption. + +- **Description**: Stores the provided RSA key pair in the user’s onboarding info. If the onboarding object is not present, it initializes a new one with the given RSA key. + +### 7. **`async encryptValue(plaintextValue: bigint | number | string, contractAddress: string, functionSelector: string): Promise`** + +- **Parameters**: + - `plaintextValue`: The value to encrypt, which can be of type `bigint`, `number`, or `string`. + - `contractAddress`: The address of the smart contract involved in the encryption. + - `functionSelector`: A string that identifies the specific contract function to which this encryption pertains. + +- **Returns**: A promise that resolves to either `itUint` or `itString`, depending on the type of the value. + +- **Description**: Encrypts the provided `plaintextValue` using the user’s AES key. If the AES key is missing, it attempts to generate or recover it. It handles both `bigint` and `string` values. + +### 8. **`async decryptValue(ciphertext: ctUint | ctString): Promise`** + +- **Parameters**: + - `ciphertext`: The encrypted value, either a `ctUint` (for integers) or a `ctString` (for strings). + +- **Returns**: A promise that resolves to either a `string` or `bigint`, depending on the ciphertext type. + +- **Description**: Decrypts the given ciphertext using the user’s AES key. If the AES key is not available, it attempts to generate or recover it. Handles both integer and string decryption. + +### 9. **`enableAutoOnboard()`** + +- **Description**: Enables automatic onboarding by setting the `_autoOnboard` flag to `true`. + +### 10. **`disableAutoOnboard()`** + +- **Description**: Disables automatic onboarding by setting the `_autoOnboard` flag to `false`. + +### 11. **`clearUserOnboardInfo()`** + +- **Description**: Clears the stored user onboarding information by setting `_userOnboardInfo` to `undefined`. + +### 12. **`async generateOrRecoverAes(onboardContractAddress: string = DEVNET_ONBOARD_CONTRACT_ADDRESS)`** + +- **Parameters**: + - `onboardContractAddress`: The contract address for onboarding purposes. Defaults to `DEVNET_ONBOARD_CONTRACT_ADDRESS`. + +- **Description**: Attempts to generate or recover the user’s AES key: + - If the AES key exists in the user’s onboarding info, it returns immediately. + - If the user’s RSA key and transaction hash are available, the AES key is recovered from the blockchain transaction using `recoverAesFromTx`. + - If neither AES nor RSA keys are available, it attempts to onboard the user by checking their account balance and invoking the onboarding process. + +- **Throws**: Throws an error if the account balance is 0, preventing the user from being onboarded. \ No newline at end of file diff --git a/example.env b/example.env deleted file mode 100644 index a5986d4..0000000 --- a/example.env +++ /dev/null @@ -1,2 +0,0 @@ -PRIVATE_KEY= -USER_KEY= \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6f57e12 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1283 @@ +{ + "name": "@coti-io/coti-ethers", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@coti-io/coti-ethers", + "version": "0.1.0", + "license": "Apache 2.0", + "dependencies": { + "@coti-io/coti-sdk-typescript": "0.6.6", + "ethers": "^6.13.1" + }, + "devDependencies": { + "@types/chai": "^4.2.0", + "@types/mocha": ">=9.1.0", + "chai": "^4.2.0", + "dotenv": "^16.4.5", + "mocha": "^10.7.3", + "ts-node": "^10.9.2", + "typescript": "^5.4.5" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" + }, + "node_modules/@coti-io/coti-sdk-typescript": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@coti-io/coti-sdk-typescript/-/coti-sdk-typescript-0.6.6.tgz", + "integrity": "sha512-bRnEWNWTLLk04fVNUUTyvjX6Tczdez2QLdIt2GM7pOyfSM8+d8bKgBgCyAP5tXOJqHD09xvXeDHf8B4yGGRJXQ==", + "dependencies": { + "node-forge": "^1.3.1" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz", + "integrity": "sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ethers": { + "version": "6.13.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.3.tgz", + "integrity": "sha512-/DzbZOLVtoO4fKvvQwpEucHAQgIwBGWuRvBdwE/lMXgXvvHHTSkn7XqAQ2b+gjJzZDJjWA9OD05bVceVOsBHbg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "peer": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index 3d45aed..59b8588 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@coti-io/coti-ethers", - "version": "0.0.1", + "version": "0.1.0", "license": "Apache 2.0", "description": "A Web3 library for interacting with the COTI V2 blockchain.", "main": "dist/index.js", @@ -20,13 +20,12 @@ "typescript": "^5.4.5" }, "dependencies": { - "ethers": "^6.13.1", - "@coti-io/coti-sdk-typescript": "git+https://github.com/coti-io/coti-sdk-typescript.git#c8990bd960d0291243d72646ecea43c14300339d" + "@coti-io/coti-sdk-typescript": "0.6.6", + "ethers": "^6.13.1" }, "scripts": { "build": "tsc", "prepare": "tsc", - "test": "ts-node test/test.ts", - "testWallet": "yarn test ./test/testNew.ts" + "test": "mocha --require ts-node/register ./test/wallet.test.ts" } } diff --git a/src/BrowserProvider.ts b/src/BrowserProvider.ts deleted file mode 100644 index db6bf73..0000000 --- a/src/BrowserProvider.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {BrowserProvider as BaseBrowserProvider, Eip1193Provider, Provider} from "ethers"; -import {Wallet} from "./Wallet"; -import type {Networkish} from "ethers/lib.commonjs/providers/network"; -import {BrowserProviderOptions} from "ethers/lib.commonjs/providers/provider-browser"; -import {OnboardInfo} from "./types"; - - -export class BrowserProvider extends BaseBrowserProvider { - - private wallet: Wallet | null = null; - - constructor(ethereum: Eip1193Provider, network?: Networkish, _options?: BrowserProviderOptions, wallet: Wallet | null = null) { - super(ethereum); - this.wallet = wallet; - } - - async encryptValue(plaintextValue: bigint | number | string, contractAddress: string, functionSelector: string) { - if (!this.wallet) { - throw new Error("wallet is undefined") - } - return this.wallet.encryptValue(plaintextValue, contractAddress, functionSelector) - } - - async decryptValue(ciphertext: bigint | Array) { - if (!this.wallet) { - throw new Error("wallet is not defined. please create one.") - } - return this.wallet.decryptValue(ciphertext) - } - - createWallet(privateKey: string, provider: Provider | null | undefined, onboardInfo: OnboardInfo | null = null) { - this.wallet = new Wallet(privateKey, provider, onboardInfo) - } - - clearWallet() { - this.wallet = null - } - -} diff --git a/src/index.ts b/src/index.ts index 56fd598..43e7475 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,27 @@ export * from 'ethers' -export * from './constants' -export * from './utils' -export {Wallet} from './Wallet' -export {BrowserProvider} from './BrowserProvider' +export * from './utils/constants' +export { + printAccountDetails, + getAccountBalance, + validateAddress, + getNonce, + addressValid, + getNativeBalance, + getEoa, + transferNative, + getDefaultProvider, + printNetworkDetails, + getLatestBlock, + isProviderConnected, + getAccountOnboardContract, + onboard, + recoverAesFromTx, + validateGasEstimation, + isGasEstimationValid +} from './utils' +export {Wallet} from './wallet/Wallet' +export {JsonRpcApiProvider} from './providers/JsonRpcApiProvider' +export {JsonRpcSigner} from './providers/JsonRpcSigner' +export {BrowserProvider} from './providers/BrowserProvider' export * from './types' -export * from '@coti-io/coti-sdk-typescript' +export {itBool, itUint, itString, ctBool, ctUint, ctString} from '@coti-io/coti-sdk-typescript' \ No newline at end of file diff --git a/src/providers/BrowserProvider.ts b/src/providers/BrowserProvider.ts new file mode 100644 index 0000000..9b0cef8 --- /dev/null +++ b/src/providers/BrowserProvider.ts @@ -0,0 +1,114 @@ +import {assertArgument, Eip1193Provider, JsonRpcApiProviderOptions, JsonRpcError, JsonRpcPayload, JsonRpcResult} from "ethers"; +import type {Networkish} from "ethers/lib.commonjs/providers/network"; +import {BrowserProviderOptions} from "ethers/lib.commonjs/providers/provider-browser"; +import {JsonRpcApiPollingProvider} from "./JsonRpcApiPollingProvider"; +import {JsonRpcSigner} from "./JsonRpcSigner" +import {OnboardInfo} from "../types"; + +export class BrowserProvider extends JsonRpcApiPollingProvider { + + #request: (method: string, params: Array | Record) => Promise; + + /** + * Connnect to the %%ethereum%% provider, optionally forcing the + * %%network%%. + */ + constructor(ethereum: Eip1193Provider, network?: Networkish, _options?: BrowserProviderOptions) { + // Copy the options + const options: JsonRpcApiProviderOptions = Object.assign({ }, + ((_options != null) ? _options: { }), + { batchMaxCount: 1 }); + + assertArgument(ethereum && ethereum.request, "invalid EIP-1193 provider", "ethereum", ethereum); + + super(network, options); + + this.#request = async (method: string, params: Array | Record) => { + const payload = { method, params }; + this.emit("debug", { action: "sendEip1193Request", payload }); + try { + const result = await ethereum.request(payload); + this.emit("debug", { action: "receiveEip1193Result", result }); + return result; + } catch (e: any) { + const error = new Error(e.message); + (error).code = e.code; + (error).data = e.data; + (error).payload = payload; + this.emit("debug", { action: "receiveEip1193Error", error }); + throw error; + } + }; + } + + async send(method: string, params: Array | Record): Promise { + await this._start(); + + return await super.send(method, params); + } + + async _send(payload: JsonRpcPayload | Array): Promise> { + assertArgument(!Array.isArray(payload), "EIP-1193 does not support batch request", "payload", payload); + + try { + const result = await this.#request(payload.method, payload.params || [ ]); + return [ { id: payload.id, result } ]; + } catch (e: any) { + return [ { + id: payload.id, + error: { code: e.code, data: e.data, message: e.message } + } ]; + } + } + + getRpcError(payload: JsonRpcPayload, error: JsonRpcError): Error { + + error = JSON.parse(JSON.stringify(error)); + + // EIP-1193 gives us some machine-readable error codes, so rewrite + // them into + switch (error.error.code || -1) { + case 4001: + error.error.message = `ethers-user-denied: ${ error.error.message }`; + break; + case 4200: + error.error.message = `ethers-unsupported: ${ error.error.message }`; + break; + } + + return super.getRpcError(payload, error); + } + + /** + * Resolves to ``true`` if the provider manages the %%address%%. + */ + async hasSigner(address: number | string): Promise { + if (address == null) { address = 0; } + + const accounts = await this.send("eth_accounts", [ ]); + if (typeof(address) === "number") { + return (accounts.length > address); + } + + address = address.toLowerCase(); + return accounts.filter((a: string) => (a.toLowerCase() === address)).length !== 0; + } + + async getSigner(address?: number | string, userOnboardInfo?: OnboardInfo): Promise { + if (address == null) { address = 0; } + + if (!(await this.hasSigner(address))) { + try { + //const resp = + await this.#request("eth_requestAccounts", [ ]); + //console.log("RESP", resp); + + } catch (error: any) { + const payload = error.payload; + throw this.getRpcError(payload, { id: payload.id, error }); + } + } + + return await super.getSigner(address, userOnboardInfo); + } +} diff --git a/src/providers/JsonRpcApiPollingProvider.ts b/src/providers/JsonRpcApiPollingProvider.ts new file mode 100644 index 0000000..20b9bc9 --- /dev/null +++ b/src/providers/JsonRpcApiPollingProvider.ts @@ -0,0 +1,56 @@ +import {JsonRpcApiProviderOptions, Networkish, Subscriber, Subscription} from "ethers" +import {JsonRpcApiProvider} from "./JsonRpcApiProvider" + +const defaultOptions = { + polling: false, + staticNetwork: null, + + batchStallTime: 10, // 10ms + batchMaxSize: (1 << 20), // 1Mb + batchMaxCount: 100, // 100 requests + + cacheTimeout: 250, + pollingInterval: 4000 +} + +interface Pollable { + pollingInterval: number; +} + +function isPollable(value: any): value is Pollable { + return (value && typeof(value.pollingInterval) === "number"); +} + +export abstract class JsonRpcApiPollingProvider extends JsonRpcApiProvider { + #pollingInterval: number; + constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) { + super(network, options); + + let pollingInterval = this._getOption("pollingInterval"); + if (pollingInterval == null) { pollingInterval = defaultOptions.pollingInterval; } + + this.#pollingInterval = pollingInterval; + } + + _getSubscriber(sub: Subscription): Subscriber { + const subscriber = super._getSubscriber(sub); + if (isPollable(subscriber)) { + subscriber.pollingInterval = this.#pollingInterval; + } + return subscriber; + } + + /** + * The polling interval (default: 4000 ms) + */ + get pollingInterval(): number { return this.#pollingInterval; } + set pollingInterval(value: number) { + if (!Number.isInteger(value) || value < 0) { throw new Error("invalid interval"); } + this.#pollingInterval = value; + this._forEachSubscriber((sub) => { + if (isPollable(sub)) { + sub.pollingInterval = this.#pollingInterval; + } + }); + } +} \ No newline at end of file diff --git a/src/providers/JsonRpcApiProvider.ts b/src/providers/JsonRpcApiProvider.ts new file mode 100644 index 0000000..5666353 --- /dev/null +++ b/src/providers/JsonRpcApiProvider.ts @@ -0,0 +1,38 @@ +import {JsonRpcApiProvider as BaseJsonRpcApiProvider, getAddress, JsonRpcApiProviderOptions, Networkish, resolveProperties} from "ethers" +import {JsonRpcSigner} from "./JsonRpcSigner" +import {OnboardInfo} from "../types"; + +export abstract class JsonRpcApiProvider extends BaseJsonRpcApiProvider { + + constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) { + super(network, options) + } + + async getSigner(address?: number | string, userOnboardInfo?: OnboardInfo): Promise { + if (address == null) { address = 0; } + + const accountsPromise = this.send("eth_accounts", [ ]); + + // Account index + if (typeof(address) === "number") { + const accounts = >(await accountsPromise); + if (address >= accounts.length) { throw new Error("no such account"); } + return new JsonRpcSigner(this, accounts[address], userOnboardInfo); + } + + const { accounts } = await resolveProperties({ + network: this.getNetwork(), + accounts: accountsPromise + }); + + // Account address + address = getAddress(address); + for (const account of accounts) { + if (getAddress(account) === address) { + return new JsonRpcSigner(this, address, userOnboardInfo); + } + } + + throw new Error("invalid account"); + } +} \ No newline at end of file diff --git a/src/providers/JsonRpcSigner.ts b/src/providers/JsonRpcSigner.ts new file mode 100644 index 0000000..60445b8 --- /dev/null +++ b/src/providers/JsonRpcSigner.ts @@ -0,0 +1,222 @@ +import {ctString, ctUint, decodeUint, decryptString, decryptUint, encodeKey, encodeUint, encrypt, itString, itUint} from "@coti-io/coti-sdk-typescript"; +import {JsonRpcSigner as BaseJsonRpcSigner, JsonRpcApiProvider, solidityPacked} from "ethers" +import {CotiNetwork, OnboardInfo, RsaKeyPair} from "../types"; +import {ONBOARD_CONTRACT_ADDRESS} from "../utils/constants"; +import {getAccountBalance, getDefaultProvider, onboard, recoverAesFromTx} from "../utils"; + +const EIGHT_BYTES = 8 + +export class JsonRpcSigner extends BaseJsonRpcSigner { + private _autoOnboard: boolean = true; + private _userOnboardInfo?: OnboardInfo; + + constructor(provider: JsonRpcApiProvider, address: string, userOnboardInfo?: OnboardInfo) { + super(provider, address) + this._userOnboardInfo = userOnboardInfo; + } + + async #buildInputText( + plaintext: bigint, + userKey: string, + contractAddress: string, + functionSelector: string + ): Promise { + if (plaintext >= BigInt(2) ** BigInt(64)) { + throw new RangeError("Plaintext size must be 64 bits or smaller.") + } + + // Convert the plaintext to bytes + const plaintextBytes = encodeUint(plaintext) + + // Convert user key to bytes + const keyBytes = encodeKey(userKey) + + // Encrypt the plaintext using AES key + const {ciphertext, r} = encrypt(keyBytes, plaintextBytes) + const ct = new Uint8Array([...ciphertext, ...r]) + + // Convert the ciphertext to BigInt + const ctInt = decodeUint(ct) + + + let signature: Uint8Array | string + + const message = solidityPacked( + ["address", "address", "bytes4", "uint256"], + [this.address, contractAddress, functionSelector, ctInt] + ) + + const messageBytes = new Uint8Array((message.length - 2) / 2) + + for (let i = 0; i < message.length - 2; i += 2) { + const byte = parseInt(message.substring(i + 2, i + 4), 16) + messageBytes[i / 2] = byte + } + + signature = await this.signMessage(messageBytes) + + return { + ciphertext: ctInt, + signature + } + } + + async #buildStringInputText( + plaintext: string, + userKey: string, + contractAddress: string, + functionSelector: string + ): Promise { + let encoder = new TextEncoder() + + // Encode the plaintext string into bytes (UTF-8 encoded) + let encodedStr = encoder.encode(plaintext) + + const inputText = { + ciphertext: { value: new Array() }, + signature: new Array() + } + + // Process the encoded string in chunks of 8 bytes + // We use 8 bytes since we will use ctUint64 to store + // each chunk of 8 characters + for (let startIdx = 0; startIdx < encodedStr.length; startIdx += EIGHT_BYTES) { + const endIdx = Math.min(startIdx + EIGHT_BYTES, encodedStr.length) + + const byteArr = new Uint8Array([...encodedStr.slice(startIdx, endIdx), ...new Uint8Array(EIGHT_BYTES - (endIdx - startIdx))]) // pad the end of the string with zeros if needed + + const it = await this.#buildInputText( + decodeUint(byteArr), // convert the 8-byte hex string into a number + userKey, + contractAddress, + functionSelector + ) + + inputText.ciphertext.value.push(it.ciphertext) + inputText.signature.push(it.signature) + } + + return inputText + } + + getAutoOnboard(): boolean { + return this._autoOnboard; + } + + getUserOnboardInfo(): OnboardInfo | undefined { + return this._userOnboardInfo; + } + + setUserOnboardInfo(onboardInfo?: Partial | undefined | null) { + if (onboardInfo) { + this._userOnboardInfo = { + ...this._userOnboardInfo, + ...onboardInfo, + }; + } + } + + setAesKey(key: string) { + if (this._userOnboardInfo) { + this._userOnboardInfo.aesKey = key + } else this._userOnboardInfo = {aesKey: key} + } + + setOnboardTxHash(hash: string) { + if (this._userOnboardInfo) { + this._userOnboardInfo.txHash = hash + } else this._userOnboardInfo = {txHash: hash} + } + + setRsaKeyPair(rsa: RsaKeyPair) { + if (this._userOnboardInfo) { + this._userOnboardInfo.rsaKey = rsa + } else this._userOnboardInfo = {rsaKey: rsa} + } + + enableAutoOnboard() { + this._autoOnboard = true; + } + + disableAutoOnboard() { + this._autoOnboard = false; + } + + clearUserOnboardInfo() { + this._userOnboardInfo = undefined + } + + async encryptValue(plaintextValue: bigint | number | string, contractAddress: string, functionSelector: string): Promise { + if (this._userOnboardInfo?.aesKey === null || this._userOnboardInfo?.aesKey === undefined) { + if (this._autoOnboard) { + console.warn("user AES key is not defined and need to onboard or recovered.") + await this.generateOrRecoverAes() + if (!this._userOnboardInfo || this._userOnboardInfo.aesKey === undefined || this._userOnboardInfo.aesKey === null) { + throw new Error("user AES key is not defined and cannot be onboarded or recovered.") + + } + } else + throw new Error("user AES key is not defined and auto onboard is off .") + + } + + const value = typeof plaintextValue === 'number' ? BigInt(plaintextValue) : plaintextValue + + let result; + + if (typeof value === 'bigint') { + result = await this.#buildInputText( + value, + this._userOnboardInfo.aesKey, + contractAddress, + functionSelector + ); + } else if (typeof value === 'string') { + result = await this.#buildStringInputText( + value, + this._userOnboardInfo.aesKey, + contractAddress, + functionSelector + ); + } else { + throw new Error("Unknown type"); + } + + return result; + } + + async decryptValue(ciphertext: ctUint | ctString): Promise { + if (this._userOnboardInfo?.aesKey === null || this._userOnboardInfo?.aesKey === undefined) { + if (this._autoOnboard) { + console.warn("user AES key is not defined and need to onboard or recovered.") + await this.generateOrRecoverAes() + if (!this._userOnboardInfo || this._userOnboardInfo.aesKey === undefined || this._userOnboardInfo.aesKey === null) { + throw new Error("user AES key is not defined and cannot be onboarded or recovered.") + + } + } else + throw new Error("user AES key is not defined and auto onboard is off .") + } + + if (typeof ciphertext === 'bigint') { + return decryptUint(ciphertext, this._userOnboardInfo.aesKey) + } + + return decryptString(ciphertext, this._userOnboardInfo.aesKey) + } + + async generateOrRecoverAes(onboardContractAddress: string = ONBOARD_CONTRACT_ADDRESS) { + if (this._userOnboardInfo?.aesKey) + return + else if (this._userOnboardInfo && this._userOnboardInfo.rsaKey && this._userOnboardInfo.txHash) + this.setAesKey(await recoverAesFromTx(this._userOnboardInfo.txHash, this._userOnboardInfo.rsaKey, + onboardContractAddress, this.provider)) + else { + const accountBalance = await getAccountBalance(this.address, this.provider || getDefaultProvider(CotiNetwork.Devnet)) + if (accountBalance > BigInt(0)) + this.setUserOnboardInfo(await onboard(onboardContractAddress, this)) + else + throw new Error("Account balance is 0 so user cannot be onboarded.") + } + } +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index b9260ca..6cbeda0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,7 @@ +export enum CotiNetwork { + Devnet = 'https://devnet.coti.io/rpc' +} + export type OnboardInfo = { aesKey?: string | null | undefined; rsaKey?: RsaKeyPair | null | undefined; diff --git a/src/utils/account.ts b/src/utils/account.ts new file mode 100644 index 0000000..d463567 --- /dev/null +++ b/src/utils/account.ts @@ -0,0 +1,73 @@ +import { formatEther, getAddress, isAddress, Provider, TransactionRequest, Wallet } from "ethers"; +import { isProviderConnected } from "./network"; +import { validateGasEstimation } from "./transaction"; + +export async function printAccountDetails(provider: Provider, address: string) { + if (!(await isProviderConnected(provider) && addressValid(address))) { + throw Error("provider not connected or address is not valid address"); + } + console.log("account address:", address); + const balanceInWei = await getAccountBalance(address, provider) + console.log("account balance: ", balanceInWei, 'wei (', formatEther(balanceInWei.toString()), 'ether)'); + console.log("account nonce: ", await getNonce(provider, address)) +} + +export async function getAccountBalance(address: string, provider: Provider) { + if (!(await isProviderConnected(provider) && addressValid(address))) { + throw Error("provider not connected or address is not valid address"); + } + return provider.getBalance(address); +} + +export function validateAddress(address: string): { valid: boolean; safe: string } { + return {'valid': isAddress(address), 'safe': getAddress(address)} +} + +export async function getNonce(provider: Provider, address: string) { + if (!(await isProviderConnected(provider) && addressValid(address))) { + throw Error("provider not connected or address is not valid address"); + } + return await provider.getTransactionCount(address) +} + +export function addressValid(address: string): boolean { + return validateAddress(address).valid +} + +export async function getNativeBalance(provider: Provider, address: string) { + if (!(await isProviderConnected(provider) && addressValid(address))) { + throw Error("provider not connected or address is not valid address"); + } + return formatEther(await getAccountBalance(address, provider)) +} + +export async function getEoa(accountPrivateKey: string) { + const wallet = new Wallet(accountPrivateKey); + if (!addressValid(wallet.address)) + throw new Error("Address generated from pk is not valid"); + return wallet.address; +} + +export async function transferNative(provider: Provider, wallet: Wallet, recipientAddress: string, amountToTransferInWei: BigInt, nativeGasUnit: number) { + const feeData = await provider.getFeeData(); + const gasPrice = feeData.gasPrice; + + const tx: TransactionRequest = { + to: recipientAddress, + from: wallet.address, + value: amountToTransferInWei.toString(), + nonce: await wallet.getNonce(), + gasLimit: nativeGasUnit, + gasPrice: gasPrice + }; + try { + await validateGasEstimation(provider, tx) + const transaction = await wallet.sendTransaction(tx); + await transaction.wait(); + + console.log('Transaction successful with hash:', transaction.hash); + return transaction; + } catch (error) { + console.error('Transaction failed:', error); + } +} \ No newline at end of file diff --git a/src/constants.ts b/src/utils/constants.ts similarity index 91% rename from src/constants.ts rename to src/utils/constants.ts index 5baf0a9..077264c 100644 --- a/src/constants.ts +++ b/src/utils/constants.ts @@ -1,4 +1,4 @@ -export const DEVNET_ONBOARD_CONTRACT_ADDRESS = "0x413370ed41FB9EE3aea0B1B91FD336cC0be1Bad6" +export const ONBOARD_CONTRACT_ADDRESS = "0x413370ed41FB9EE3aea0B1B91FD336cC0be1Bad6" export const ONBOARD_CONTRACT_ABI = [ { diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..38c1815 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,5 @@ +export * from "./account" +export * from "./constants" +export * from "./network" +export * from "./onboard" +export * from "./transaction" \ No newline at end of file diff --git a/src/utils/network.ts b/src/utils/network.ts new file mode 100644 index 0000000..e66032c --- /dev/null +++ b/src/utils/network.ts @@ -0,0 +1,35 @@ +import { JsonRpcProvider, Provider } from "ethers"; +import { CotiNetwork } from "../types"; + +export function getDefaultProvider(cotiNetwork: CotiNetwork) { + return new JsonRpcProvider(cotiNetwork) +} + +export async function printNetworkDetails(provider: Provider) { + if (!await isProviderConnected(provider)) { + throw Error("provider not connected"); + } + if (provider instanceof JsonRpcProvider) { + console.log(`provider: ${provider._getConnection().url}`) + } + const network = await provider.getNetwork(); + console.log(`chainId: ${network.chainId}`) + console.log(`latest block: ${await getLatestBlock(provider)}`) +} + +export async function getLatestBlock(provider: Provider) { + if (!await isProviderConnected(provider)) { + throw Error("provider not connected or address is not valid address"); + } + return await provider.getBlockNumber() +} + +export async function isProviderConnected(provider: Provider): Promise { + if (provider == undefined) { + throw Error('Provider does not exist.') + } + const network = await provider.getNetwork(); + if (!network) + return false + return true +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils/onboard.ts similarity index 61% rename from src/utils.ts rename to src/utils/onboard.ts index 5fb3485..683d27c 100644 --- a/src/utils.ts +++ b/src/utils/onboard.ts @@ -1,21 +1,29 @@ -import {BaseWallet, Contract, keccak256, Signer} from "ethers"; -import {decryptRSA, generateRSAKeyPair, initEtherProvider, sign} from "@coti-io/coti-sdk-typescript"; -import {RsaKeyPair} from "./types"; -import {ONBOARD_CONTRACT_ABI} from "./constants"; +import { Contract, ContractRunner, keccak256, Provider } from "ethers" +import { getDefaultProvider } from "./network" +import { decryptRSA, generateRSAKeyPair, sign } from "@coti-io/coti-sdk-typescript" +import { CotiNetwork, RsaKeyPair } from "../types" +import { ONBOARD_CONTRACT_ABI } from "./constants" +import { Wallet } from "../wallet/Wallet" +import { JsonRpcSigner } from "../providers/JsonRpcSigner" -export function getAccountOnboardContract(contractAddress: string, wallet?: Signer) { - return new Contract(contractAddress, JSON.stringify(ONBOARD_CONTRACT_ABI), wallet) +export function getAccountOnboardContract(contractAddress: string, runner?: ContractRunner) { + return new Contract(contractAddress, JSON.stringify(ONBOARD_CONTRACT_ABI), runner) } - -export async function onboard(defaultOnboardContractAddress: string, wallet: BaseWallet) { +export async function onboard(defaultOnboardContractAddress: string, signer: Wallet | JsonRpcSigner) { try { - const accountOnboardContract: any = getAccountOnboardContract(defaultOnboardContractAddress, wallet) + const accountOnboardContract: any = getAccountOnboardContract(defaultOnboardContractAddress, signer) const {publicKey, privateKey} = generateRSAKeyPair() - let receipt; - const signedEK = sign(keccak256(publicKey), wallet.privateKey) - receipt = await (await accountOnboardContract.onboardAccount(publicKey, signedEK, {gasLimit: 12000000})).wait() + let signedEK: string | Uint8Array + + if (signer instanceof Wallet) { + signedEK = sign(keccak256(publicKey), signer.privateKey) + } else { + signedEK = await signer.signMessage(publicKey) + } + + const receipt = await (await accountOnboardContract.onboardAccount(publicKey, signedEK, {gasLimit: 12000000})).wait() if (!receipt || !receipt.logs || !receipt.logs[0]) { throw new Error("failed to onboard account") @@ -25,7 +33,7 @@ export async function onboard(defaultOnboardContractAddress: string, wallet: Bas throw new Error("failed to onboard account") } const encryptedKey = decodedLog.args.userKey - console.log(encryptedKey) + return { aesKey: decryptRSA(privateKey, encryptedKey.substring(2)), rsaKey: {publicKey: publicKey, privateKey: privateKey}, @@ -38,15 +46,14 @@ export async function onboard(defaultOnboardContractAddress: string, wallet: Bas } - export async function recoverAesFromTx(txHash: string, rsaKey: RsaKeyPair, defaultOnboardContractAddress: string, - wallet: BaseWallet) { + provider: Provider | null) { try { - const receipt = wallet.provider - ? await wallet.provider.getTransactionReceipt(txHash) - : await initEtherProvider().getTransactionReceipt(txHash); + const receipt = provider + ? await provider.getTransactionReceipt(txHash) + : await getDefaultProvider(CotiNetwork.Devnet).getTransactionReceipt(txHash) if (!receipt || !receipt.logs || !receipt.logs[0]) { console.error("failed to get onboard tx info") @@ -62,4 +69,4 @@ export async function recoverAesFromTx(txHash: string, throw Error(`unable to recover aes key from transaction.`) } -} +} \ No newline at end of file diff --git a/src/utils/transaction.ts b/src/utils/transaction.ts new file mode 100644 index 0000000..5a30bcb --- /dev/null +++ b/src/utils/transaction.ts @@ -0,0 +1,17 @@ +import { Provider, toNumber, TransactionRequest } from "ethers"; + +export async function validateGasEstimation(provider: Provider, tx: TransactionRequest) { + const {valid, gasEstimation} = await isGasEstimationValid(provider, tx); + if (!valid) + throw new Error(`Not enough gas for tx. Provided: ${tx.gasLimit}, needed: ${gasEstimation}`); +} + +export async function isGasEstimationValid(provider: Provider, tx: TransactionRequest) { + const estimatedGas = await provider.estimateGas(tx) + const gasLimit = tx.gasLimit ? toNumber(tx.gasLimit) : 0; + + if (!estimatedGas || estimatedGas > gasLimit) { + throw new Error(`Not enough gas for tx. Provided: ${gasLimit}, needed: ${estimatedGas.toString()}`); + } + return {valid: true, gasEstimation: estimatedGas} +} \ No newline at end of file diff --git a/src/Wallet.ts b/src/wallet/Wallet.ts similarity index 80% rename from src/Wallet.ts rename to src/wallet/Wallet.ts index 7df822d..2e57dd4 100644 --- a/src/Wallet.ts +++ b/src/wallet/Wallet.ts @@ -1,25 +1,27 @@ import {Provider, SigningKey, Wallet as BaseWallet} from "ethers"; -import {OnboardInfo, RsaKeyPair} from "./types"; +import {CotiNetwork, OnboardInfo, RsaKeyPair} from "../types"; import { buildInputText, buildStringInputText, + ctString, + ctUint, decryptString, decryptUint, - getAccountBalance, - initEtherProvider + itString, + itUint } from "@coti-io/coti-sdk-typescript"; -import {onboard, recoverAesFromTx} from "./utils"; -import {DEVNET_ONBOARD_CONTRACT_ADDRESS} from "./constants"; +import {getAccountBalance, getDefaultProvider, onboard, recoverAesFromTx} from "../utils"; +import {ONBOARD_CONTRACT_ADDRESS} from "../utils/constants"; export class Wallet extends BaseWallet { private _autoOnboard: boolean = true; - private _userOnboardInfo: OnboardInfo | null = null; + private _userOnboardInfo?: OnboardInfo; constructor( - privateKey: string | SigningKey = BaseWallet.createRandom().privateKey, - provider: Provider | null | undefined = initEtherProvider(), - userOnboardInfo: OnboardInfo | null = null + privateKey: string | SigningKey, + provider?: Provider | null, + userOnboardInfo?: OnboardInfo ) { super(privateKey, provider); this._userOnboardInfo = userOnboardInfo; @@ -29,7 +31,7 @@ export class Wallet extends BaseWallet { return this._autoOnboard; } - getUserOnboardInfo(): OnboardInfo | null { + getUserOnboardInfo(): OnboardInfo | undefined { return this._userOnboardInfo; } @@ -60,7 +62,7 @@ export class Wallet extends BaseWallet { } else this._userOnboardInfo = {rsaKey: rsa} } - async encryptValue(plaintextValue: bigint | number | string, contractAddress: string, functionSelector: string) { + async encryptValue(plaintextValue: bigint | number | string, contractAddress: string, functionSelector: string): Promise { if (this._userOnboardInfo?.aesKey === null || this._userOnboardInfo?.aesKey === undefined) { if (this._autoOnboard) { console.warn("user AES key is not defined and need to onboard or recovered.") @@ -69,22 +71,21 @@ export class Wallet extends BaseWallet { throw new Error("user AES key is not defined and cannot be onboarded or recovered.") } - } else - throw new Error("user AES key is not defined and auto onboard is off .") - + } else { + throw new Error("user AES key is not defined and auto onboard is off.") + } } const value = typeof plaintextValue === 'number' ? BigInt(plaintextValue) : plaintextValue let result; if (typeof value === 'bigint') { - const singleResult = buildInputText(value, { + result = buildInputText(value, { wallet: this, userKey: this._userOnboardInfo.aesKey }, contractAddress, functionSelector); - result = [{ciphertext: singleResult.ctInt, signature: singleResult.signature}]; } else if (typeof value === 'string') { - result = await buildStringInputText(value, { + result = buildStringInputText(value, { wallet: this, userKey: this._userOnboardInfo.aesKey }, contractAddress, functionSelector); @@ -95,7 +96,7 @@ export class Wallet extends BaseWallet { return result; } - async decryptValue(ciphertext: bigint | Array) { + async decryptValue(ciphertext: ctUint | ctString) { if (this._userOnboardInfo?.aesKey === null || this._userOnboardInfo?.aesKey === undefined) { if (this._autoOnboard) { console.warn("user AES key is not defined and need to onboard or recovered.") @@ -124,17 +125,17 @@ export class Wallet extends BaseWallet { } clearUserOnboardInfo() { - this._userOnboardInfo = null + this._userOnboardInfo = undefined } - async generateOrRecoverAes(onboardContractAddress: string = DEVNET_ONBOARD_CONTRACT_ADDRESS) { + async generateOrRecoverAes(onboardContractAddress: string = ONBOARD_CONTRACT_ADDRESS) { if (this._userOnboardInfo?.aesKey) return else if (this._userOnboardInfo && this._userOnboardInfo.rsaKey && this._userOnboardInfo.txHash) this.setAesKey(await recoverAesFromTx(this._userOnboardInfo.txHash, this._userOnboardInfo.rsaKey, - onboardContractAddress, this)) + onboardContractAddress, this.provider)) else { - const accountBalance = await getAccountBalance(this.address, this.provider || initEtherProvider()) + const accountBalance = await getAccountBalance(this.address, this.provider || getDefaultProvider(CotiNetwork.Devnet)) if (accountBalance > BigInt(0)) this.setUserOnboardInfo(await onboard(onboardContractAddress, this)) else diff --git a/test/example.env b/test/example.env new file mode 100644 index 0000000..374d16a --- /dev/null +++ b/test/example.env @@ -0,0 +1,4 @@ +PRIVATE_KEY= +USER_KEY= +RSA_PUB= +RSA_PRIVATE= \ No newline at end of file diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 01c9e5c..2973d4f 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -1,55 +1,47 @@ import {Wallet as etherWallet} from "ethers" -import {DEVNET_ONBOARD_CONTRACT_ADDRESS, getAccountOnboardContract, Wallet} from '../src' +import {CotiNetwork, ONBOARD_CONTRACT_ADDRESS, getAccountOnboardContract, getDefaultProvider, Wallet} from '../src' import {expect} from "chai" -import 'dotenv/config'; +import dotenv from "dotenv" +dotenv.config({ path: './test/.env' }) -describe("Wallet tests", async function () { - this.timeout(20000); +describe("Wallet tests", function () { + this.timeout(30000); const pk = process.env.PRIVATE_KEY || Wallet.createRandom().privateKey; + let wallet: Wallet - it('Should successfully create wallet without aes key', async function () { - const wallet = new Wallet(pk); + it('Should successfully create wallet without aes key', function () { + const provider = getDefaultProvider(CotiNetwork.Devnet) + wallet = new Wallet(pk, provider); expect(wallet.address).to.equal(new etherWallet(pk).address); - expect(wallet.getUserOnboardInfo()).to.be.null + expect(wallet.getUserOnboardInfo()).to.be.undefined }) - it('Should successfully create wallet and onboard it.', async function () { - const wallet = new Wallet(pk); + it('Should successfully onboard the wallet', async function () { await wallet.generateOrRecoverAes() - expect(wallet.address).to.equal(new etherWallet(pk).address); expect(wallet.getUserOnboardInfo()?.aesKey).to.not.equal(null); - expect(wallet.getUserOnboardInfo()?.aesKey).to.equal(process.env.AES_KEY); + expect(wallet.getUserOnboardInfo()?.aesKey).to.equal(process.env.USER_KEY); }) it('Should successfully encrypt and decrypt', async function () { const msg = "hello world" - const wallet = new Wallet(pk); - await wallet.generateOrRecoverAes() - const accountOnboardContract: any = getAccountOnboardContract(DEVNET_ONBOARD_CONTRACT_ADDRESS, wallet) - // const func = accountOnboardContract.fragment.onboard - const ct: { ctInt: bigint; signature: Uint8Array; } | { - ciphertext: bigint, - signature: Uint8Array - }[] = await wallet.encryptValue(msg, DEVNET_ONBOARD_CONTRACT_ADDRESS, accountOnboardContract.interface.fragments[1].selector); - let pt - const ciphertexts = ct.map((val) => val.ciphertext); - pt = await wallet.decryptValue(ciphertexts); - expect(ciphertexts[0]).to.not.equal(msg[0]) + const accountOnboardContract: any = getAccountOnboardContract(ONBOARD_CONTRACT_ADDRESS, wallet) + const inputText = await wallet.encryptValue(msg, ONBOARD_CONTRACT_ADDRESS, accountOnboardContract.interface.fragments[1].selector); + let pt = await wallet.decryptValue(inputText.ciphertext); expect(pt).to.equal(msg) }) - it('Should failed encrypt when autoOnboard flag off', async function () { + it('Should fail to encrypt when autoOnboard flag off', async function () { const wallet = new Wallet(pk); wallet.disableAutoOnboard(); - const accountOnboardContract: any = getAccountOnboardContract(DEVNET_ONBOARD_CONTRACT_ADDRESS, wallet); + const accountOnboardContract: any = getAccountOnboardContract(ONBOARD_CONTRACT_ADDRESS, wallet); let ct; let errorThrown = false; try { ct = await wallet.encryptValue( "on board", - DEVNET_ONBOARD_CONTRACT_ADDRESS, + ONBOARD_CONTRACT_ADDRESS, accountOnboardContract.interface.fragments[1].selector ); } catch (error) { @@ -60,8 +52,9 @@ describe("Wallet tests", async function () { expect(ct).to.be.undefined; }); - it('Should aes recovered from tx hash and rsa key', async function () { - const wallet = new Wallet(pk); + it('Should recover aes key from tx hash and rsa key', async function () { + const provider = getDefaultProvider(CotiNetwork.Devnet) + const wallet = new Wallet(pk, provider); await wallet.generateOrRecoverAes() const onBoardInfo = { rsaKey: { @@ -70,19 +63,19 @@ describe("Wallet tests", async function () { }, txHash: process.env.TX_HASH } - const wallet2 = new Wallet(pk, null, onBoardInfo); + const wallet2 = new Wallet(pk, provider, onBoardInfo); await wallet2.generateOrRecoverAes() expect(wallet.address).to.equal(wallet2.address); expect(wallet.getUserOnboardInfo()?.aesKey).to.equal(wallet2.getUserOnboardInfo()?.aesKey); }) - it('Should be able to set autoOnboard off', async function () { + it('Should be able to set autoOnboard off', function () { const wallet = new Wallet(pk); wallet.disableAutoOnboard() expect(wallet.getAutoOnboard()).to.equal(false) }) - it('Should be able to set autoOnboard on', async function () { + it('Should be able to set autoOnboard on', function () { const wallet = new Wallet(pk); wallet.disableAutoOnboard() expect(wallet.getAutoOnboard()).to.equal(false) @@ -91,7 +84,7 @@ describe("Wallet tests", async function () { }) - it('Should be able to set userOnboardInfo parameters.', async function () { + it('Should be able to set userOnboardInfo parameters', function () { const wallet = new Wallet(pk); const rsaKey = { publicKey: parseRsaKey(process.env.RSA_PUB), @@ -102,10 +95,10 @@ describe("Wallet tests", async function () { wallet.setOnboardTxHash(txHash) const aesKey = process.env.AES_KEY || "e0262555000f88878acc5b38146fbd05" wallet.setAesKey(aesKey) - expect(wallet.getUserOnboardInfo()).to.not.be.null + expect(wallet.getUserOnboardInfo()).to.not.be.undefined }) - it('Should be able to reset userOnboardInfo parameters.', async function () { + it('Should be able to reset userOnboardInfo parameters', function () { const wallet = new Wallet(pk); const rsaKey = { publicKey: parseRsaKey(process.env.RSA_PUB), @@ -116,9 +109,9 @@ describe("Wallet tests", async function () { wallet.setOnboardTxHash(txHash) const aesKey = process.env.AES_KEY || "e0262555000f88878acc5b38146fbd05" wallet.setAesKey(aesKey) - expect(wallet.getUserOnboardInfo()).to.not.be.null + expect(wallet.getUserOnboardInfo()).to.not.be.undefined wallet.clearUserOnboardInfo() - expect(wallet.getUserOnboardInfo()).to.be.null + expect(wallet.getUserOnboardInfo()).to.be.undefined }) }) diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 5d162fa..0000000 --- a/yarn.lock +++ /dev/null @@ -1,730 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@adraffy/ens-normalize@1.10.1": - version "1.10.1" - resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz" - integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== - -"@coti-io/coti-sdk-typescript@git+https://github.com/coti-io/coti-sdk-typescript.git#c8990bd960d0291243d72646ecea43c14300339d": - version "0.5.5" - resolved "git+https://github.com/coti-io/coti-sdk-typescript.git#c8990bd960d0291243d72646ecea43c14300339d" - dependencies: - node-forge "^1.3.1" - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@noble/curves@1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz" - integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== - dependencies: - "@noble/hashes" "1.3.2" - -"@noble/hashes@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz" - integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== - -"@tsconfig/node10@^1.0.7": - version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" - integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - -"@types/chai@^4.2.0": - version "4.3.17" - resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.17.tgz" - integrity sha512-zmZ21EWzR71B4Sscphjief5djsLre50M6lI622OSySTmn9DB3j+C3kWroHfBQWXbOBwbgg/M8CG/hUxDLIloow== - -"@types/mocha@>=9.1.0": - version "10.0.7" - resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz" - integrity sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw== - -"@types/node@18.15.13": - version "18.15.13" - resolved "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz" - integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== - -acorn-walk@^8.1.1: - version "8.3.3" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== - dependencies: - acorn "^8.11.0" - -acorn@^8.11.0, acorn@^8.4.1: - version "8.12.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz" - integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== - -aes-js@4.0.0-beta.5: - version "4.0.0-beta.5" - resolved "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz" - integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== - -ansi-colors@^4.1.3: - version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@~3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browser-stdout@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -camelcase@^6.0.0: - version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -chai@^4.2.0: - version "4.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz" - integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.1.0" - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== - dependencies: - get-func-name "^2.0.2" - -chokidar@^3.5.3: - version "3.6.0" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -debug@^4.3.5: - version "4.3.6" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz" - integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== - dependencies: - ms "2.1.2" - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -deep-eql@^4.1.3: - version "4.1.4" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz" - integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== - dependencies: - type-detect "^4.0.0" - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -diff@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz" - integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== - -dotenv@^16.4.5: - version "16.4.5" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" - integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -ethers@^6.13.1: - version "6.13.1" - resolved "https://registry.npmjs.org/ethers/-/ethers-6.13.1.tgz" - integrity sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.17.1" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-func-name@^2.0.1, get-func-name@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -he@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -loupe@^2.3.6: - version "2.3.7" - resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== - dependencies: - get-func-name "^2.0.1" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -minimatch@^5.0.1, minimatch@^5.1.6: - version "5.1.6" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -mocha@^10.7.3: - version "10.7.3" - resolved "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz" - integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== - dependencies: - ansi-colors "^4.1.3" - browser-stdout "^1.3.1" - chokidar "^3.5.3" - debug "^4.3.5" - diff "^5.2.0" - escape-string-regexp "^4.0.0" - find-up "^5.0.0" - glob "^8.1.0" - he "^1.2.0" - js-yaml "^4.1.0" - log-symbols "^4.1.0" - minimatch "^5.1.6" - ms "^2.1.3" - serialize-javascript "^6.0.2" - strip-json-comments "^3.1.1" - supports-color "^8.1.1" - workerpool "^6.5.1" - yargs "^16.2.0" - yargs-parser "^20.2.9" - yargs-unparser "^2.0.0" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -node-forge@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== - -picomatch@^2.0.4, picomatch@^2.2.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -safe-buffer@^5.1.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -ts-node@^10.9.2: - version "10.9.2" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tslib@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -type-detect@^4.0.0, type-detect@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz" - integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== - -typescript@^5.4.5: - version "5.5.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -workerpool@^6.5.1: - version "6.5.1" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" - integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -ws@8.17.1: - version "8.17.1" - resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yargs-parser@^20.2.2, yargs-parser@^20.2.9: - version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-unparser@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==