From 9219555be6adcc9f5d4debeae60c91b0770489d2 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:05:56 +0100 Subject: [PATCH 001/263] feat(e2e-test): introducing Tinny --- .gitignore | 4 + local-tests/README.md | 118 + local-tests/build.mjs | 55 + local-tests/setup/accs/accs.ts | 21 + local-tests/setup/networkContext.example.json | 11268 ++++++++++++++++ .../session-sigs/get-eoa-session-sigs.ts | 156 + .../get-lit-action-session-sigs.ts | 91 + .../session-sigs/get-pkp-session-sigs.ts | 45 + local-tests/setup/tinny-config.ts | 145 + local-tests/setup/tinny-environment.ts | 371 + local-tests/setup/tinny-operations.ts | 209 + local-tests/setup/tinny-person.ts | 182 + local-tests/shim.mjs | 3 + local-tests/test.ts | 39 + local-tests/tests/test-bundle-speed.ts | 15 + local-tests/tests/test-example.ts | 46 + package.json | 5 +- yarn.lock | 2428 ++-- 18 files changed, 14017 insertions(+), 1184 deletions(-) create mode 100644 local-tests/README.md create mode 100644 local-tests/build.mjs create mode 100644 local-tests/setup/accs/accs.ts create mode 100644 local-tests/setup/networkContext.example.json create mode 100644 local-tests/setup/session-sigs/get-eoa-session-sigs.ts create mode 100644 local-tests/setup/session-sigs/get-lit-action-session-sigs.ts create mode 100644 local-tests/setup/session-sigs/get-pkp-session-sigs.ts create mode 100644 local-tests/setup/tinny-config.ts create mode 100644 local-tests/setup/tinny-environment.ts create mode 100644 local-tests/setup/tinny-operations.ts create mode 100644 local-tests/setup/tinny-person.ts create mode 100644 local-tests/shim.mjs create mode 100644 local-tests/test.ts create mode 100644 local-tests/tests/test-bundle-speed.ts create mode 100644 local-tests/tests/test-example.ts diff --git a/.gitignore b/.gitignore index 5ff919dcab..a7c51e3dec 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,7 @@ storage.test.db .nx .yalc + +local-tests/build +local-tests/setup/networkContext.json +note.txt \ No newline at end of file diff --git a/local-tests/README.md b/local-tests/README.md new file mode 100644 index 0000000000..a4db70e7af --- /dev/null +++ b/local-tests/README.md @@ -0,0 +1,118 @@ +# Tinny + +Tinny is a mini test framework, serving as a temporary solution for running e2e tests in TypeScript until we can integrate `Jest`. It utilizes `esbuild` for its rapid compilation speed to bundle all the tests into a single `test.mjs` file, then runs the built `test.mjs` file immediately. See [Benchmark](#esbuild-benchmark) + +# How to run + +In most cases, you will only need the following two environment variables, and a `--filter` flag. See [API](#api) + +The `testName` specified in the filter **must be the same as the function name**. + +## to run all tests + +``` +// run all tests on localchain +DEBUG=true NETWORK=localchain yarn test:local + +// run filtered tests on manzano +DEBUG=true NETWORK=manzano yarn test:local --filter=testExample +DEBUG=true NETWORK=manzano yarn test:local --filter=testExample,testBundleSpeed + +// eg. +yarn test:local --filter=testExample,testBundleSpeed + +``` + +## API + +Below is the API documentation for the `ProcessEnvs` interface, detailing the configurable environment variables and their purposes: + +| Variable | Description | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `MAX_ATTEMPTS` | Each test is executed in a loop with a maximum number of attempts specified by `devEnv.processEnvs.MAX_ATTEMPTS`. | +| `NETWORK` | The network to use for testing, which can be one of the following: `LIT_TESTNET.LOCALCHAIN`, `LIT_TESTNET.MANZANO`, or `LIT_TESTNET.CAYENNE`. | +| `DEBUG` | Specifies whether to enable debug mode. | +| `REQUEST_PER_KILOSECOND` | To execute a transaction with Lit, you must reserve capacity on the network using Capacity Credits. These allow a set number of requests over a period (default 2 days). | +| `WAIT_FOR_KEY_INTERVAL` | Wait time in milliseconds if no private keys are available. | +| `TIME_TO_RELEASE_KEY` | Time to wait before releasing the key after requesting it. | +| `RUN_IN_BAND` | Run all tests in a single thread. | +| `RUN_IN_BAND_INTERVAL` | The interval in milliseconds to run the tests in a single thread. | +| `LIT_RPC_URL` | The URL of the Lit RPC server. If running locally on Anvil, it should be 'http://127.0.0.1:8545'. | +| `LIT_OFFICIAL_RPC` | The URL of the official Lit RPC server, usually 'https://chain-rpc.litprotocol.com/http' but can be changed if needed. | + +# Writing a test + +Writing a test is the same as writing any other code, except that you must throw an error if any occur. There are no assertion libraries, so all tests are written using basic `if-else` statements. + +In the test function, a `devEnv` variable will automatically be added as the first parameter to your function. + +## Using the devEnv API in the test + +```ts +export const testExample = async (devEnv: TinnyEnvironment) => { + + // ========== Enviorment ========== + // This test will be skipped if we are testing on the Cayenne network + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + // Using litNodeClient + const res = await devEnv.litNodeClient.executeJs({...}); + + // ========== Creating a new identify/user profile ========== + const alice = await devEnv.createRandomPerson(); + + // Alice minting a capacity creditrs NFT + const aliceCcNft = await alice.mintCapacityCreditsNFT(); + + // Alice creating a capacity delegation authSig + const aliceCcAuthSig = await alice.createCapacityDelegationAuthSig(); +}; +``` + +## TinnyPerson Class API + +The `TinnyPerson` class encapsulates various functionalities to manage wallet operations, authentication, and contract interactions for testing purposes. Below is a detailed API documentation: + +### Alice's Properties + +| Property | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `privateKey` | The private key used to instantiate the wallet associated with the TinnyPerson instance. | +| `wallet` | An `ethers.Wallet` instance created using the provided `privateKey` and connected to the specified provider. | +| `siweMessage` | A string that holds the Sign-In with Ethereum (SIWE) message used for authentication. | +| `pkp` | EOA/Hot wallet owned PKP NFT | +| `authSig` | An `AuthSig` object that stores the authentication signature derived from the SIWE message. | +| `authMethod` | An `AuthMethod` object representing the authentication method used, typically related to blockchain wallet authentication. | +| `authMethodOwnedPkp` | PKP information specifically tied to the authentication method of the wallet. | +| `contractsClient` | An instance of `LitContracts`, used to interact with Lit Protocol smart contracts for operations such as minting tokens or PKP NFTs. | +| `provider` | An `ethers.providers.JsonRpcProvider` instance connected to the blockchain network specified in `envConfig`. | +| `loveLetter` | A `Uint8Array` containing a keccak256 hashed value, typically used as unsigned data to be passed to the `executeJs` and `pkpSign` functions | + +### Methods + +| Method | Description | +| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `constructor({privateKey, envConfig})` | Initializes a new instance of `TinnyPerson` with the specified private key and environment configuration. Sets up the wallet and provider based on these settings. | +| `spawn()` | Performs several operations to set up the TinnyPerson instance fully, including authentication and contract client setup. It also mints a PKP using the specified authentication method. | +| `mintCapacityCreditsNFT()` | Mints a Capacity Credits NFT based on the `REQUEST_PER_KILOSECOND` setting in `envConfig`. Returns the token ID of the minted NFT. | +| `createCapacityDelegationAuthSig(addresses)` | Mints a Capacity Credits NFT and creates an authentication signature for delegating capacity, which can be used to authorize other addresses to use the minted credits. | + +## + +# esbuild benchmark + +```ts + +// test-bundle-speed.ts +export const testBundleSpeed = async (devEnv: TinnyEnvironment) => { + const a = await import('@lit-protocol/lit-node-client'); + const b = await import('@lit-protocol/contracts-sdk'); + const c = await import('@lit-protocol/auth-helpers'); + const d = await import('@lit-protocol/constants'); + const e = await import('@lit-protocol/lit-auth-client'); + + console.log(a, b, c, d, e); +}; +---------------- +Build time: 77ms +``` diff --git a/local-tests/build.mjs b/local-tests/build.mjs new file mode 100644 index 0000000000..02e3008a3b --- /dev/null +++ b/local-tests/build.mjs @@ -0,0 +1,55 @@ +import * as esbuild from 'esbuild'; +import { nodeExternalsPlugin } from 'esbuild-node-externals'; +import fs from 'fs'; + +const TEST_DIR = 'local-tests'; + +/** + * Builds the project using esbuild. + * @returns {Promise} A promise that resolves when the build is complete. + */ +export const build = async () => { + await esbuild.build({ + entryPoints: [`${TEST_DIR}/test.ts`], // Use template literals to inject the variable + outfile: `./${TEST_DIR}/build/test.mjs`, // Modify paths to use the TEST_DIR variable + bundle: true, + plugins: [ + nodeExternalsPlugin({ + allowList: ['ethers', '@lit-protocol/accs-schemas', 'crypto'], + }), + ], + platform: 'node', + target: 'esnext', + format: 'esm', + inject: [`./${TEST_DIR}/shim.mjs`], // Update inject path to use TEST_DIR + mainFields: ['module', 'main'], + }); +}; + +/** + * Inserts a polyfill at the beginning of a file. + * The polyfill ensures that the global `fetch` function is available. + * @returns {void} + */ +export const postBuildPolyfill = () => { + const file = fs.readFileSync(`./${TEST_DIR}/build/test.mjs`, 'utf8'); // Use the TEST_DIR variable in the file path + const content = `import fetch from 'cross-fetch'; +try { + if (!globalThis.fetch) { + globalThis.fetch = fetch; + } +} catch (error) { + console.error('❌ Error in polyfill', error); +} +`; + const newFile = content + file; + fs.writeFileSync(`./${TEST_DIR}/build/test.mjs`, newFile); // Use the TEST_DIR variable in the file path +}; + +// Go! +(async () => { + const start = Date.now(); + await build(); + postBuildPolyfill(); + console.log(`[build.mjs] 🚀 Build time: ${Date.now() - start}ms`); +})(); diff --git a/local-tests/setup/accs/accs.ts b/local-tests/setup/accs/accs.ts new file mode 100644 index 0000000000..48a4d03e67 --- /dev/null +++ b/local-tests/setup/accs/accs.ts @@ -0,0 +1,21 @@ +import { LPACC_EVM_BASIC } from '@lit-protocol/accs-schemas'; + +export namespace AccessControlConditions { + export const getEmvBasicAccessControlConditions = ({ + userAddress, + }): LPACC_EVM_BASIC[] => { + return [ + { + contractAddress: '', + standardContractType: '', + chain: 'ethereum', + method: '', + parameters: [':userAddress'], + returnValueTest: { + comparator: '=', + value: userAddress, + }, + }, + ]; + }; +} diff --git a/local-tests/setup/networkContext.example.json b/local-tests/setup/networkContext.example.json new file mode 100644 index 0000000000..307fd9f508 --- /dev/null +++ b/local-tests/setup/networkContext.example.json @@ -0,0 +1,11268 @@ +{ + "Allowlist": { + "address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "ItemAllowed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "ItemNotAllowed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "addAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "allowAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "allowedItems", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "isAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "removeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_allowAll", + "type": "bool" + } + ], + "name": "setAllowAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "setAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "setNotAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "Allowlist" + }, + "LITToken": { + "address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidShortString", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "str", + "type": "string" + } + ], + "name": "StringTooLong", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "delegator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "fromDelegate", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "toDelegate", + "type": "address" + } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousBalance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBalance", + "type": "uint256" + } + ], + "name": "DelegateVotesChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CLOCK_MODE", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint32", + "name": "pos", + "type": "uint32" + } + ], + "name": "checkpoints", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "fromBlock", + "type": "uint32" + }, + { + "internalType": "uint224", + "name": "votes", + "type": "uint224" + } + ], + "internalType": "struct ERC20Votes.Checkpoint", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "clock", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + } + ], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "delegateBySig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "delegates", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "timepoint", + "type": "uint256" + } + ], + "name": "getPastTotalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timepoint", + "type": "uint256" + } + ], + "name": "getPastVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "numCheckpoints", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "LITToken" + }, + "Multisender": { + "address": "0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_recipients", + "type": "address[]" + } + ], + "name": "sendEth", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_recipients", + "type": "address[]" + }, + { + "internalType": "address", + "name": "tokenContract", + "type": "address" + } + ], + "name": "sendTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenContract", + "type": "address" + } + ], + "name": "withdrawTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "Multisender" + }, + "PKPHelper": { + "address": "0x21dF544947ba3E8b3c32561399E88B52Dc8b2823", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_resolver", + "type": "address" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "_env", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "internalType": "struct LibPKPNFTStorage.ClaimMaterial", + "name": "claimMaterial", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "permittedIpfsCIDs", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedIpfsCIDScopes", + "type": "uint256[][]" + }, + { + "internalType": "address[]", + "name": "permittedAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAddressScopes", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "internalType": "struct PKPHelper.AuthMethodData", + "name": "authMethodData", + "type": "tuple" + } + ], + "name": "claimAndMintNextAndAddAuthMethods", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "internalType": "struct LibPKPNFTStorage.ClaimMaterial", + "name": "claimMaterial", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "permittedIpfsCIDs", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedIpfsCIDScopes", + "type": "uint256[][]" + }, + { + "internalType": "address[]", + "name": "permittedAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAddressScopes", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "internalType": "struct PKPHelper.AuthMethodData", + "name": "authMethodData", + "type": "tuple" + } + ], + "name": "claimAndMintNextAndAddAuthMethodsWithTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "contract ContractResolver", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "env", + "outputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDomainWalletRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPKPNftMetdataAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpPermissionsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "name": "mintNextAndAddAuthMethods", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "permittedIpfsCIDs", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedIpfsCIDScopes", + "type": "uint256[][]" + }, + { + "internalType": "address[]", + "name": "permittedAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAddressScopes", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "name": "mintNextAndAddAuthMethodsWithTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "string[]", + "name": "nftMetadata", + "type": "string[]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "name": "mintNextAndAddDomainWalletMetadata", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "removePkpMetadata", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string[]", + "name": "nftMetadata", + "type": "string[]" + } + ], + "name": "setPkpMetadata", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "PKPHelper" + }, + "PKPNFT": { + "address": "0xf5059a5D33d5853360D16C683c16e67980206f36", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "FreeMintSignerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMintCost", + "type": "uint256" + } + ], + "name": "MintCostSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + } + ], + "name": "PKPMinted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrew", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "name": "claimAndMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "freeMintSigner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getEthAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNextDerivedKeyId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftMetadataAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpPermissionsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRouterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mintCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + } + ], + "name": "mintGrantAndBurnNext", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "name": "mintNext", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "prefixed", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "redeemedFreeMintIds", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "setFreeMintSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMintCost", + "type": "uint256" + } + ], + "name": "setMintCost", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "PKPNFT" + }, + "PKPNFTMetadata": { + "address": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_resolver", + "type": "address" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "_env", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "buffer", + "type": "bytes" + } + ], + "name": "bytesToHex", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "contract ContractResolver", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "env", + "outputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "removeProfileForPkp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "removeUrlForPKP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "imgUrl", + "type": "string" + } + ], + "name": "setProfileForPKP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "name": "setUrlForPKP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pubKey", + "type": "bytes" + }, + { + "internalType": "address", + "name": "ethAddress", + "type": "address" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "PKPNFTMetadata" + }, + "PKPPermissions": { + "address": "0x4C4a2f8c81640e47606d3fd77B353E87Ba015584", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "userPubkey", + "type": "bytes" + } + ], + "name": "PermittedAuthMethodAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "PermittedAuthMethodRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "PermittedAuthMethodScopeAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "PermittedAuthMethodScopeRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "root", + "type": "bytes32" + } + ], + "name": "RootHashUpdated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "scopes", + "type": "uint256[]" + } + ], + "name": "addPermittedAction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "scopes", + "type": "uint256[]" + } + ], + "name": "addPermittedAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "userPubkey", + "type": "bytes" + } + ], + "internalType": "struct LibPKPPermissionsStorage.AuthMethod", + "name": "authMethod", + "type": "tuple" + }, + { + "internalType": "uint256[]", + "name": "scopes", + "type": "uint256[]" + } + ], + "name": "addPermittedAuthMethod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "addPermittedAuthMethodScope", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypesToAdd", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIdsToAdd", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeysToAdd", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopesToAdd", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypesToRemove", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIdsToRemove", + "type": "bytes[]" + } + ], + "name": "batchAddRemoveAuthMethods", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "getAuthMethodId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getEthAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPermittedActions", + "outputs": [ + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPermittedAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "maxScopeId", + "type": "uint256" + } + ], + "name": "getPermittedAuthMethodScopes", + "outputs": [ + { + "internalType": "bool[]", + "name": "", + "type": "bool[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPermittedAuthMethods", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "userPubkey", + "type": "bytes" + } + ], + "internalType": "struct LibPKPPermissionsStorage.AuthMethod[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRouterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "getTokenIdsForAuthMethod", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "getUserPubkeyForAuthMethod", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + } + ], + "name": "isPermittedAction", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "isPermittedAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "isPermittedAuthMethod", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "isPermittedAuthMethodScopePresent", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + } + ], + "name": "removePermittedAction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "removePermittedAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "removePermittedAuthMethod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "removePermittedAuthMethodScope", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "root", + "type": "bytes32" + } + ], + "name": "setRootHash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "leaf", + "type": "bytes32" + } + ], + "name": "verifyState", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + }, + { + "internalType": "bool[]", + "name": "proofFlags", + "type": "bool[]" + }, + { + "internalType": "bytes32[]", + "name": "leaves", + "type": "bytes32[]" + } + ], + "name": "verifyStates", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "PKPPermissions" + }, + "PubkeyRouter": { + "address": "0x1291Be112d480055DaFd8a610b7d1e203891C274", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "PubkeyRoutingDataSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct IPubkeyRouter.RootKey", + "name": "rootKey", + "type": "tuple" + } + ], + "name": "RootKeySet", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + } + ], + "name": "adminResetRootKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "signedMessage", + "type": "bytes" + }, + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + } + ], + "name": "checkNodeSignatures", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + } + ], + "name": "deriveEthAddressFromPubkey", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "ethAddress", + "type": "address" + } + ], + "name": "ethAddressToPkpId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "getDerivedPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getEthAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + } + ], + "name": "getRootKeys", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "internalType": "struct IPubkeyRouter.RootKey[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getRoutingData", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "internalType": "struct LibPubkeyRouterStorage.PubkeyRoutingData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "isRouted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "pubkeys", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "internalType": "struct LibPubkeyRouterStorage.PubkeyRoutingData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "setRoutingData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "setRoutingDataAsAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "internalType": "struct IPubkeyRouter.RootKey[]", + "name": "newRootKeys", + "type": "tuple[]" + } + ], + "name": "voteForRootKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "PubkeyRouter" + }, + "RateLimitNFT": { + "address": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newAdditionalRequestsPerKilosecondCost", + "type": "uint256" + } + ], + "name": "AdditionalRequestsPerKilosecondCostSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "FreeMintSignerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newFreeRequestsPerRateLimitWindow", + "type": "uint256" + } + ], + "name": "FreeRequestsPerRateLimitWindowSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newRLIHolderRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "RLIHolderRateLimitWindowSecondsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "RateLimitWindowSecondsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrew", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sVal", + "type": "bytes32" + } + ], + "name": "freeMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newAdditionalRequestsPerKilosecondCost", + "type": "uint256" + } + ], + "name": "setAdditionalRequestsPerKilosecondCost", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "setFreeMintSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newFreeRequestsPerRateLimitWindow", + "type": "uint256" + } + ], + "name": "setFreeRequestsPerRateLimitWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaxExpirationSeconds", + "type": "uint256" + } + ], + "name": "setMaxExpirationSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaxRequestsPerKilosecond", + "type": "uint256" + } + ], + "name": "setMaxRequestsPerKilosecond", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newRLIHolderRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "setRLIHolderRateLimitWindowSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "setRateLimitWindowSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "RLIHolderRateLimitWindowSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "additionalRequestsPerKilosecondCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "calculateCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "payingAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "calculateRequestsPerKilosecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "capacity", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "internalType": "struct LibRateLimitNFTStorage.RateLimit", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestedRequestsPerKilosecond", + "type": "uint256" + } + ], + "name": "checkBelowMaxRequestsPerKilosecond", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentSoldRequestsPerKilosecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultRateLimitWindowSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sVal", + "type": "bytes32" + } + ], + "name": "freeMintSigTest", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "freeMintSigner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "freeRequestsPerRateLimitWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "isExpired", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxExpirationSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxRequestsPerKilosecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "prefixed", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "redeemedFreeMints", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokenIdCounter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenSVG", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "totalSoldRequestsPerKilosecondByExpirationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "RateLimitNFT" + }, + "Staking": { + "address": "0xc5a5C42992dECbae36851359345FE25997F5C42d", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "ActiveValidatorsCannotLeave", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "CannotKickBelowCurrentValidatorThreshold", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingAddress", + "type": "address" + } + ], + "name": "CannotRejoinUntilNextEpochBecauseKicked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "CannotReuseCommsKeys", + "type": "error" + }, + { + "inputs": [], + "name": "CannotStakeZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "CannotVoteTwice", + "type": "error" + }, + { + "inputs": [], + "name": "CannotWithdrawZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + } + ], + "name": "CouldNotMapNodeAddressToStakerAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInActiveOrUnlockedOrPausedState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInActiveOrUnlockedState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInNextValidatorSetLockedOrReadyForNextEpochOrRestoreState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInNextValidatorSetLockedOrReadyForNextEpochState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInNextValidatorSetLockedState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInReadyForNextEpochState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "MustBeValidatorInNextEpochToKick", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epochEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeout", + "type": "uint256" + } + ], + "name": "NotEnoughTimeElapsedForTimeoutSinceLastEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epochEndTime", + "type": "uint256" + } + ], + "name": "NotEnoughTimeElapsedSinceLastEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "validatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCount", + "type": "uint256" + } + ], + "name": "NotEnoughValidatorsInNextEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentReadyValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nextReadyValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCountToBeReady", + "type": "uint256" + } + ], + "name": "NotEnoughValidatorsReadyForNextEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentEpochNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receivedEpochNumber", + "type": "uint256" + } + ], + "name": "SignaledReadyForWrongEpochNumber", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "StakerNotPermitted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "yourBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestedWithdrawlAmount", + "type": "uint256" + } + ], + "name": "TryingToWithdrawMoreThanStaked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "internalType": "address[]", + "name": "validatorsInNextEpoch", + "type": "address[]" + } + ], + "name": "ValidatorIsNotInNextEpoch", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newTokenRewardPerTokenPerEpoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newComplaintTolerance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newComplaintIntervalSecs", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "newKeyTypes", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinimumValidatorCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxConcurrentRequests", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxTripleCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinTripleCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeerCheckingIntervalSecs", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxTripleConcurrency", + "type": "uint256" + } + ], + "name": "ConfigSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newEpochEndTime", + "type": "uint256" + } + ], + "name": "EpochEndTimeSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newEpochLength", + "type": "uint256" + } + ], + "name": "EpochLengthSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newEpochTimeout", + "type": "uint256" + } + ], + "name": "EpochTimeoutSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newKickPenaltyPercent", + "type": "uint256" + } + ], + "name": "KickPenaltyPercentSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "epochNumber", + "type": "uint256" + } + ], + "name": "ReadyForNextEpoch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Recovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "RequestToJoin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "RequestToLeave", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverContractAddress", + "type": "address" + } + ], + "name": "ResolverContractAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newDuration", + "type": "uint256" + } + ], + "name": "RewardsDurationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newStakingTokenAddress", + "type": "address" + } + ], + "name": "StakingTokenSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum LibStakingStorage.States", + "name": "newState", + "type": "uint8" + } + ], + "name": "StateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountBurned", + "type": "uint256" + } + ], + "name": "ValidatorKickedFromNextEpoch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "ValidatorRejoinedNextEpoch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "VotedToKickValidatorInNextEpoch", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + } + ], + "name": "adminKickValidatorInNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "adminRejoinValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "adminResetEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountToPenalize", + "type": "uint256" + } + ], + "name": "adminSlashValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "advanceEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "exit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "kickValidatorInNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lockValidatorsForNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "requestToJoin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "requestToLeave", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "requestToLeaveAsNode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newTokenRewardPerTokenPerEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newComplaintTolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newComplaintIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "newKeyTypes", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "newMinimumValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newMaxConcurrentRequests", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newMaxTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newMinTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newPeerCheckingIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newMaxTripleConcurrency", + "type": "uint256" + } + ], + "name": "setConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newEpochEndTime", + "type": "uint256" + } + ], + "name": "setEpochEndTime", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newEpochLength", + "type": "uint256" + } + ], + "name": "setEpochLength", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "newState", + "type": "uint8" + } + ], + "name": "setEpochState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newEpochTimeout", + "type": "uint256" + } + ], + "name": "setEpochTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "setIpPortNodeAddressAndCommunicationPubKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newKickPenaltyPercent", + "type": "uint256" + } + ], + "name": "setKickPenaltyPercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epochNumber", + "type": "uint256" + } + ], + "name": "signalReadyForNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "stakeAndJoin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "VersionRequirementsUpdated", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "checkVersion", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxVersion", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxVersionString", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMinVersion", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMinVersionString", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "setMaxVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "setMinVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "config", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenRewardPerTokenPerEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "complaintTolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "complaintIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "keyTypes", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxConcurrentRequests", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "peerCheckingIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTripleConcurrency", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Config", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "countOfCurrentValidatorsReadyForNextEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "countOfNextValidatorsReadyForNextEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentValidatorCountForConsensus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "epoch", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "epochLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "retries", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeout", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Epoch", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getKeyTypes", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getKickedValidators", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "name": "getNodeStakerAddressMappings", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "internalType": "struct LibStakingStorage.AddressMapping[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStakingBalancesAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsInCurrentEpoch", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsInCurrentEpochLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsInNextEpoch", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "name": "getValidatorsStructs", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsStructsInCurrentEpoch", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsStructsInNextEpoch", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epochNumber", + "type": "uint256" + }, + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "voterStakerAddress", + "type": "address" + } + ], + "name": "getVotingStatusToKickValidator", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isActiveValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isActiveValidatorByNodeAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isReadyForNextEpoch", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + } + ], + "name": "kickPenaltyPercentByReason", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextValidatorCountForConsensus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + } + ], + "name": "nodeAddressToStakerAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "readyForNextEpoch", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "shouldKickValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "state", + "outputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "validators", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "Staking" + }, + "StakingBalances": { + "address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "ActiveValidatorsCannotLeave", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "AliasNotOwnedBySender", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "CannotRemoveAliasOfActiveValidator", + "type": "error" + }, + { + "inputs": [], + "name": "CannotStakeZero", + "type": "error" + }, + { + "inputs": [], + "name": "CannotWithdrawZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "aliasCount", + "type": "uint256" + } + ], + "name": "MaxAliasCountReached", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "OnlyStakingContract", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountStaked", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + } + ], + "name": "StakeMustBeGreaterThanMinimumStake", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountStaked", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maximumStake", + "type": "uint256" + } + ], + "name": "StakeMustBeLessThanMaximumStake", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "StakerNotPermitted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "yourBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestedWithdrawlAmount", + "type": "uint256" + } + ], + "name": "TryingToWithdrawMoreThanStaked", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "AliasAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "AliasRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxAliasCount", + "type": "uint256" + } + ], + "name": "MaxAliasCountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMaximumStake", + "type": "uint256" + } + ], + "name": "MaximumStakeSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMinimumStake", + "type": "uint256" + } + ], + "name": "MinimumStakeSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "PermittedStakerAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "PermittedStakerRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "permittedStakersOn", + "type": "bool" + } + ], + "name": "PermittedStakersOnChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ResolverContractAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newTokenRewardPerTokenPerEpoch", + "type": "uint256" + } + ], + "name": "TokenRewardPerTokenPerEpochSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "ValidatorNotRewardedBecauseAlias", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRewarded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorTokensPenalized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "addAlias", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "addPermittedStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "stakers", + "type": "address[]" + } + ], + "name": "addPermittedStakers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "checkStakingAmounts", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "isPermittedStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maximumStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minimumStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "penalizeTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "permittedStakersOn", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "removeAlias", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "removePermittedStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "restakePenaltyTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "rewardOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "rewardValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaxAliasCount", + "type": "uint256" + } + ], + "name": "setMaxAliasCount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaximumStake", + "type": "uint256" + } + ], + "name": "setMaximumStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMinimumStake", + "type": "uint256" + } + ], + "name": "setMinimumStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "permitted", + "type": "bool" + } + ], + "name": "setPermittedStakersOn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalStaked", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "transferPenaltyTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "withdrawPenaltyTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "StakingBalances" + }, + "ContractResolver": { + "address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "abi": [ + { + "inputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AdminRoleRequired", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "AllowedEnvAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "AllowedEnvRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "typ", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "SetContract", + "type": "event" + }, + { + "inputs": [], + "name": "ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ALLOWLIST_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BACKUP_RECOVERY_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_WALLET_REGISTRY", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "HD_KEY_DERIVER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "LIT_TOKEN_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MULTI_SENDER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAYMENT_DELEGATION_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_HELPER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_NFT_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_NFT_METADATA_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_PERMISSIONS_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PUB_KEY_ROUTER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RATE_LIMIT_NFT_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELEASE_REGISTER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKING_BALANCES_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKING_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "addAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "addAllowedEnv", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "typ", + "type": "bytes32" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "getContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adminBeingRemoved", + "type": "address" + } + ], + "name": "removeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "removeAllowedEnv", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "typ", + "type": "bytes32" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + }, + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "setContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "", + "type": "uint8" + } + ], + "name": "typeAddresses", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "ContractResolver" + } +} diff --git a/local-tests/setup/session-sigs/get-eoa-session-sigs.ts b/local-tests/setup/session-sigs/get-eoa-session-sigs.ts new file mode 100644 index 0000000000..057eed415b --- /dev/null +++ b/local-tests/setup/session-sigs/get-eoa-session-sigs.ts @@ -0,0 +1,156 @@ +import { + LitActionResource, + LitPKPResource, + craftAuthSig, + createSiweMessageWithRecaps, +} from '@lit-protocol/auth-helpers'; +import { + AuthCallbackParams, + AuthSig, + LitAbility, + LitResourceAbilityRequest, +} from '@lit-protocol/types'; +import { log } from '@lit-protocol/misc'; +import { ethers } from 'ethers'; +import { LitNetwork } from '@lit-protocol/constants'; +import { TinnyPerson } from '../tinny-person'; +import { TinnyEnvironment } from '../tinny-environment'; + +/** + * Retrieves the session signatures for an EOA in a given Tinny environment. + * + * @param devEnv - The Tinny environment object. + * @param person - The Tinny person object representing the EOA. + * @param resourceAbilityRequests - Optional. An array of resource ability requests. If not provided, default requests will be used. + * @returns A promise that resolves to the session signatures. + */ +export const getEoaSessionSigs = async ( + devEnv: TinnyEnvironment, + person: TinnyPerson, + resourceAbilityRequests?: LitResourceAbilityRequest[] +) => { + if (devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano) { + console.warn( + 'Manzano network detected. Adding capacityDelegationAuthSig to eoaSessionSigs' + ); + } + + // Use default resourceAbilityRequests if not provided + const _resourceAbilityRequests = resourceAbilityRequests || [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]; + + const sessionSigs = await devEnv.litNodeClient.getSessionSigs({ + chain: 'ethereum', + resourceAbilityRequests: _resourceAbilityRequests, + authNeededCallback: async ({ + uri, + expiration, + resourceAbilityRequests, + }: AuthCallbackParams) => { + console.log('resourceAbilityRequests:', resourceAbilityRequests); + + if (!expiration) { + throw new Error('expiration is required'); + } + + if (!resourceAbilityRequests) { + throw new Error('resourceAbilityRequests is required'); + } + + if (!uri) { + throw new Error('uri is required'); + } + + const toSign = await createSiweMessageWithRecaps({ + uri: uri, + expiration: expiration, + resources: resourceAbilityRequests, + walletAddress: person.wallet.address, + nonce: await devEnv.litNodeClient.getLatestBlockhash(), + litNodeClient: devEnv.litNodeClient, + }); + + const authSig = await craftAuthSig({ + signer: person.wallet, + toSign, + }); + + return authSig; + }, + + // -- only add this for manzano network because of rate limiting + ...(devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano + ? { capabilityAuthSigs: [devEnv.superCapacityDelegationAuthSig] } + : {}), + }); + + log('[getEoaSessionSigs]: ', getEoaSessionSigs); + + return sessionSigs; +}; + +export const getEoaSessionSigsWithCapacityDelegations = async ( + devEnv: TinnyEnvironment, + fromWallet: ethers.Wallet, + capacityDelegationAuthSig: AuthSig +) => { + const sessionSigs = await devEnv.litNodeClient.getSessionSigs({ + chain: 'ethereum', + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ], + authNeededCallback: async ({ + uri, + expiration, + resourceAbilityRequests, + }: AuthCallbackParams) => { + if (!expiration) { + throw new Error('expiration is required'); + } + + if (!resourceAbilityRequests) { + throw new Error('resourceAbilityRequests is required'); + } + + if (!uri) { + throw new Error('uri is required'); + } + + const toSign = await createSiweMessageWithRecaps({ + uri: uri, + expiration: expiration, + resources: resourceAbilityRequests, + walletAddress: fromWallet.address, + nonce: await devEnv.litNodeClient.getLatestBlockhash(), + litNodeClient: devEnv.litNodeClient, + }); + + const authSig = await craftAuthSig({ + signer: fromWallet, + toSign, + }); + + return authSig; + }, + capacityDelegationAuthSig: capacityDelegationAuthSig, + }); + + log('[getEoaSessionSigs]: ', getEoaSessionSigs); + + return sessionSigs; +}; diff --git a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts new file mode 100644 index 0000000000..1ccca73331 --- /dev/null +++ b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts @@ -0,0 +1,91 @@ +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LitAbility, LitResourceAbilityRequest } from '@lit-protocol/types'; +import { LitNetwork } from '@lit-protocol/constants'; +import { TinnyPerson } from '../tinny-person'; +import { TinnyEnvironment } from '../tinny-environment'; + +const VALID_SESSION_SIG_LIT_ACTION_CODE = ` +// Works with an AuthSig AuthMethod +if (Lit.Auth.authMethodContexts.some(e => e.authMethodType === 1)) { + LitActions.setResponse({ response: "true" }); +} else { + LitActions.setResponse({ response: "false" }); +} +`; + +const INVALID_SESSION_SIG_LIT_ACTION_CODE = ` +(async () => { + let utf8Encode = new TextEncoder(); + const toSign = utf8Encode.encode('This message is exactly 32 bytes'); + const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName }); +})(); +`; + +export const getLitActionSessionSigs = async ( + devEnv: TinnyEnvironment, + alice: TinnyPerson, + resourceAbilityRequests?: LitResourceAbilityRequest[] +) => { + if (devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano) { + console.warn( + 'Manzano network detected. Adding capacityDelegationAuthSig to litActionSessionSigs' + ); + } + + // Use default resourceAbilityRequests if not provided + const _resourceAbilityRequests = resourceAbilityRequests || [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]; + + const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: alice.authMethodOwnedPkp.publicKey, + authMethods: [alice.authMethod], + resourceAbilityRequests: _resourceAbilityRequests, + litActionCode: Buffer.from(VALID_SESSION_SIG_LIT_ACTION_CODE).toString( + 'base64' + ), + jsParams: { + publicKey: alice.authMethodOwnedPkp.publicKey, + sigName: 'unified-auth-sig', + }, + + // -- only add this for manzano network + ...(devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano + ? { capacityDelegationAuthSig: devEnv.superCapacityDelegationAuthSig } + : {}), + }); + + return litActionSessionSigs; +}; + +export const getInvalidLitActionSessionSigs = async ( + devEnv: TinnyEnvironment, + alice: TinnyPerson +) => { + const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: alice.authMethodOwnedPkp.publicKey, + authMethods: [alice.authMethod], + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + ], + litActionCode: Buffer.from(INVALID_SESSION_SIG_LIT_ACTION_CODE).toString( + 'base64' + ), + jsParams: { + publicKey: alice.authMethodOwnedPkp.publicKey, + sigName: 'unified-auth-sig', + }, + }); + + return litActionSessionSigs; +}; diff --git a/local-tests/setup/session-sigs/get-pkp-session-sigs.ts b/local-tests/setup/session-sigs/get-pkp-session-sigs.ts new file mode 100644 index 0000000000..fb5d75a7e1 --- /dev/null +++ b/local-tests/setup/session-sigs/get-pkp-session-sigs.ts @@ -0,0 +1,45 @@ +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LitAbility, LitResourceAbilityRequest } from '@lit-protocol/types'; +import { log } from '@lit-protocol/misc'; +import { LitNetwork } from '@lit-protocol/constants'; +import { TinnyEnvironment } from '../tinny-environment'; +import { TinnyPerson } from '../tinny-person'; + +export const getPkpSessionSigs = async ( + devEnv: TinnyEnvironment, + alice: TinnyPerson, + resourceAbilityRequests?: LitResourceAbilityRequest[] +) => { + if (devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano) { + console.warn( + 'Manzano network detected. Adding capacityDelegationAuthSig to pkpSessionSigs' + ); + } + + // Use default resourceAbilityRequests if not provided + const _resourceAbilityRequests = resourceAbilityRequests || [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]; + + const pkpSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: alice.authMethodOwnedPkp.publicKey, + authMethods: [alice.authMethod], + resourceAbilityRequests: _resourceAbilityRequests, + + // -- only add this for manzano network + ...(devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano + ? { capacityDelegationAuthSig: devEnv.superCapacityDelegationAuthSig } + : {}), + }); + + log('[getPkpSessionSigs]: ', pkpSessionSigs); + + return pkpSessionSigs; +}; diff --git a/local-tests/setup/tinny-config.ts b/local-tests/setup/tinny-config.ts new file mode 100644 index 0000000000..a4d53754dd --- /dev/null +++ b/local-tests/setup/tinny-config.ts @@ -0,0 +1,145 @@ +import { LitNodeClient } from '@lit-protocol/lit-node-client'; + +export enum LIT_TESTNET { + LOCALCHAIN = 'localchain', + MANZANO = 'manzano', + CAYENNE = 'cayenne', +} + +export interface ProcessEnvs { + /** + * Each test is executed in a loop with a maximum number of attempts specified by `devEnv.processEnvs.MAX_ATTEMPTS`. + */ + MAX_ATTEMPTS: number; + + /** + * The network to use for testing. This can be one of the following: + * - `LIT_TESTNET.LOCALCHAIN` + * - `LIT_TESTNET.MANZANO` + * - `LIT_TESTNET.CAYENNE` + */ + NETWORK: LIT_TESTNET; + + /** + * The number of milliseconds to wait between each request. + */ + DEBUG: boolean; + + /** + * Capacity Credits: In order to execute a transaction with Lit, you’ll need to reserve capacity on the network using Capacity Credits. These allow holders to reserve a set number of requests over a desired period of time (by default expiration set to 2 days) + */ + REQUEST_PER_KILOSECOND: number; + + /** + * Wait time in milliseconds if no private keys are available. + */ + WAIT_FOR_KEY_INTERVAL: number; + + /** + * Time to wait before releasing the key after requesting it. + */ + TIME_TO_RELEASE_KEY: number; + + /** + * Run all the tests in a single thread. + */ + RUN_IN_BAND: boolean; + + /** + * The interval in milliseconds to run the tests in a single thread. + */ + RUN_IN_BAND_INTERVAL: number; + + // =========== In most cases you won't need to change the following values =========== + /** + * The URL of Lit RPC server. If it's running locally on Anvil, it should be 'http://127.0.0.1:8545' + */ + LIT_RPC_URL: string; + + /** + * The URL of the official Lit RPC server. Usually 'https://chain-rpc.litprotocol.com/http' but can be changed if needed + */ + LIT_OFFICIAL_RPC: string; + + /** + * This is usually used when you're running tests locally depending how many nodes you are running. + */ + BOOTSTRAP_URLS: string[]; + + /** + * The list of private keys to use for testing. + */ + PRIVATE_KEYS: string[]; + + /** + * The list of keys that are currently in use. + */ + KEY_IN_USE: boolean[]; +} + +/** + * Represents the PKP information. + */ +export type PKPInfo = { + tokenId: string; + publicKey: string; + ethAddress: string; +}; + +export interface TinnyEnvConfig { + rpc: string; + litNodeClient: LitNodeClient; + network: LIT_TESTNET; + processEnvs: ProcessEnvs; +} + +export enum LIT_ENDPOINT_VERSION { + LEGACY = '/', + V1 = '/v1', +} + +export const LIT_ENDPOINT = { + HANDSHAKE: { + path: '/web/handshake', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'HANDSHAKE', + }, + SIGN_SESSION_KEY: { + path: '/web/sign_session_key', + // version: LIT_ENDPOINT_VERSION.V1, + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'SIGN_SESSION_KEY', + }, + EXECUTE_JS: { + path: '/web/execute', + // version: LIT_ENDPOINT_VERSION.V1, + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'EXECUTE_JS', + }, + PKP_SIGN: { + path: '/web/pkp/sign', + // version: LIT_ENDPOINT_VERSION.V1, + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'PKP_SIGN', + }, + PKP_CLAIM: { + path: '/web/pkp/claim', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'PKP_CLAIM', + }, + SIGN_ACCS: { + path: '/web/signing/access_control_condition', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'SIGN_ACCS', + }, + ENCRYPTION_SIGN: { + path: '/web/encryption/sign', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'ENCRYPTION_SIGN', + }, + SIGN_ECDSA: { + path: '/web/signing/signConditionEcdsa', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'SIGN_ECDSA', + }, +}; diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts new file mode 100644 index 0000000000..c33c098667 --- /dev/null +++ b/local-tests/setup/tinny-environment.ts @@ -0,0 +1,371 @@ +import { + LIT_ENDPOINT, + LIT_ENDPOINT_VERSION, + LIT_TESTNET, + ProcessEnvs, + TinnyEnvConfig, +} from './tinny-config'; +import { LitNodeClient } from '@lit-protocol/lit-node-client'; +import { LitContracts } from '@lit-protocol/contracts-sdk'; +import { AuthSig, LitContractContext } from '@lit-protocol/types'; +import { TinnyPerson } from './tinny-person'; +import networkContext from './networkContext.json'; +import { ethers } from 'ethers'; + +export class TinnyEnvironment { + public network: LIT_TESTNET; + + /** + * Environment variables used in the process. + */ + public processEnvs: ProcessEnvs = { + MAX_ATTEMPTS: parseInt(process.env['MAX_ATTEMPTS']) || 3, + NETWORK: (process.env['NETWORK'] as LIT_TESTNET) || LIT_TESTNET.LOCALCHAIN, + DEBUG: Boolean(process.env['DEBUG']) || false, + REQUEST_PER_KILOSECOND: + parseInt(process.env['REQUEST_PER_KILOSECOND']) || 200, + LIT_RPC_URL: process.env['LIT_RPC_URL'] || 'http://127.0.0.1:8545', + WAIT_FOR_KEY_INTERVAL: + parseInt(process.env['WAIT_FOR_KEY_INTERVAL']) || 3000, + BOOTSTRAP_URLS: process.env['BOOTSTRAP_URLS']?.split(',') || [ + 'http://127.0.0.1:7470', + 'http://127.0.0.1:7471', + 'http://127.0.0.1:7472', + ], + LIT_OFFICIAL_RPC: + process.env['LIT_OFFICIAL_RPC'] || + 'https://chain-rpc.litprotocol.com/http', + TIME_TO_RELEASE_KEY: parseInt(process.env['TIME_TO_RELEASE_KEY']) || 10000, + RUN_IN_BAND: Boolean(process.env['RUN_IN_BAND']) || false, + RUN_IN_BAND_INTERVAL: parseInt(process.env['RUN_IN_BAND_INTERVAL']) || 5000, + + // Available Accounts + // ================== + + // (0) "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" (10000.000000000000000000 ETH) + // (1) "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (10000.000000000000000000 ETH) + // (2) "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" (10000.000000000000000000 ETH) + // (3) "0x90F79bf6EB2c4f870365E785982E1f101E93b906" (10000.000000000000000000 ETH) + // (4) "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" (10000.000000000000000000 ETH) + // (5) "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" (10000.000000000000000000 ETH) + // (6) "0x976EA74026E726554dB657fA54763abd0C3a0aa9" (10000.000000000000000000 ETH) + // (7) "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955" (10000.000000000000000000 ETH) + // (8) "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f" (10000.000000000000000000 ETH) + // (9) "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" (10000.000000000000000000 ETH) + PRIVATE_KEYS: process.env['PRIVATE_KEYS']?.split(',') || [ + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', + '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', + '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', + '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', + '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a', + '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba', + '0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e', + '0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356', + '0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97', + '0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6', + ], + KEY_IN_USE: new Array(), + }; + + public litNodeClient: LitNodeClient; + public contractsClient: LitContracts; + public rpc: string; + public superCapacityDelegationAuthSig: AuthSig; + + constructor(network?: LIT_TESTNET) { + // -- setup networkj + this.network = network || this.processEnvs.NETWORK; + + if (Object.values(LIT_TESTNET).indexOf(this.network) === -1) { + throw new Error( + `Invalid network environment. Please use one of ${Object.values( + LIT_TESTNET + )}` + ); + } + + // -- create an empty array to keep track of all keys + this.processEnvs.KEY_IN_USE = new Array( + this.processEnvs.PRIVATE_KEYS.length + ).fill(false); + + // -- setup rpc + if (this.network === LIT_TESTNET.LOCALCHAIN) { + this.rpc = this.processEnvs.LIT_RPC_URL; + } else { + this.rpc = this.processEnvs.LIT_OFFICIAL_RPC; + } + } + + world: Map = new Map(); + + /** + * Retrieves an available private key from a list, marking it as in use and scheduling + * its automatic release. If no unused keys are available, it waits for a set interval + * before rechecking. + * + * This function loops until it finds an unused key, marks it, and returns the key with + * its index. If all keys are in use, it logs a wait message and pauses before retrying. + * + * Outputs: + * - privateKey: The selected private key. + * - index: The index of the selected key. + * + * Environment variables required: + * - KEY_IN_USE: Boolean array indicating key usage. + * - PRIVATE_KEYS: Array of key strings. + * - TIME_TO_RELEASE_KEY: Milliseconds until a key is automatically released. + * - WAIT_FOR_KEY_INTERVAL: Wait time in milliseconds if no keys are free. + */ + async getAvailablePrivateKey(): Promise<{ + privateKey: string; + index: number; + }> { + while (true) { + const index = this.processEnvs.KEY_IN_USE.findIndex((used) => !used); // Find the first unused key + + if (index !== -1) { + // If an available key is found + this.processEnvs.KEY_IN_USE[index] = true; // Mark the key as in use + console.log('[𐬺🧪 Tinny Environment𐬺] 🔑 Selected key at index', index); // Log a message indicating that we have selected a key + + // Set a timer to automatically release the key after 10 seconds + setTimeout(() => { + this.releasePrivateKey(index); + console.log( + '[𐬺🧪 Tinny Environment𐬺] 🔓 Automatically released key at index', + index, + `after ${this.processEnvs.TIME_TO_RELEASE_KEY / 10000} seconds` + ); + }, this.processEnvs.TIME_TO_RELEASE_KEY); + + return { privateKey: this.processEnvs.PRIVATE_KEYS[index], index }; // Return the key and its index + } else { + console.log('[𐬺🧪 Tinny Environment𐬺] No available keys. Waiting...'); // Log a message indicating that we are waiting + // Wait for the specified interval before checking again + await new Promise((resolve) => + setTimeout(resolve, this.processEnvs.WAIT_FOR_KEY_INTERVAL) + ); + } + } + } + + /** + * Marks a private key as available again after use. + * @param {number} index - The index of the key to mark as available. + */ + releasePrivateKey(index: number) { + this.processEnvs.KEY_IN_USE[index] = false; + console.log( + `[𐬺🧪 Tinny Environment𐬺] 🪽 Released key at index ${index}. Thank you for your service!` + ); + } + + /** + * Initializes the LitNodeClient based on the specified network configuration and environment variables. + * This setup differentiates between local and production environments, adjusts node attestation checks, + * and sets network-specific parameters. The function ensures the client is connected and ready before proceeding. + * + * The LitNodeClient is configured differently based on the network: + * - LOCALCHAIN: Uses custom settings for local testing, with node attestation disabled. + * - MANZANO (or other specified testnets): Configures for specific network environments with node attestation enabled. + * + * Logs the process and exits if the client is not ready after attempting to connect. + */ + + async setupLitNodeClient() { + console.log('[𐬺🧪 Tinny Environment𐬺] Setting up LitNodeClient'); + + if (this.network === LIT_TESTNET.LOCALCHAIN) { + this.litNodeClient = new LitNodeClient({ + litNetwork: 'custom', + bootstrapUrls: this.processEnvs.BOOTSTRAP_URLS, + rpcUrl: this.processEnvs.LIT_RPC_URL, + debug: this.processEnvs.DEBUG, + checkNodeAttestation: false, // disable node attestation check for local testing + contractContext: networkContext as LitContractContext, + }); + } else if (this.network === LIT_TESTNET.MANZANO) { + this.litNodeClient = new LitNodeClient({ + litNetwork: this.network, // 'habanero' or 'manzano' + checkNodeAttestation: true, + debug: this.processEnvs.DEBUG, + }); + } else { + this.litNodeClient = new LitNodeClient({ + litNetwork: this.network, + checkNodeAttestation: false, + debug: this.processEnvs.DEBUG, + }); + } + + await this.litNodeClient.connect(); + + if (!this.litNodeClient.ready) { + console.error('❌ litNodeClient not ready'); + process.exit(); + } + } + + /** + * Retrieves the environment configuration. + * @returns The TinnyEnvConfig object containing the environment configuration. + */ + getEnvConfig(): TinnyEnvConfig { + return { + rpc: this.rpc, + litNodeClient: this.litNodeClient, + network: this.network, + processEnvs: this.processEnvs, + }; + } + + /** + * Creates a new person with the given name. + * @param name - The name of the person. + * @returns The newly created person. + * @throws Error if the name is not provided. + */ + async createNewPerson(name: string) { + console.log('[𐬺🧪 Tinny Environment𐬺] Creating new person:', name); + if (!name) { + throw new Error('Name is required'); + } + const key = await this.getAvailablePrivateKey(); + const privateKey = key.privateKey; + const envConfig = this.getEnvConfig(); + + console.log( + '[𐬺🧪 Tinny Environment𐬺] Creating new person with private key:', + JSON.stringify(key) + ); + console.log( + '[𐬺🧪 Tinny Environment𐬺] Creating new person with envConfig:', + envConfig + ); + + const person = new TinnyPerson({ + privateKey, + envConfig, + }); + + await person.spawn(); + + this.world.set(name, person); + + return person; + } + + /** + * Retrieves a person from the world by their name. + * @param name - The name of the person to retrieve. + * @returns The person object if found, or undefined if not found. + */ + getPerson(name: string) { + return this.world.get(name); + } + + /** + * Creates a random person. + * @returns A promise that resolves to the created person. + */ + async createRandomPerson() { + return await this.createNewPerson('Alice'); + } + + /** + * Sets the global execute JS version for a specific network. + * @param network - The network for which to set the execute JS version. + * @param version - The execute JS version to set. + */ + setGlobalExecuteJsVersion = ( + network: LIT_TESTNET, + version: LIT_ENDPOINT_VERSION + ) => { + if (this.processEnvs.NETWORK === network) { + process.env[LIT_ENDPOINT.EXECUTE_JS.envName] = version; + } + }; + + /** + * Sets the global PKP sign version for the specified network. + * @param network - The network for which to set the PKP sign version. + * @param version - The PKP sign version to set. + */ + setGlobalPkpSignVersion = ( + network: LIT_TESTNET, + version: LIT_ENDPOINT_VERSION + ) => { + if (this.processEnvs.NETWORK === network) { + process.env[LIT_ENDPOINT.PKP_SIGN.envName] = version; + } + }; + + setUnavailable = (network: LIT_TESTNET) => { + if (this.processEnvs.NETWORK === network) { + throw new Error('LIT_IGNORE_TEST'); + } + }; + + /** + * Init + */ + async init() { + await this.setupLitNodeClient(); + await this.setupSuperCapacityDelegationAuthSig(); + } + + /** + * Context: the reason this is created instead of individually is because we can't allocate capacity beyond the global + * max capacity. + */ + setupSuperCapacityDelegationAuthSig = async () => { + const privateKey = await this.getAvailablePrivateKey(); + const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc); + const wallet = new ethers.Wallet(privateKey.privateKey, provider); + + /** + * ==================================== + * Setup contracts-sdk client + * ==================================== + */ + if (this.network === LIT_TESTNET.LOCALCHAIN) { + this.contractsClient = new LitContracts({ + signer: wallet, + debug: this.processEnvs.DEBUG, + rpc: this.processEnvs.LIT_RPC_URL, // anvil rpc + customContext: networkContext as unknown as LitContractContext, + }); + } else { + this.contractsClient = new LitContracts({ + signer: wallet, + debug: this.processEnvs.DEBUG, + network: this.network, + }); + } + + await this.contractsClient.connect(); + + /** + * ==================================== + * Mint a Capacity Credits NFT and get a capacity delegation authSig with it + * ==================================== + */ + console.log( + '[𐬺🧪 Tinny Environment𐬺] Mint a Capacity Credits NFT and get a capacity delegation authSig with it' + ); + const capacityTokenId = ( + await this.contractsClient.mintCapacityCreditsNFT({ + requestsPerKilosecond: this.processEnvs.REQUEST_PER_KILOSECOND, + daysUntilUTCMidnightExpiration: 2, + }) + ).capacityTokenIdStr; + + this.superCapacityDelegationAuthSig = ( + await this.litNodeClient.createCapacityDelegationAuthSig({ + dAppOwnerWallet: wallet, + capacityTokenId: capacityTokenId, + }) + ).capacityDelegationAuthSig; + }; +} diff --git a/local-tests/setup/tinny-operations.ts b/local-tests/setup/tinny-operations.ts new file mode 100644 index 0000000000..6bd14ab41b --- /dev/null +++ b/local-tests/setup/tinny-operations.ts @@ -0,0 +1,209 @@ +import { TinnyEnvironment } from './tinny-environment'; + +/** + * Retrieves filter flags from the command line arguments to determine which tests to run. + * It parses the process arguments to find flags that specify filters, typically used to limit test execution to specific tests. + * + * @returns {string[]} An array of filter strings extracted from the command line arguments. + * + * @example + * // Assume the command line is: node script.js --filter=test1,test2 + */ +export const getFiltersFlag = (): string[] => { + const filterArg = process.argv.find((arg) => arg.startsWith('--filter=')); + return filterArg ? filterArg.replace('--filter=', '').split(',') : []; +}; + +/** + * Runs the tests in the provided `tests` object in a synchronous manner. + * Each test is executed in a loop with a maximum number of attempts specified by `devEnv.processEnvs.MAX_ATTEMPTS`. + * Skipped, failed, and passed tests are tracked and logged. + * At the end, a test report is printed with the number of passed, failed, and skipped tests. + * If any test fails, the process exits with an error code. Otherwise, it exits successfully. + * + * @param {Object} options - The options object. + * @param {Object} options.tests - The tests to run. + * @param {TinnyEnvironment} options.devEnv - The development environment. + * @returns {Promise} - A promise that resolves when all tests have been executed. + */ +export const runInBand = async ({ + tests, + devEnv, +}: { + tests: any; + devEnv: TinnyEnvironment; +}): Promise => { + const filters = getFiltersFlag(); + const testsToRun = Object.entries(tests).filter( + ([testName]) => filters.length === 0 || filters.includes(testName) + ); + + // Initialize arrays to keep track of skipped, failed, and passed tests + let skippedTests: string[] = []; + let failedTests: string[] = []; + let passedTests: string[] = []; + + // Iterate over each test and run it in series + for (const [testName, testFunction] of testsToRun) { + const maxAttempts = devEnv.processEnvs.MAX_ATTEMPTS; + let attempts = 0; + let testPassed = false; + + while (attempts < maxAttempts && !testPassed) { + const startTime = performance.now(); + + try { + console.log(`Attempt ${attempts + 1} for ${testName}...`); + + // @ts-ignore + await testFunction(devEnv); + testPassed = true; + + const endTime = performance.now(); + const timeTaken = (endTime - startTime).toFixed(2); + console.log(`${testName} - Passed (${timeTaken} ms)`); + passedTests.push(`${testName} (Passed in ${timeTaken} ms)`); + } catch (error) { + if (error.message === 'LIT_IGNORE_TEST') { + skippedTests.push(`${testName} (Skipped)`); + break; + } + attempts++; + if (attempts >= maxAttempts) { + const endTime = performance.now(); + const timeTaken = (endTime - startTime).toFixed(2); + console.error( + `${testName} - Failed after ${maxAttempts} attempts (${timeTaken} ms)` + ); + console.error(`Error: ${error}`); + failedTests.push( + `${testName} (Failed in ${timeTaken} ms) - Error: ${error}` + ); + } + } + + await new Promise((resolve) => + setTimeout(resolve, devEnv.processEnvs.RUN_IN_BAND_INTERVAL) + ); + } + } + + passedTests.forEach((test) => console.log(`- ${test}`)); + failedTests.forEach((test) => console.log(`- ${test}`)); + skippedTests.forEach((test) => console.log(`- ${test}`)); + + console.log(); + // Print results + console.log( + `Test Report: ${passedTests.length} test(s) passed, ${failedTests.length} failed, ${skippedTests.length} skipped.` + ); + + if (failedTests.length > 0) { + process.exit(1); // Exit with error code if any test failed + } else { + process.exit(0); // Exit successfully if all tests passed + } +}; + +/** + * Runs tests in parallel and reports the results. + * @param {Object} options - The options for running the tests. + * @param {any} options.tests - The tests to run. + * @param {TinnyEnvironment} options.devEnv - The development environment. + * @returns {Promise} - A promise that resolves when all tests have been run. + */ +export const runTestsParallel = async ({ + tests, + devEnv, +}: { + tests: any; + devEnv: TinnyEnvironment; +}): Promise => { + const filters = getFiltersFlag(); + const testsToRun = Object.entries(tests).filter( + ([testName]) => filters.length === 0 || filters.includes(testName) + ); + + const testPromises = testsToRun.map( + async ([testName, testFunction], testIndex) => { + const maxAttempts = devEnv.processEnvs.MAX_ATTEMPTS; + let attempts = 0; + let testPassed = false; + + while (attempts < maxAttempts && !testPassed) { + const startTime = performance.now(); + try { + console.log( + `\x1b[90m[runTestsParallel] Attempt ${attempts + 1} for ${ + testIndex + 1 + }. ${testName}...\x1b[0m` + ); + + // @ts-ignore + await testFunction(devEnv); + testPassed = true; + + const endTime = performance.now(); + const timeTaken = (endTime - startTime).toFixed(2); + console.log( + `\x1b[32m✔\x1b[90m ${ + testIndex + 1 + }. ${testName} - Passed (${timeTaken} ms)\x1b[0m` + ); + return `${testName} (Passed in ${timeTaken} ms)`; + } catch (error) { + if (error.message === 'LIT_IGNORE_TEST') { + return `${testName} (Skipped)`; + } + attempts++; + + // wait for at least 5 seconds + if (attempts >= maxAttempts) { + const endTime = performance.now(); + const timeTaken = (endTime - startTime).toFixed(2); + console.error( + `\x1b[31m✖\x1b[90m ${ + testIndex + 1 + }. ${testName} - Failed after ${maxAttempts} attempts (${timeTaken} ms)\x1b[0m` + ); + console.error(`\x1b[31mError:\x1b[90m ${error}\x1b[0m`); + return `${testName} (Failed in ${timeTaken} ms) - Error: ${error}`; + } + } + } + } + ); + + const results = await Promise.all(testPromises); + + const skippedTests = results.filter((result) => result.includes('Skipped')); + const failedTests = results.filter((result) => result.includes('Failed')); + const passedTests = results.filter((result) => result.includes('Passed')); + + if (skippedTests.length > 0) { + console.log(`\x1b[90mTest Report: Some tests were skipped.\x1b[0m`); + skippedTests.forEach((skippedTest) => + console.log(`\x1b[90m- ${skippedTest}\x1b[0m`) + ); + } + + if (failedTests.length > 0) { + console.log(`\x1b[31mTest Report: Some tests failed.\x1b[0m`); + failedTests.forEach((failedTest) => + console.log(`\x1b[31m- ${failedTest}\x1b[0m`) + ); + } + + if (passedTests.length > 0) { + passedTests.forEach((passedTest) => + console.log(`\x1b[32m- ${passedTest}\x1b[0m`) + ); + console.log('\x1b[32mTest Report: All tests passed.\x1b[0m'); + } + + if (failedTests.length > 0) { + process.exit(1); // Exit with error code if any test failed + } else { + process.exit(0); // Exit successfully if all tests passed + } +}; diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts new file mode 100644 index 0000000000..210a2943f1 --- /dev/null +++ b/local-tests/setup/tinny-person.ts @@ -0,0 +1,182 @@ +import { + AuthSig, + craftAuthSig, + createSiweMessage, +} from '@lit-protocol/auth-helpers'; +import { LitContracts } from '@lit-protocol/contracts-sdk'; +import { + AuthMethod, + BaseSiweMessage, + LitContractContext, +} from '@lit-protocol/types'; +import { ethers } from 'ethers'; +import { LIT_TESTNET, PKPInfo, TinnyEnvConfig } from './tinny-config'; +import { EthWalletProvider } from '@lit-protocol/lit-auth-client'; +import networkContext from './networkContext.json'; +import { AuthMethodScope } from '@lit-protocol/constants'; + +export class TinnyPerson { + public privateKey: string; + public wallet: ethers.Wallet; + public siweMessage: string; + public authSig: AuthSig; + public authMethod: AuthMethod; + public contractsClient: LitContracts; + // public capacityTokenId: string; + // public capacityDelegationAuthSig: AuthSig; + public pkp: PKPInfo; + public authMethodOwnedPkp: PKPInfo; + + // Pass this to data to sign + public loveLetter: Uint8Array = ethers.utils.arrayify( + ethers.utils.keccak256([1, 2, 3, 4, 5]) + ); + + public provider: ethers.providers.JsonRpcProvider; + + public envConfig: TinnyEnvConfig; + + constructor({ + privateKey, + envConfig, + }: { + privateKey: string; + envConfig: TinnyEnvConfig; + }) { + this.envConfig = envConfig; + + this.privateKey = privateKey; + this.provider = new ethers.providers.JsonRpcProvider(this.envConfig.rpc); + this.wallet = new ethers.Wallet(privateKey, this.provider); + } + + async spawn() { + console.log('[𐬺🧪 Tinny Person𐬺] Spawning person:', this.wallet.address); + /** + * ==================================== + * Get Hot Wallet Auth Sig + * ==================================== + */ + this.siweMessage = await createSiweMessage({ + nonce: await this.envConfig.litNodeClient.getLatestBlockhash(), + walletAddress: this.wallet.address, + }); + + this.authSig = await craftAuthSig({ + signer: this.wallet, + toSign: this.siweMessage, + }); + + /** + * ==================================== + * Craft an authMethod from the authSig for the eth wallet auth method + * ==================================== + */ + console.log( + '[𐬺🧪 Tinny Person𐬺] Crafting an authMethod from the authSig for the eth wallet auth method...' + ); + this.authMethod = await EthWalletProvider.authenticate({ + signer: this.wallet, + litNodeClient: this.envConfig.litNodeClient, + }); + + // /** + // * ==================================== + // * Setup contracts-sdk client + // * ==================================== + // */ + if (this.envConfig.network === LIT_TESTNET.LOCALCHAIN) { + this.contractsClient = new LitContracts({ + signer: this.wallet, + debug: this.envConfig.processEnvs.DEBUG, + rpc: this.envConfig.processEnvs.LIT_RPC_URL, // anvil rpc + customContext: networkContext as unknown as LitContractContext, + }); + } else { + this.contractsClient = new LitContracts({ + signer: this.wallet, + debug: this.envConfig.processEnvs.DEBUG, + network: this.envConfig.network, + }); + } + + await this.contractsClient.connect(); + + /** + * ==================================== + * Mint a PKP + * ==================================== + */ + console.log('[𐬺🧪 Tinny Person𐬺] Minting a PKP...'); + const walletMintRes = + await this.contractsClient.pkpNftContractUtils.write.mint(); + + this.pkp = walletMintRes.pkp; + + /** + * ==================================== + * Mint a PKP wiuth eth wallet auth method + * ==================================== + */ + console.log( + '[𐬺🧪 Tinny Person𐬺] Minting a PKP with eth wallet auth method...' + ); + this.authMethodOwnedPkp = ( + await this.contractsClient.mintWithAuth({ + authMethod: this.authMethod, + scopes: [AuthMethodScope.SignAnything], + }) + ).pkp; + + console.log( + '[𐬺🧪 Tinny Person𐬺] 🐣 TinnyPerson spawned:', + this.wallet.address + ); + } + + /** + * ==================================== + * Mint a Capacity Credits NFT + * ==================================== + */ + async mintCapacityCreditsNFT() { + console.log('[𐬺🧪 Tinny Person𐬺] Mint a Capacity Credits NFT '); + const capacityTokenId = ( + await this.contractsClient.mintCapacityCreditsNFT({ + requestsPerKilosecond: + this.envConfig.processEnvs.REQUEST_PER_KILOSECOND, + daysUntilUTCMidnightExpiration: 2, + }) + ).capacityTokenIdStr; + + return capacityTokenId; + } + + /** + * ==================================== + * Mint a Capacity Credits NFT and get a capacity delegation authSig with it + * ==================================== + */ + async createCapacityDelegationAuthSig( + addresses: string[] = [] + ): Promise { + console.log( + '[𐬺🧪 Tinny Person𐬺] Mint a Capacity Credits NFT and get a capacity delegation authSig with it' + ); + const capacityTokenId = ( + await this.contractsClient.mintCapacityCreditsNFT({ + requestsPerKilosecond: + this.envConfig.processEnvs.REQUEST_PER_KILOSECOND, + daysUntilUTCMidnightExpiration: 2, + }) + ).capacityTokenIdStr; + + return ( + await this.envConfig.litNodeClient.createCapacityDelegationAuthSig({ + dAppOwnerWallet: this.wallet, + capacityTokenId: capacityTokenId, + ...(addresses.length && { delegateeAddresses: addresses }), + }) + ).capacityDelegationAuthSig; + } +} diff --git a/local-tests/shim.mjs b/local-tests/shim.mjs new file mode 100644 index 0000000000..32068375c1 --- /dev/null +++ b/local-tests/shim.mjs @@ -0,0 +1,3 @@ +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +global.require = require; diff --git a/local-tests/test.ts b/local-tests/test.ts new file mode 100644 index 0000000000..bfc0bcf724 --- /dev/null +++ b/local-tests/test.ts @@ -0,0 +1,39 @@ +import { LIT_ENDPOINT_VERSION, LIT_TESTNET } from './setup/tinny-config'; +import { TinnyEnvironment } from './setup/tinny-environment'; +import { runInBand, runTestsParallel } from './setup/tinny-operations'; +import { testBundleSpeed } from './tests/test-bundle-speed'; +import { testExample } from './tests/test-example'; + +(async () => { + console.log('[𐬺🧪 Tinny𐬺] Running tests...'); + const devEnv = new TinnyEnvironment(); + await devEnv.init(); + + if (LIT_TESTNET.LOCALCHAIN) { + // set global executeJs endpoint version for all tests. + devEnv.setGlobalExecuteJsVersion( + LIT_TESTNET.LOCALCHAIN, + LIT_ENDPOINT_VERSION.V1 + ); + + // set global pkpSign endpoint version for all tests. + devEnv.setGlobalPkpSignVersion( + LIT_TESTNET.LOCALCHAIN, + LIT_ENDPOINT_VERSION.V1 + ); + } + + const testConfig = { + tests: { + testExample, + testBundleSpeed, + }, + devEnv, + }; + + if (devEnv.processEnvs.RUN_IN_BAND) { + await runInBand(testConfig); + } else { + await runTestsParallel(testConfig); + } +})(); diff --git a/local-tests/tests/test-bundle-speed.ts b/local-tests/tests/test-bundle-speed.ts new file mode 100644 index 0000000000..703b9017f3 --- /dev/null +++ b/local-tests/tests/test-bundle-speed.ts @@ -0,0 +1,15 @@ +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test bundle speed + * @param devEnv + */ +export const testBundleSpeed = async (devEnv: TinnyEnvironment) => { + const a = await import('@lit-protocol/lit-node-client'); + const b = await import('@lit-protocol/contracts-sdk'); + const c = await import('@lit-protocol/auth-helpers'); + const d = await import('@lit-protocol/constants'); + const e = await import('@lit-protocol/lit-auth-client'); + + console.log(a, b, c, d, e); +}; diff --git a/local-tests/tests/test-example.ts b/local-tests/tests/test-example.ts new file mode 100644 index 0000000000..6b907d19a0 --- /dev/null +++ b/local-tests/tests/test-example.ts @@ -0,0 +1,46 @@ +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; + +import { + LIT_ENDPOINT_VERSION, + LIT_TESTNET, +} from 'local-tests/setup/tinny-config'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +export const testExample = async (devEnv: TinnyEnvironment) => { + // Note: This test will be skipped if we are testing on the Cayenne network + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + + const aliceEoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const aliceExecuteJsRes = await devEnv.litNodeClient.executeJs({ + sessionSigs: aliceEoaSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.pkp.publicKey, + }, + }); + + console.log('aliceExecuteJsRes:', aliceExecuteJsRes); + + // console.log('aliceEoaSessionSigs: ', aliceEoaSessionSigs); + + // const alicePkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + // console.log('alicePkpSessionSigs: ', alicePkpSessionSigs); + + // const aliceLitActionSessionSigs = await getLitActionSessionSigs( + // devEnv, + // alice + // ); + // console.log('aliceLitActionSessionSigs: ', aliceLitActionSessionSigs); +}; diff --git a/package.json b/package.json index 0a68a8662f..91460ceed7 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "test:e2e:web": "yarn test:e2e", "test:e2e:node": "node --no-warnings ./e2e-nodejs/index.mjs", "test:e2e:nodejs": "yarn test:e2e:node", + "test:local": "node ./local-tests/build.mjs && node ./local-tests/build/test.mjs", "test:unit": "yarn test:packages", "test:custom": "yarn tools --test --custom", "test:bun": "bun ./tools/scripts/test-script.mjs", @@ -108,7 +109,7 @@ "commander": "^9.4.0", "concurrently": "^7.4.0", "core-js": "^3.6.5", - "cross-fetch": "^3.1.4", + "cross-fetch": "3.1.4", "crypto-browserify": "^3.12.0", "cypress-wait-until": "^1.7.2", "cypress-watch-and-reload": "^1.10.3", @@ -171,7 +172,9 @@ "cypress-metamask": "^1.0.5-development", "cypress-metamask-v2": "^1.7.2", "esbuild": "0.19.12", + "esbuild-plugin-tsc": "^0.4.0", "esbuild-node-builtins": "^0.1.0", + "esbuild-node-externals": "^1.13.0", "eslint": "8.48.0", "eslint-config-next": "12.2.3", "eslint-config-prettier": "9.1.0", diff --git a/yarn.lock b/yarn.lock index 9493696879..500b580f33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,9 +16,9 @@ "@jridgewell/trace-mapping" "^0.3.24" "@angular-devkit/core@^17.2.1": - version "17.3.0" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-17.3.0.tgz#88f8a513dbf23d3248d4cc1ffadfb6324b3aa859" - integrity sha512-ldErhMYq8rcFOhWQ0syQdLy6IYb/LL0erigj7gCMOf59oJgM7B13o/ZTOCvyJttUZ9IP0HB98Gi3epEuJ30VLg== + version "17.3.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-17.3.5.tgz#5af01de95b4945587aea1feaa1011f87485ffee5" + integrity sha512-iqGv45HVI+yRROoTqQTY0QChYlRCZkFUfIjdfJLegjc6xq9sLtxDr03CWM45BKGG5lSxDOy+qu/pdRvtL3V2eg== dependencies: ajv "8.12.0" ajv-formats "2.1.1" @@ -63,23 +63,23 @@ "@babel/highlight" "^7.24.2" picocolors "^1.0.0" -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.1.tgz#31c1f66435f2a9c329bb5716a6d6186c516c3742" - integrity sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== "@babel/core@^7.1.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.21.3", "@babel/core@^7.22.9", "@babel/core@^7.23.9", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.3.tgz#568864247ea10fbd4eff04dda1e05f9e2ea985c3" - integrity sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" + integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.1" + "@babel/generator" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.1" - "@babel/parser" "^7.24.1" + "@babel/helpers" "^7.24.4" + "@babel/parser" "^7.24.4" "@babel/template" "^7.24.0" "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" @@ -89,10 +89,10 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.1", "@babel/generator@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0" - integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A== +"@babel/generator@^7.24.1", "@babel/generator@^7.24.4", "@babel/generator@^7.7.2": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498" + integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== dependencies: "@babel/types" "^7.24.0" "@jridgewell/gen-mapping" "^0.3.5" @@ -124,10 +124,10 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz#db58bf57137b623b916e24874ab7188d93d7f68f" - integrity sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA== +"@babel/helper-create-class-features-plugin@^7.24.1", "@babel/helper-create-class-features-plugin@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz#c806f73788a6800a5cfbbc04d2df7ee4d927cce3" + integrity sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" "@babel/helper-environment-visitor" "^7.22.20" @@ -148,10 +148,10 @@ regexpu-core "^5.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz#fadc63f0c2ff3c8d02ed905dcea747c5b0fb74fd" - integrity sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA== +"@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" + integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== dependencies: "@babel/helper-compilation-targets" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" @@ -279,10 +279,10 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.1.tgz#183e44714b9eba36c3038e442516587b1e0a1a94" - integrity sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg== +"@babel/helpers@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.4.tgz#dc00907fd0d95da74563c142ef4cd21f2cb856b6" + integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== dependencies: "@babel/template" "^7.24.0" "@babel/traverse" "^7.24.1" @@ -298,10 +298,18 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" - integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz#6125f0158543fb4edf1c22f322f3db67f21cb3e1" + integrity sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.1": version "7.24.1" @@ -529,10 +537,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-block-scoping@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz#27af183d7f6dad890531256c7a45019df768ac1f" - integrity sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw== +"@babel/plugin-transform-block-scoping@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz#28f5c010b66fbb8ccdeef853bef1935c434d7012" + integrity sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g== dependencies: "@babel/helper-plugin-utils" "^7.24.0" @@ -544,12 +552,12 @@ "@babel/helper-create-class-features-plugin" "^7.24.1" "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-class-static-block@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz#4e37efcca1d9f2fcb908d1bae8b56b4b6e9e1cb6" - integrity sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA== +"@babel/plugin-transform-class-static-block@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz#1a4653c0cf8ac46441ec406dece6e9bc590356a4" + integrity sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-create-class-features-plugin" "^7.24.4" "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-class-static-block" "^7.14.5" @@ -905,12 +913,12 @@ "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-transform-typescript@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz#5c05e28bb76c7dfe7d6c5bed9951324fd2d3ab07" - integrity sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz#03e0492537a4b953e491f53f2bc88245574ebd15" + integrity sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-create-class-features-plugin" "^7.24.4" "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-typescript" "^7.24.1" @@ -946,14 +954,15 @@ "@babel/helper-plugin-utils" "^7.24.0" "@babel/preset-env@^7.20.2", "@babel/preset-env@^7.22.9": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.3.tgz#f3f138c844ffeeac372597b29c51b5259e8323a3" - integrity sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.4.tgz#46dbbcd608771373b88f956ffb67d471dce0d23b" + integrity sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A== dependencies: - "@babel/compat-data" "^7.24.1" + "@babel/compat-data" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.4" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.1" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.1" "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.1" @@ -980,9 +989,9 @@ "@babel/plugin-transform-async-generator-functions" "^7.24.3" "@babel/plugin-transform-async-to-generator" "^7.24.1" "@babel/plugin-transform-block-scoped-functions" "^7.24.1" - "@babel/plugin-transform-block-scoping" "^7.24.1" + "@babel/plugin-transform-block-scoping" "^7.24.4" "@babel/plugin-transform-class-properties" "^7.24.1" - "@babel/plugin-transform-class-static-block" "^7.24.1" + "@babel/plugin-transform-class-static-block" "^7.24.4" "@babel/plugin-transform-classes" "^7.24.1" "@babel/plugin-transform-computed-properties" "^7.24.1" "@babel/plugin-transform-destructuring" "^7.24.1" @@ -1069,17 +1078,17 @@ integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== "@babel/runtime-corejs3@^7.10.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.24.1.tgz#f39707b213441dec645ce8285ae14f281a5077c6" - integrity sha512-T9ko/35G+Bkl+win48GduaPlhSlOjjE5s1TeiEcD+QpxlLQnoEfb/nO/T+TQqkm+ipFwORn+rB8w14iJ/uD0bg== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.24.4.tgz#b9ebe728087cfbb22bbaccc6f9a70d69834124a0" + integrity sha512-VOQOexSilscN24VEY810G/PqtpFvx/z6UqDIjIWbDe2368HhDLkYN5TYwaEz/+eRCUkhJ2WaNLLmQAlxzfWj4w== dependencies: core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.18.9", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57" - integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== dependencies: regenerator-runtime "^0.14.0" @@ -1267,9 +1276,9 @@ "@jridgewell/trace-mapping" "0.3.9" "@cypress/code-coverage@^3.10.0": - version "3.12.30" - resolved "https://registry.yarnpkg.com/@cypress/code-coverage/-/code-coverage-3.12.30.tgz#0f5647e402457f1ce65388a1fd9754fbb1027847" - integrity sha512-3pE2NgAIHPw92MCzgXAtJJe6Z0z4HUJuorWBSh9Ly0s/BpLf9lZKRI8WhMIDA35oFjAmNCsChiXHFy47evasfw== + version "3.12.36" + resolved "https://registry.yarnpkg.com/@cypress/code-coverage/-/code-coverage-3.12.36.tgz#c484f0c738621a481c2d9e613adb6d9009d95ae6" + integrity sha512-+oI0HXRgQ33jRjt3DED0K333Qp+52PuhY3Ka7j1N2qbjmshvM+kX+C9R51vELbuoPRDWGsYIdQ4A4ECK9rnrVg== dependencies: "@cypress/webpack-preprocessor" "^6.0.0" chalk "4.1.2" @@ -1994,7 +2003,7 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== -"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": +"@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== @@ -2048,9 +2057,9 @@ integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -2069,7 +2078,14 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@isaacs/string-locale-compare@^1.0.1", "@isaacs/string-locale-compare@^1.1.0": +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + +"@isaacs/string-locale-compare@*", "@isaacs/string-locale-compare@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" integrity sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ== @@ -2532,9 +2548,9 @@ integrity sha512-o+TYF8vBcyySRsb2kqBDv/KMeme8a2nwWoG+lAWzbDmWfb2/MrVWYCVYDYvjXdSoI/Cujqy1i0gIDrkdxa9chA== "@leichtgewicht/ip-codec@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" - integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + version "2.0.5" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" + integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== "@lerna/add@5.6.2": version "5.6.2" @@ -3443,7 +3459,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== -"@noble/hashes@1.4.0", "@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.1.2", "@noble/hashes@^1.2.0", "@noble/hashes@^1.3.0", "@noble/hashes@~1.4.0": +"@noble/hashes@1.4.0", "@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.1.2", "@noble/hashes@^1.2.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.4.0", "@noble/hashes@~1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== @@ -3491,15 +3507,55 @@ undici "^5.14.0" "@npmcli/agent@^2.0.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.1.tgz#8aa677d0a4136d57524336a35d5679aedf2d56f7" - integrity sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ== + version "2.2.2" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5" + integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== dependencies: agent-base "^7.1.0" http-proxy-agent "^7.0.0" https-proxy-agent "^7.0.1" lru-cache "^10.0.1" - socks-proxy-agent "^8.0.1" + socks-proxy-agent "^8.0.3" + +"@npmcli/arborist@*", "@npmcli/arborist@^7.2.1": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-7.4.2.tgz#deb6eb3d88ab6913f0efeb4ebca64151d091d331" + integrity sha512-13flK0DTIhG7VEmPtoKFoi+88hIjuZxuZAvnHUTthIFql1Kc51VlsMRpbJPIcDEZHaHkILwFjHRXtCUYdFWvAQ== + dependencies: + "@isaacs/string-locale-compare" "^1.1.0" + "@npmcli/fs" "^3.1.0" + "@npmcli/installed-package-contents" "^2.0.2" + "@npmcli/map-workspaces" "^3.0.2" + "@npmcli/metavuln-calculator" "^7.0.0" + "@npmcli/name-from-folder" "^2.0.0" + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/package-json" "^5.0.0" + "@npmcli/query" "^3.1.0" + "@npmcli/redact" "^1.1.0" + "@npmcli/run-script" "^7.0.2" + bin-links "^4.0.1" + cacache "^18.0.0" + common-ancestor-path "^1.0.1" + hosted-git-info "^7.0.1" + json-parse-even-better-errors "^3.0.0" + json-stringify-nice "^1.1.4" + minimatch "^9.0.4" + nopt "^7.0.0" + npm-install-checks "^6.2.0" + npm-package-arg "^11.0.1" + npm-pick-manifest "^9.0.0" + npm-registry-fetch "^16.2.0" + npmlog "^7.0.1" + pacote "^17.0.4" + parse-conflict-json "^3.0.0" + proc-log "^3.0.0" + promise-all-reject-late "^1.0.0" + promise-call-limit "^3.0.1" + read-package-json-fast "^3.0.2" + semver "^7.3.7" + ssri "^10.0.5" + treeverse "^3.0.0" + walk-up-path "^3.0.1" "@npmcli/arborist@5.3.0": version "5.3.0" @@ -3541,75 +3597,32 @@ treeverse "^2.0.0" walk-up-path "^1.0.0" -"@npmcli/arborist@^2.3.0", "@npmcli/arborist@^2.5.0", "@npmcli/arborist@^2.9.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-2.10.0.tgz#424c2d73a7ae59c960b0cc7f74fed043e4316c2c" - integrity sha512-CLnD+zXG9oijEEzViimz8fbOoFVb7hoypiaf7p6giJhvYtrxLAyY3cZAMPIFQvsG731+02eMDp3LqVBNo7BaZA== - dependencies: - "@isaacs/string-locale-compare" "^1.0.1" - "@npmcli/installed-package-contents" "^1.0.7" - "@npmcli/map-workspaces" "^1.0.2" - "@npmcli/metavuln-calculator" "^1.1.0" - "@npmcli/move-file" "^1.1.0" - "@npmcli/name-from-folder" "^1.0.1" - "@npmcli/node-gyp" "^1.0.1" - "@npmcli/package-json" "^1.0.1" - "@npmcli/run-script" "^1.8.2" - bin-links "^2.2.1" - cacache "^15.0.3" - common-ancestor-path "^1.0.1" - json-parse-even-better-errors "^2.3.1" - json-stringify-nice "^1.1.4" - mkdirp "^1.0.4" - mkdirp-infer-owner "^2.0.0" - npm-install-checks "^4.0.0" - npm-package-arg "^8.1.5" - npm-pick-manifest "^6.1.0" - npm-registry-fetch "^11.0.0" - pacote "^11.3.5" - parse-conflict-json "^1.1.1" - proc-log "^1.0.0" - promise-all-reject-late "^1.0.0" - promise-call-limit "^1.0.1" - read-package-json-fast "^2.0.2" - readdir-scoped-modules "^1.1.0" - rimraf "^3.0.2" - semver "^7.3.5" - ssri "^8.0.1" - treeverse "^1.0.4" - walk-up-path "^1.0.0" - -"@npmcli/ci-detect@^1.2.0", "@npmcli/ci-detect@^1.3.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" - integrity sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q== +"@npmcli/ci-detect@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-3.0.2.tgz#facf5e48f553dd876cc9f5a749b269186ed7f7e6" + integrity sha512-P7nZG0skRVa9lH0OQmFG62CrzOySUiuPbKopjVAj3sXP0m1om9XfIvTp46h+NvlpTyd121JekiXFZj+1pnbm9g== -"@npmcli/config@^2.3.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-2.4.0.tgz#1447b0274f9502871dabd3ab1d8302472d515b1f" - integrity sha512-fwxu/zaZnvBJohXM3igzqa3P1IVYWi5N343XcKvKkJbAx+rTqegS5tAul4NLiMPQh6WoS5a4er6oo/ieUx1f4g== +"@npmcli/config@*": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-8.2.2.tgz#7383559f04e753cad007c845defaacd0c47c6e30" + integrity sha512-VvMHPIzcsKHCaNh9h4kCbn7NyDtcNJFMOUZ8Wu9SWhds5Egr1gMGU2fv+M50P1V5iAUZWZcv2Iguo5HTckpzww== dependencies: - ini "^2.0.0" - mkdirp-infer-owner "^2.0.0" - nopt "^5.0.0" - semver "^7.3.4" - walk-up-path "^1.0.0" + "@npmcli/map-workspaces" "^3.0.2" + ci-info "^4.0.0" + ini "^4.1.2" + nopt "^7.0.0" + proc-log "^3.0.0" + read-package-json-fast "^3.0.2" + semver "^7.3.5" + walk-up-path "^3.0.1" -"@npmcli/disparity-colors@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/disparity-colors/-/disparity-colors-1.0.1.tgz#b23c864c9658f9f0318d5aa6d17986619989535c" - integrity sha512-kQ1aCTTU45mPXN+pdAaRxlxr3OunkyztjbbxDY/aIcPS5CnCUrx+1+NvA6pTcYR7wmLZe37+Mi5v3nfbwPxq3A== +"@npmcli/disparity-colors@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/disparity-colors/-/disparity-colors-3.0.0.tgz#60ea8c6eb5ba9de2d1950e15b06205b2c3ab7833" + integrity sha512-5R/z157/f20Fi0Ou4ZttL51V0xz0EdPEOauFtPCEYOLInDBRCj1/TxOJ5aGTrtShxEshN2d+hXb9ZKSi5RLBcg== dependencies: ansi-styles "^4.3.0" -"@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - "@npmcli/fs@^2.1.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" @@ -3625,20 +3638,6 @@ dependencies: semver "^7.3.5" -"@npmcli/git@^2.0.7", "@npmcli/git@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" - integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== - dependencies: - "@npmcli/promise-spawn" "^1.3.2" - lru-cache "^6.0.0" - mkdirp "^1.0.4" - npm-pick-manifest "^6.1.1" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^2.0.2" - "@npmcli/git@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-3.0.2.tgz#5c5de6b4d70474cf2d09af149ce42e4e1dacb931" @@ -3654,7 +3653,21 @@ semver "^7.3.5" which "^2.0.2" -"@npmcli/installed-package-contents@^1.0.6", "@npmcli/installed-package-contents@^1.0.7": +"@npmcli/git@^5.0.0", "@npmcli/git@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-5.0.6.tgz#d7b24eb2cff98754c8868faab40405abfa1abe28" + integrity sha512-4x/182sKXmQkf0EtXxT26GEsaOATpD7WVtza5hrYivWZeo6QefC6xq9KAXrnjtFKBZ4rZwR7aX/zClYYXgtwLw== + dependencies: + "@npmcli/promise-spawn" "^7.0.0" + lru-cache "^10.0.1" + npm-pick-manifest "^9.0.0" + proc-log "^4.0.0" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.5" + which "^4.0.0" + +"@npmcli/installed-package-contents@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== @@ -3662,15 +3675,23 @@ npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -"@npmcli/map-workspaces@^1.0.2", "@npmcli/map-workspaces@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-1.0.4.tgz#915708b55afa25e20bc2c14a766c124c2c5d4cab" - integrity sha512-wVR8QxhyXsFcD/cORtJwGQodeeaDf0OxcHie8ema4VgFeqwYkFsDPnSrIRSytX8xR6nKPAH89WnwTcaU608b/Q== +"@npmcli/installed-package-contents@^2.0.1", "@npmcli/installed-package-contents@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33" + integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ== dependencies: - "@npmcli/name-from-folder" "^1.0.1" - glob "^7.1.6" - minimatch "^3.0.4" - read-package-json-fast "^2.0.1" + npm-bundled "^3.0.0" + npm-normalize-package-bin "^3.0.0" + +"@npmcli/map-workspaces@*", "@npmcli/map-workspaces@^3.0.2": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz#27dc06c20c35ef01e45a08909cab9cb3da08cea6" + integrity sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA== + dependencies: + "@npmcli/name-from-folder" "^2.0.0" + glob "^10.2.2" + minimatch "^9.0.0" + read-package-json-fast "^3.0.0" "@npmcli/map-workspaces@^2.0.3": version "2.0.4" @@ -3682,15 +3703,6 @@ minimatch "^5.0.1" read-package-json-fast "^2.0.3" -"@npmcli/metavuln-calculator@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-1.1.1.tgz#2f95ff3c6d88b366dd70de1c3f304267c631b458" - integrity sha512-9xe+ZZ1iGVaUovBVFI9h3qW+UuECUzhvZPxK9RaEA2mjU26o5D0JloGYWwLYvQELJNmBdQB6rrpuN8jni6LwzQ== - dependencies: - cacache "^15.0.5" - pacote "^11.1.11" - semver "^7.3.2" - "@npmcli/metavuln-calculator@^3.0.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz#9359bd72b400f8353f6a28a25c8457b562602622" @@ -3701,13 +3713,16 @@ pacote "^13.0.3" semver "^7.3.5" -"@npmcli/move-file@^1.0.1", "@npmcli/move-file@^1.1.0": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== +"@npmcli/metavuln-calculator@^7.0.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.0.tgz#70aad00623d47297cd2c950a686ef4220e4a9040" + integrity sha512-D4VZzVLZ4Mw+oUCWyQ6qzlm5SGlrLnhKtZscDwQXFFc1FUPvw69Ibo2E5ZpJAmjFSYkA5UlCievWmREW0JLC3w== dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" + cacache "^18.0.0" + json-parse-even-better-errors "^3.0.0" + pacote "^18.0.0" + proc-log "^4.1.0" + semver "^7.3.5" "@npmcli/move-file@^2.0.0": version "2.0.1" @@ -3722,22 +3737,33 @@ resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz#77ecd0a4fcb772ba6fe927e2e2e155fbec2e6b1a" integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== -"@npmcli/node-gyp@^1.0.1", "@npmcli/node-gyp@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" - integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== +"@npmcli/name-from-folder@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz#c44d3a7c6d5c184bb6036f4d5995eee298945815" + integrity sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg== "@npmcli/node-gyp@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz#8c20e53e34e9078d18815c1d2dda6f2420d75e35" integrity sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A== -"@npmcli/package-json@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-1.0.1.tgz#1ed42f00febe5293c3502fd0ef785647355f6e89" - integrity sha512-y6jnu76E9C23osz8gEMBayZmaZ69vFOIk8vR1FJL/wbEJ54+9aVG9rLTjQKSXfgYZEr50nw1txBBFfBZZe+bYg== +"@npmcli/node-gyp@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a" + integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA== + +"@npmcli/package-json@*", "@npmcli/package-json@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-5.1.0.tgz#10d117b5fb175acc14c70901a151c52deffc843e" + integrity sha512-1aL4TuVrLS9sf8quCLerU3H9J4vtCtgu8VauYozrmEyU57i/EdKleCnsQ7vpnABIH6c9mnTxcH5sFkO3BlV8wQ== dependencies: - json-parse-even-better-errors "^2.3.1" + "@npmcli/git" "^5.0.0" + glob "^10.2.2" + hosted-git-info "^7.0.0" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^6.0.0" + proc-log "^4.0.0" + semver "^7.5.3" "@npmcli/package-json@^2.0.0": version "2.0.0" @@ -3746,13 +3772,6 @@ dependencies: json-parse-even-better-errors "^2.3.1" -"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" - integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== - dependencies: - infer-owner "^1.0.4" - "@npmcli/promise-spawn@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz#53283b5f18f855c6925f23c24e67c911501ef573" @@ -3760,15 +3779,36 @@ dependencies: infer-owner "^1.0.4" -"@npmcli/run-script@^1.8.2", "@npmcli/run-script@^1.8.3", "@npmcli/run-script@^1.8.4", "@npmcli/run-script@^1.8.6": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" - integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== +"@npmcli/promise-spawn@^7.0.0": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz#a836de2f42a2245d629cf6fbb8dd6c74c74c55af" + integrity sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg== + dependencies: + which "^4.0.0" + +"@npmcli/query@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/query/-/query-3.1.0.tgz#bc202c59e122a06cf8acab91c795edda2cdad42c" + integrity sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ== dependencies: - "@npmcli/node-gyp" "^1.0.2" - "@npmcli/promise-spawn" "^1.3.2" - node-gyp "^7.1.0" - read-package-json-fast "^2.0.1" + postcss-selector-parser "^6.0.10" + +"@npmcli/redact@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/redact/-/redact-1.1.0.tgz#78e53a6a34f013543a73827a07ebdc3a6f10454b" + integrity sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ== + +"@npmcli/run-script@*", "@npmcli/run-script@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-8.0.0.tgz#644f8e28fd3cde25e40a79d3b35cb14076ec848b" + integrity sha512-5noc+eCQmX1W9nlFUe65n5MIteikd3vOA2sEPdXtlUv68KWyHNFZnT/LDRXu/E4nZ5yxjciP30pADr/GQ97W1w== + dependencies: + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/package-json" "^5.0.0" + "@npmcli/promise-spawn" "^7.0.0" + node-gyp "^10.0.0" + proc-log "^4.0.0" + which "^4.0.0" "@npmcli/run-script@^4.1.0", "@npmcli/run-script@^4.1.3", "@npmcli/run-script@^4.1.7": version "4.2.1" @@ -3781,6 +3821,17 @@ read-package-json-fast "^2.0.3" which "^2.0.2" +"@npmcli/run-script@^7.0.0", "@npmcli/run-script@^7.0.2": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-7.0.4.tgz#9f29aaf4bfcf57f7de2a9e28d1ef091d14b2e6eb" + integrity sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg== + dependencies: + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/package-json" "^5.0.0" + "@npmcli/promise-spawn" "^7.0.0" + node-gyp "^10.0.0" + which "^4.0.0" + "@nrwl/cli@15.9.7": version "15.9.7" resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-15.9.7.tgz#1db113f5cb1cfe63213097be1ece041eef33da1f" @@ -4543,11 +4594,11 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@playwright/test@^1.25.2", "@playwright/test@^1.27.1": - version "1.42.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.42.1.tgz#9eff7417bcaa770e9e9a00439e078284b301f31c" - integrity sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ== + version "1.43.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.43.1.tgz#16728a59eb8ce0f60472f98d8886d6cab0fa3e42" + integrity sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA== dependencies: - playwright "1.42.1" + playwright "1.43.1" "@portis/web3-provider-engine@1.1.2": version "1.1.2" @@ -4646,9 +4697,9 @@ integrity sha512-LzqpSrMK/3JBAVBI9u3NWtOhWNw5AMQfrUFYB0+bDHTSw17z++WJLsPsxAuK+oSddsxk4d7F/JcdDPM1M5YAhA== "@rushstack/eslint-patch@^1.1.3": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz#c5545e6a5d2bd5c26b4021c357177a28698c950e" - integrity sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ== + version "1.10.2" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz#053f1540703faa81dea2966b768ee5581c66aeda" + integrity sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw== "@scure/base@~1.1.0", "@scure/base@~1.1.4", "@scure/base@~1.1.6": version "1.1.6" @@ -4690,7 +4741,7 @@ "@noble/hashes" "~1.2.0" "@scure/base" "~1.1.0" -"@scure/bip39@1.2.2", "@scure/bip39@^1.2.0": +"@scure/bip39@1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== @@ -4698,6 +4749,14 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.4" +"@scure/bip39@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + "@semantic-release/commit-analyzer@^8.0.0": version "8.0.1" resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz#5d2a37cd5a3312da0e3ac05b1ca348bf60b90bca" @@ -4790,6 +4849,50 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@sigstore/bundle@^2.3.0", "@sigstore/bundle@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-2.3.1.tgz#f6cdc67c8400e58ca27f0ef495b27a9327512073" + integrity sha512-eqV17lO3EIFqCWK3969Rz+J8MYrRZKw9IBHpSo6DEcEX2c+uzDFOgHE9f2MnyDpfs48LFO4hXmk9KhQ74JzU1g== + dependencies: + "@sigstore/protobuf-specs" "^0.3.1" + +"@sigstore/core@^1.0.0", "@sigstore/core@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@sigstore/core/-/core-1.1.0.tgz#5583d8f7ffe599fa0a89f2bf289301a5af262380" + integrity sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg== + +"@sigstore/protobuf-specs@^0.3.0", "@sigstore/protobuf-specs@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.3.1.tgz#7095819fa7c5743efde48a858c37b30fab190a09" + integrity sha512-aIL8Z9NsMr3C64jyQzE0XlkEyBLpgEJJFDHLVVStkFV5Q3Il/r/YtY6NJWKQ4cy4AE7spP1IX5Jq7VCAxHHMfQ== + +"@sigstore/sign@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@sigstore/sign/-/sign-2.3.0.tgz#c35e10a3d707e0c69a29bd9f93fa2bdc6275817c" + integrity sha512-tsAyV6FC3R3pHmKS880IXcDJuiFJiKITO1jxR1qbplcsBkZLBmjrEw5GbC7ikD6f5RU1hr7WnmxB/2kKc1qUWQ== + dependencies: + "@sigstore/bundle" "^2.3.0" + "@sigstore/core" "^1.0.0" + "@sigstore/protobuf-specs" "^0.3.1" + make-fetch-happen "^13.0.0" + +"@sigstore/tuf@^2.3.1": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@sigstore/tuf/-/tuf-2.3.2.tgz#e9c5bffc2a5f3434f87195902d7f9cd7f48c70fa" + integrity sha512-mwbY1VrEGU4CO55t+Kl6I7WZzIl+ysSzEYdA1Nv/FTrl2bkeaPXo5PnWZAVfcY2zSdhOpsUTJW67/M2zHXGn5w== + dependencies: + "@sigstore/protobuf-specs" "^0.3.0" + tuf-js "^2.2.0" + +"@sigstore/verify@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@sigstore/verify/-/verify-1.2.0.tgz#48549186305d8a5e471a3a304cf4cb3e0c99dde7" + integrity sha512-hQF60nc9yab+Csi4AyoAmilGNfpXT+EXdBgFkP9OgPwIBPwyqVf7JAWPtmqrrrneTmAT6ojv7OlH1f6Ix5BG4Q== + dependencies: + "@sigstore/bundle" "^2.3.1" + "@sigstore/core" "^1.1.0" + "@sigstore/protobuf-specs" "^0.3.1" + "@simplewebauthn/browser@^7.2.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@simplewebauthn/browser/-/browser-7.4.0.tgz#3e25b5e9f45d03eb60d3e4f8812d8d2acfd7dba6" @@ -4850,13 +4953,13 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@spruceid/siwe-parser@*": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@spruceid/siwe-parser/-/siwe-parser-2.0.2.tgz#964dbe9e5611fe95d39e21aa96e67407f610374f" - integrity sha512-9WuA0ios2537cWYu39MMeH0O2KdrMKgKlOBUTWRTXQjCYu5B+mHCA0JkCbFaJ/0EjxoVIcYCXIW/DoPEpw+PqA== +"@spruceid/siwe-parser@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@spruceid/siwe-parser/-/siwe-parser-2.1.2.tgz#3e13e7d3ac0bfdaf109a07342590eb21daee2fc3" + integrity sha512-d/r3S1LwJyMaRAKQ0awmo9whfXeE88Qt00vRj91q5uv5ATtWIQEGJ67Yr5eSZw5zp1/fZCXZYuEckt8lSkereQ== dependencies: "@noble/hashes" "^1.1.2" - apg-js "^4.1.1" + apg-js "^4.3.0" uri-js "^4.4.1" valid-url "^1.0.9" @@ -5461,9 +5564,9 @@ integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -5480,6 +5583,19 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@tufjs/canonical-json@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a" + integrity sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA== + +"@tufjs/models@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-2.0.0.tgz#c7ab241cf11dd29deb213d6817dabb8c99ce0863" + integrity sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg== + dependencies: + "@tufjs/canonical-json" "2.0.0" + minimatch "^9.0.3" + "@typechain/ethers-v5@^11.1.1": version "11.1.2" resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-11.1.2.tgz#82510c1744f37a2f906b9e0532ac18c0b74ffe69" @@ -5586,9 +5702,9 @@ "@types/node" "*" "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz#3ae8ab3767d98d0b682cda063c3339e1e86ccfaa" + integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== dependencies: "@types/node" "*" "@types/qs" "*" @@ -5696,11 +5812,6 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/mime@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" - integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw== - "@types/mime@^1": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" @@ -5729,9 +5840,9 @@ "@types/node" "*" "@types/node@*", "@types/node@>=13.7.0": - version "20.11.30" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f" - integrity sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw== + version "20.12.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384" + integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg== dependencies: undici-types "~5.26.4" @@ -5775,14 +5886,14 @@ integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== "@types/prop-types@*": - version "15.7.11" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" - integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== "@types/qs@*": - version "6.9.14" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.14.tgz#169e142bfe493895287bee382af6039795e9b75b" - integrity sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA== + version "6.9.15" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== "@types/range-parser@*": version "1.2.7" @@ -5797,19 +5908,18 @@ "@types/react" "*" "@types/react-dom@^18.0.0": - version "18.2.22" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.22.tgz#d332febf0815403de6da8a97e5fe282cbe609bae" - integrity sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ== + version "18.2.25" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521" + integrity sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA== dependencies: "@types/react" "*" "@types/react@*": - version "18.2.67" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.67.tgz#96b7af0b5e79c756f4bdd981de2ca28472c858e5" - integrity sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw== + version "18.2.79" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.79.tgz#c40efb4f255711f554d47b449f796d1c7756d865" + integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w== dependencies: "@types/prop-types" "*" - "@types/scheduler" "*" csstype "^3.0.2" "@types/react@18.2.24": @@ -5834,9 +5944,9 @@ integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== "@types/scheduler@*": - version "0.16.8" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" - integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== + version "0.23.0" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.23.0.tgz#0a6655b3e2708eaabca00b7372fafd7a792a7b09" + integrity sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw== "@types/secp256k1@^4.0.1": version "4.0.6" @@ -5866,13 +5976,13 @@ "@types/express" "*" "@types/serve-static@*", "@types/serve-static@^1.13.10": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" - integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" - "@types/mime" "*" "@types/node" "*" + "@types/send" "*" "@types/sinonjs__fake-timers@8.1.1": version "8.1.1" @@ -6215,9 +6325,9 @@ "@walletconnect/utils" "^1.8.0" "@walletconnect/core@^2.9.0": - version "2.11.3" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.11.3.tgz#c81855722cb9afd411f91f5345c7874f48bade0b" - integrity sha512-/9m4EqiggFUwkQDv5PDWbcTI+yCVnBd/iYW5iIHEkivg2/mnBr2bQz2r/vtPjp19r/ZK62Dx0+UN3U+BWP8ulQ== + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.12.2.tgz#12bd568b90daed876e58ebcc098c12843a3321e6" + integrity sha512-7Adv/b3pp9F42BkvReaaM4KS8NEvlkS7AMtwO3uF/o6aRMKtcfTJq9/jgWdKJh4RP8pPRTRFjCw6XQ/RZtT4aQ== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" @@ -6225,13 +6335,13 @@ "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/jsonrpc-ws-connection" "1.0.14" "@walletconnect/keyvaluestorage" "^1.1.1" - "@walletconnect/logger" "^2.0.1" + "@walletconnect/logger" "^2.1.2" "@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.11.3" - "@walletconnect/utils" "2.11.3" + "@walletconnect/types" "2.12.2" + "@walletconnect/utils" "2.12.2" events "^3.3.0" isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" @@ -6382,7 +6492,7 @@ idb-keyval "^6.2.1" unstorage "^1.9.0" -"@walletconnect/logger@2.0.1", "@walletconnect/logger@^2.0.1": +"@walletconnect/logger@2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.0.1.tgz#7f489b96e9a1ff6bf3e58f0fbd6d69718bf844a8" integrity sha512-SsTKdsgWm+oDTBeNE/zHxxr5eJfZmE9/5yp/Ku+zJtcTAjELb3DXueWkDXmE9h8uHIbJzIb5wj5lPdzyrjT6hQ== @@ -6390,6 +6500,14 @@ pino "7.11.0" tslib "1.14.1" +"@walletconnect/logger@^2.0.1", "@walletconnect/logger@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.1.2.tgz#813c9af61b96323a99f16c10089bfeb525e2a272" + integrity sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw== + dependencies: + "@walletconnect/safe-json" "^1.0.2" + pino "7.11.0" + "@walletconnect/mobile-registry@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@walletconnect/mobile-registry/-/mobile-registry-1.4.0.tgz#502cf8ab87330841d794819081e748ebdef7aee5" @@ -6443,12 +6561,11 @@ tslib "1.14.1" "@walletconnect/relay-api@^1.0.9": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.9.tgz#f8c2c3993dddaa9f33ed42197fc9bfebd790ecaf" - integrity sha512-Q3+rylJOqRkO1D9Su0DPE3mmznbAalYapJ9qmzDgK28mYF9alcP3UwG/og5V7l7CFOqzCLi7B8BvcBUrpDj0Rg== + version "1.0.10" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.10.tgz#5aef3cd07c21582b968136179aa75849dcc65499" + integrity sha512-tqrdd4zU9VBNqUaXXQASaexklv6A54yEyQQEXYOCr+Jz8Ket0dmPBDyg19LVSNUN2cipAghQc45/KVmfFJ0cYw== dependencies: "@walletconnect/jsonrpc-types" "^1.0.2" - tslib "1.14.1" "@walletconnect/relay-auth@^1.0.4": version "1.0.4" @@ -6505,10 +6622,10 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.11.3": - version "2.11.3" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.11.3.tgz#8ce43cb77e8fd9d5269847cdd73bcfa7cce7dd1a" - integrity sha512-JY4wA9MVosDW9dcJMTpnwliste0aJGJ1X6Q4ulLsQsgWRSEBRkLila0oUT01TDBW9Yq8uUp7uFOUTaKx6KWVAg== +"@walletconnect/types@2.12.2": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.12.2.tgz#8b64a2015a0a96972d28acb2ff317a9a994abfdb" + integrity sha512-9CmwTlPbrFTzayTL9q7xM7s3KTJkS6kYFtH2m1/fHFgALs6pIUjf1qAx1TF2E4tv7SEzLAIzU4NqgYUt2vWXTg== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" @@ -6549,10 +6666,10 @@ "@walletconnect/utils" "2.9.2" events "^3.3.0" -"@walletconnect/utils@2.11.3", "@walletconnect/utils@^2.9.0": - version "2.11.3" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.11.3.tgz#3731809b54902655cf202e0bf0e8f268780e8b54" - integrity sha512-jsdNkrl/IcTkzWFn0S2d0urzBXg6RxVJtUYRsUx3qI3wzOGiABP9ui3yiZ3SgZOv9aRe62PaNp1qpbYZ+zPb8Q== +"@walletconnect/utils@2.12.2", "@walletconnect/utils@^2.9.0": + version "2.12.2" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.12.2.tgz#a2c349d4effef7c1c5e72e74a5483d8dfbb10918" + integrity sha512-zf50HeS3SfoLv1N9GPl2IXTZ9TsXfet4usVAsZmX9P6/Xzq7d/7QakjVQCHH/Wk1O9XkcsfeoZoUhRxoMJ5uJw== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -6562,7 +6679,7 @@ "@walletconnect/relay-api" "^1.0.9" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.11.3" + "@walletconnect/types" "2.12.2" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" @@ -6700,16 +6817,16 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abbrev@1, abbrev@^1.0.0, abbrev@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abbrev@^2.0.0: +abbrev@*, abbrev@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== +abbrev@1, abbrev@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + abi-decoder@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/abi-decoder/-/abi-decoder-2.3.0.tgz#e56b4e7b45f9a612c8aa2c76655948e7bb2687b3" @@ -6813,14 +6930,14 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" -agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" - integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== +agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== dependencies: debug "^4.3.4" -agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: +agentkeepalive@^4.2.1: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== @@ -6854,16 +6971,6 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - ajv@8.12.0, ajv@^8.0.0, ajv@^8.0.1, ajv@^8.12.0, ajv@^8.9.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" @@ -6972,12 +7079,12 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -ansicolors@~0.3.2: +ansicolors@*, ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== -ansistyles@~0.1.3: +ansistyles@*: version "0.1.3" resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" integrity sha512-6QWEyvMgIXX0eO972y7YPBLSBsq7UWKFAoNNTLGaOJ9bstcEL9sCbcjf96dVfNDdUsRoGOK82vWFJlKApXds7g== @@ -7010,7 +7117,7 @@ apache-md5@^1.0.6: resolved "https://registry.yarnpkg.com/apache-md5/-/apache-md5-1.1.8.tgz#ea79c6feb03abfed42b2830dde06f75df5e3bbd9" integrity sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA== -apg-js@^4.1.1: +apg-js@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/apg-js/-/apg-js-4.3.0.tgz#2c55d3f1aa6b90be5d3c6539f346cf2c726702c3" integrity sha512-8U8MULS+JocCnm11bfrVS4zxtAcE3uOiCAI21SnjDrV9LNhMSGwTGGeko3QfyK1JLWwT7KebFqJMB2puzfdFMQ== @@ -7022,11 +7129,6 @@ append-transform@^2.0.0: dependencies: default-require-extensions "^3.0.0" -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - "aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" @@ -7044,19 +7146,11 @@ archive-type@^4.0.0: dependencies: file-type "^4.2.0" -archy@^1.0.0, archy@~1.0.0: +archy@*, archy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - are-we-there-yet@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" @@ -7065,13 +7159,10 @@ are-we-there-yet@^3.0.0: delegates "^1.0.0" readable-stream "^3.6.0" -are-we-there-yet@~1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" - integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" +are-we-there-yet@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-4.0.2.tgz#aed25dd0eae514660d49ac2b2366b175c614785a" + integrity sha512-ncSWAawFhKMJDTdoAeOV+jyW1VCMj5QIAwULIBV0SSR7B/RLPPEQiknKcg/RIIZlUQrxELpsxMiTUoAQ4sIUyg== arg@5.0.2, arg@^5.0.2: version "5.0.2" @@ -7176,14 +7267,15 @@ array-ify@^1.0.0: integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== array-includes@^3.1.3, array-includes@^3.1.5, array-includes@^3.1.6, array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^1.0.1: @@ -7258,14 +7350,16 @@ array.prototype.flatmap@^1.2.4, array.prototype.flatmap@^1.3.0, array.prototype. es-shim-unscopables "^1.0.0" array.prototype.reduce@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz#63149931808c5fc1e1354814923d92d45f7d96d5" - integrity sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg== + version "1.0.7" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz#6aadc2f995af29cb887eb866d981dc85ab6f7dc7" + integrity sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" es-array-method-boxes-properly "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" is-string "^1.0.7" array.prototype.toreversed@^1.1.2: @@ -7473,9 +7567,9 @@ axe-core@=4.7.0: integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== axe-core@^4.4.3: - version "4.8.4" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.4.tgz#90db39a2b316f963f00196434d964e6e23648643" - integrity sha512-CZLSKisu/bhJ2awW4kJndluz2HLZYIHh5Uy1+ZwDRkJi69811xgIXXfdU9HSLX0Th+ILrHj8qfL/5wzamsFtQg== + version "4.9.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.9.0.tgz#b18971494551ab39d4ff5f7d4c6411bd20cc7c2a" + integrity sha512-H5orY+M2Fr56DWmMFpMrq5Ge93qjNdPVqzBv5gWK3aD1OvjBEJlEzxf09z93dGVQeI0LiW+aCMIx1QtShC/zUw== axios@1.1.3: version "1.1.3" @@ -7791,12 +7885,12 @@ babel-plugin-macros@^2.8.0: resolve "^1.12.0" babel-plugin-polyfill-corejs2@^0.4.10: - version "0.4.10" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz#276f41710b03a64f6467433cab72cbc2653c38b1" - integrity sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ== + version "0.4.11" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" + integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== dependencies: "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.6.1" + "@babel/helper-define-polyfill-provider" "^0.6.2" semver "^6.3.1" babel-plugin-polyfill-corejs3@^0.10.1, babel-plugin-polyfill-corejs3@^0.10.4: @@ -7808,11 +7902,11 @@ babel-plugin-polyfill-corejs3@^0.10.1, babel-plugin-polyfill-corejs3@^0.10.4: core-js-compat "^3.36.1" babel-plugin-polyfill-regenerator@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz#4f08ef4c62c7a7f66a35ed4c0d75e30506acc6be" - integrity sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g== + version "0.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" + integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.1" + "@babel/helper-define-polyfill-provider" "^0.6.2" babel-plugin-react-generate-property@^1.1.2: version "1.1.2" @@ -8348,18 +8442,6 @@ bignumber.js@^9.0.0, bignumber.js@^9.0.1: resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== -bin-links@^2.2.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-2.3.0.tgz#1ff241c86d2c29b24ae52f49544db5d78a4eb967" - integrity sha512-JzrOLHLwX2zMqKdyYZjkDgQGT+kHDkIhv2/IK2lJ00qLxV4TmFoHi8drDBb6H5Zrz1YfgHkai4e2MGPqnoUhqA== - dependencies: - cmd-shim "^4.0.1" - mkdirp-infer-owner "^2.0.0" - npm-normalize-package-bin "^1.0.0" - read-cmd-shim "^2.0.0" - rimraf "^3.0.0" - write-file-atomic "^3.0.3" - bin-links@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-3.0.3.tgz#3842711ef3db2cd9f16a5f404a996a12db355a6e" @@ -8372,12 +8454,22 @@ bin-links@^3.0.0: rimraf "^3.0.0" write-file-atomic "^4.0.0" +bin-links@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.3.tgz#9e4a3c5900830aee3d7f52178b65e01dcdde64a5" + integrity sha512-obsRaULtJurnfox/MDwgq6Yo9kzbv1CPTk/1/s7Z/61Lezc8IKkFCOXNeVLXz0456WRzBQmSsDWlai2tIhBsfA== + dependencies: + cmd-shim "^6.0.0" + npm-normalize-package-bin "^3.0.0" + read-cmd-shim "^4.0.0" + write-file-atomic "^5.0.0" + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== -binary-extensions@^2.0.0, binary-extensions@^2.2.0: +binary-extensions@^2.0.0, binary-extensions@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== @@ -8813,9 +8905,9 @@ builtins@^1.0.3: integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ== builtins@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + version "5.1.0" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== dependencies: semver "^7.0.0" @@ -8846,29 +8938,23 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@^15.0.3, cacache@^15.0.5, cacache@^15.2.0, cacache@^15.3.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== +cacache@*, cacache@^18.0.0: + version "18.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.2.tgz#fd527ea0f03a603be5c0da5805635f8eef00c60c" + integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" + minipass-pipeline "^1.2.4" p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: version "16.1.3" @@ -8894,24 +8980,6 @@ cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" -cacache@^18.0.0: - version "18.0.2" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.2.tgz#fd527ea0f03a603be5c0da5805635f8eef00c60c" - integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== - dependencies: - "@npmcli/fs" "^3.1.0" - fs-minipass "^3.0.0" - glob "^10.2.2" - lru-cache "^10.0.1" - minipass "^7.0.3" - minipass-collect "^2.0.1" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - p-map "^4.0.0" - ssri "^10.0.0" - tar "^6.1.11" - unique-filename "^3.0.0" - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -9058,9 +9126,9 @@ camelcase@^7.0.0: integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001587: - version "1.0.30001599" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce" - integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA== + version "1.0.30001612" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz#d34248b4ec1f117b70b24ad9ee04c90e0b8a14ae" + integrity sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g== canonicalize@^2.0.0: version "2.0.0" @@ -9107,6 +9175,11 @@ chalk-template@0.4.0: dependencies: chalk "^4.1.2" +chalk@*, chalk@^5.0.1, chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + chalk@4.1.2, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -9148,11 +9221,6 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.0.1, chalk@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - chance@^1.1.4: version "1.1.11" resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.11.tgz#78e10e1f9220a5bbc60a83e3f28a5d8558d84d1b" @@ -9263,6 +9331,11 @@ chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.7" +chownr@*, chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + chownr@^1.1.1, chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -9283,12 +9356,17 @@ ci-info@^3.2.0, ci-info@^3.4.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -cidr-regex@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-3.1.1.tgz#ba1972c57c66f61875f18fd7dd487469770b571d" - integrity sha512-RBqYd32aDwbCMFJRL6wHOlDNYJsPNTt8vC82ErHF5vKt8QQzxm1FrkW8s/R5pVrXMf17sba09Uoy91PKiddAsw== +ci-info@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" + integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== + +cidr-regex@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-4.0.5.tgz#c90181992feb60ce28b8cc7590970ab94ab1060a" + integrity sha512-gljhROSwEnEvC+2lKqfkv1dU2v46h8Cwob19LlfGeGRMDLuwFD5+3D6+/vaa9/QrVLDASiSQ2OYQwzzjQ5I57A== dependencies: - ip-regex "^4.1.0" + ip-regex "^5.0.0" cids@^0.7.1: version "0.7.5" @@ -9372,13 +9450,13 @@ cli-boxes@^3.0.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== -cli-columns@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e" - integrity sha512-iQYpDgpPPmCjn534ikQOhi+ydP6uMar+DtJ6a0In4aGL/PKqWfao75s6eF81quQQaz7isGz+goNECLARRZswdg== +cli-columns@*: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-4.0.0.tgz#9fe4d65975238d55218c41bd2ed296a7fa555646" + integrity sha512-XW2Vg+w+L9on9wtwKpyzluIPCWXjaBahI7mTcYjx+BVIYD9c3yqcv/yKC7CmdCZat4rq2yiE1UMSJC5ivKfMtQ== dependencies: - string-width "^2.0.0" - strip-ansi "^3.0.1" + string-width "^4.2.3" + strip-ansi "^6.0.1" cli-cursor@3.1.0, cli-cursor@^3.1.0: version "3.1.0" @@ -9404,10 +9482,10 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== -cli-table3@^0.6.0, cli-table3@~0.6.0, cli-table3@~0.6.1: - version "0.6.3" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" - integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== +cli-table3@*, cli-table3@^0.6.0, cli-table3@~0.6.0, cli-table3@~0.6.1: + version "0.6.4" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.4.tgz#d1c536b8a3f2e7bec58f67ac9e5769b1b30088b0" + integrity sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw== dependencies: string-width "^4.2.0" optionalDependencies: @@ -9537,13 +9615,6 @@ clsx@^1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -cmd-shim@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" - integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== - dependencies: - mkdirp-infer-owner "^2.0.0" - cmd-shim@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-5.0.0.tgz#8d0aaa1a6b0708630694c4dbde070ed94c707724" @@ -9551,6 +9622,11 @@ cmd-shim@^5.0.0: dependencies: mkdirp-infer-owner "^2.0.0" +cmd-shim@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.2.tgz#435fd9e5c95340e61715e19f90209ed6fcd9e0a4" + integrity sha512-+FFYbB0YLaAkhkcrjkyNLYDiOsFSfRjwjY19LXk/psmMx1z00xlCv7hhQoTGXXIKi+YXHL/iiFo8NqMVQX9nOw== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -9606,7 +9682,7 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.2, color-support@^1.1.3: +color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== @@ -9621,7 +9697,7 @@ colors@1.4.0, colors@^1.4.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -columnify@^1.6.0: +columnify@*, columnify@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== @@ -9629,14 +9705,6 @@ columnify@^1.6.0: strip-ansi "^6.0.1" wcwidth "^1.0.0" -columnify@~1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - integrity sha512-rFl+iXVT1nhLQPfGDw+3WcS8rmm7XsLKUmhsGE3ihzzpIikeGrTaZPIRKYWeLsLBypsHzjXIvYEltVUZS84XxQ== - dependencies: - strip-ansi "^3.0.0" - wcwidth "^1.0.0" - combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -9794,6 +9862,11 @@ concurrently@^7.4.0: tree-kill "^1.2.2" yargs "^17.3.1" +confbox@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" + integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== + config-chain@^1.1.12: version "1.1.13" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" @@ -9849,7 +9922,7 @@ console-browserify@^1.2.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: +console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== @@ -10002,9 +10075,9 @@ convert-source-map@^2.0.0: integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie-es@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.0.0.tgz#4759684af168dfc54365b2c2dda0a8d7ee1e4865" - integrity sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.1.0.tgz#68f8d9f48aeb5a534f3896f80e792760d3d20def" + integrity sha512-L2rLOcK0wzWSfSDA33YR+PUHDG10a8px7rUHKWbGLP4YfbsMed2KFUw5fczvDPbT98DDe3LEzviswl810apTEw== cookie-signature@1.0.6: version "1.0.6" @@ -10046,16 +10119,16 @@ copy-webpack-plugin@^10.2.4: serialize-javascript "^6.0.0" core-js-compat@^3.31.0, core-js-compat@^3.36.1: - version "3.36.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.36.1.tgz#1818695d72c99c25d621dca94e6883e190cea3c8" - integrity sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA== + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.0.tgz#d9570e544163779bb4dff1031c7972f44918dc73" + integrity sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA== dependencies: browserslist "^4.23.0" core-js-pure@^3.30.2: - version "3.36.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.36.1.tgz#1461c89e76116528b54eba20a0aff30164087a94" - integrity sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA== + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.37.0.tgz#ce99fb4a7cec023fdbbe5b5bd1f06bbcba83316e" + integrity sha512-d3BrpyFr5eD4KcbRvQ3FTUx/KWmaDesr7+a3+1+P46IUnNoEt+oiLijPINZMEon7w9oGkIINWxrBAU9DEciwFQ== core-js@^2.4.0, core-js@^2.5.0: version "2.6.12" @@ -10063,9 +10136,9 @@ core-js@^2.4.0, core-js@^2.5.0: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.6.4, core-js@^3.6.5: - version "3.36.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.36.1.tgz#c97a7160ebd00b2de19e62f4bbd3406ab720e578" - integrity sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA== + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.0.tgz#d8dde58e91d156b2547c19d8a4efd5c7f6c426bb" + integrity sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug== core-util-is@1.0.2: version "1.0.2" @@ -10171,6 +10244,13 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-fetch@3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + cross-fetch@^2.1.0, cross-fetch@^2.1.1: version "2.2.6" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" @@ -10283,6 +10363,11 @@ css-what@^6.0.1, css-what@^6.1.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + csso@^5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" @@ -10367,9 +10452,9 @@ cypress-watch-and-reload@^1.10.3: ws "8.16.0" cypress@*: - version "13.7.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.7.0.tgz#19e53c0bd6eca5e3bde0d6ac9e98fbf1782e3a9e" - integrity sha512-UimjRSJJYdTlvkChcdcfywKJ6tUYuwYuk/n1uMMglrvi+ZthNhoRYcxnWgTqUtkl17fXrPAsD5XT2rcQYN1xKA== + version "13.8.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.8.0.tgz#118e94161334e03841714c9b9b3600ae853c11f9" + integrity sha512-Qau//mtrwEGOU9cn2YjavECKyDUwBh8J2tit+y9s1wsv6C3BX+rlv6I9afmQnL8PmEEzJ6be7nppMHacFzZkTw== dependencies: "@cypress/request" "^3.0.0" "@cypress/xvfb" "^1.2.4" @@ -10769,9 +10854,9 @@ dedent@^0.7.0: integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-equal@^2.0.5: version "2.2.3" @@ -10969,7 +11054,7 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destr@^2.0.1, destr@^2.0.3: +destr@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ== @@ -11057,7 +11142,7 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.0.0: +diff@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== @@ -11334,16 +11419,16 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== ejs@^3.1.7: - version "3.1.9" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" - integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== dependencies: jake "^10.8.5" electron-to-chromium@^1.3.47, electron-to-chromium@^1.4.668: - version "1.4.711" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.711.tgz#f9fd04007878cc27ac327d5c6ce300f8b516f635" - integrity sha512-hRg81qzvUEibX2lDxnFlVCHACa+LtrCPIsWAxo161LDYIB3jauf57RGsMZV9mvGwE98yGH06icj3zBEoOkxd/w== + version "1.4.746" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.746.tgz#787213e75f6c7bccb55dfe8b68170555c548d093" + integrity sha512-jeWaIta2rIG2FzHaYIhSuVWqC6KJYo7oSBX4Jv7g+aVujKztfvdpf+n6MGwZdC5hQXbax4nntykLH2juIQrfPg== elliptic@6.5.2: version "6.5.2" @@ -11429,7 +11514,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encoding@^0.1.11, encoding@^0.1.12, encoding@^0.1.13: +encoding@^0.1.11, encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -11483,9 +11568,9 @@ env-paths@^2.2.0: integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== envinfo@^7.7.4, envinfo@^7.8.1: - version "7.11.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.1.tgz#2ffef77591057081b0129a8fd8cf6118da1b94e1" - integrity sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg== + version "7.12.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.12.0.tgz#b56723b39c2053d67ea5714f026d05d4f5cc7acd" + integrity sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg== err-code@^2.0.2: version "2.0.3" @@ -11511,57 +11596,10 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" - integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.1" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.0" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.5" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.14" - -es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2: - version "1.23.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.2.tgz#693312f3940f967b8dd3eebacb590b01712622e0" - integrity sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" @@ -11602,11 +11640,11 @@ es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2: safe-regex-test "^1.0.3" string.prototype.trim "^1.2.9" string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.7" + string.prototype.trimstart "^1.0.8" typed-array-buffer "^1.0.2" typed-array-byte-length "^1.0.1" typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.5" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" which-typed-array "^1.1.15" @@ -11761,6 +11799,21 @@ esbuild-node-builtins@^0.1.0: util "^0.12.3" vm-browserify "^1.1.2" +esbuild-node-externals@^1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/esbuild-node-externals/-/esbuild-node-externals-1.13.0.tgz#adad097c1d45a373cc2226b76408ba095a5c1c62" + integrity sha512-EAd32LMfUajIbLZphERyDVltTn/jir55B40xND5ro6VpCiv5/pum+s51cQf3LBFSVgEFznVJYMJtfVCJiSb32w== + dependencies: + find-up "^5.0.0" + tslib "^2.4.1" + +esbuild-plugin-tsc@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/esbuild-plugin-tsc/-/esbuild-plugin-tsc-0.4.0.tgz#d7d516fda0e0b05c8e0b442152deebdee01ddc61" + integrity sha512-q9gWIovt1nkwchMLc2zhyksaiHOv3kDK4b0AUol8lkMCRhJ1zavgfb2fad6BKp7FT9rh/OHmEBXVjczLoi/0yw== + dependencies: + strip-comments "^2.0.1" + esbuild@0.19.12: version "0.19.12" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" @@ -11903,13 +11956,20 @@ eslint-plugin-chai-friendly@^0.7.2: resolved "https://registry.yarnpkg.com/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.4.tgz#eaf222b848673ef8a00b8e507f7c6fd83d036bf2" integrity sha512-PGPjJ8diYgX1mjLxGJqRop2rrGwZRKImoEOwUOgoIhg0p80MkTaqvmFLe5TF7/iagZHggasvIfQlUyHIhK/PYg== -eslint-plugin-cypress@2.15.1, eslint-plugin-cypress@^2.11.3, eslint-plugin-cypress@^2.12.1: +eslint-plugin-cypress@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz#336afa7e8e27451afaf65aa359c9509e0a4f3a7b" integrity sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w== dependencies: globals "^13.20.0" +eslint-plugin-cypress@^2.11.3, eslint-plugin-cypress@^2.12.1: + version "2.15.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz#f22e12fad4c434edad7b298ef92bac8fa087ffa0" + integrity sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ== + dependencies: + globals "^13.20.0" + eslint-plugin-es@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" @@ -12596,11 +12656,11 @@ ethereum-abi-types-generator@^1.3.2: yargs "^15.3.1" ethereum-bloom-filters@^1.0.6: - version "1.0.10" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" - integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.1.0.tgz#b3fc1eb789509ee30db0bf99a2988ccacb8d0397" + integrity sha512-J1gDRkLpuGNvWYzWslBQR9cDV4nd4kfvVTE/Wy4Kkm4yb3EYRSlyi0eB/inTsSTTVyA0+HyzHgbr95Fn/Z1fSw== dependencies: - js-sha3 "^0.8.0" + "@noble/hashes" "^1.4.0" ethereum-common@0.2.0: version "0.2.0" @@ -12898,7 +12958,7 @@ ethers@^4.0.32, ethers@^4.0.45, ethers@^4.0.47: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.0.13, ethers@^5.1.4, ethers@^5.7.1, ethers@^5.7.2: +ethers@^5.0.13, ethers@^5.1.4, ethers@^5.7.1, ethers@^5.7.2, "ethersv5@npm:ethers@^5.0.32": version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -12943,42 +13003,6 @@ etherscan-api@^10.2.0: gh-pages "4.0.0" querystring "0.2.1" -"ethersv5@npm:ethers@^5.0.32": - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -13151,9 +13175,9 @@ exponential-backoff@^3.1.1: integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== express@^4.14.0, express@^4.17.3, express@^4.18.2: - version "4.19.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.0.tgz#c9f689a62522f3399132d49eacd9af177d8ccb9e" - integrity sha512-/ERliX0l7UuHEgAy7HU2FRsiz3ScIKNl/iwnoYzHTJC0Sqj3ctWDD3MQ9CbUEfjshvxXImWaeukD0Xo7a2lWLA== + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== dependencies: accepts "~1.3.8" array-flatten "1.1.1" @@ -13346,7 +13370,7 @@ fast-url-parser@1.1.3, fast-url-parser@^1.1.3: dependencies: punycode "^1.3.2" -fastest-levenshtein@^1.0.12: +fastest-levenshtein@*: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== @@ -13900,21 +13924,6 @@ g@^2.0.1: resolved "https://registry.yarnpkg.com/g/-/g-2.0.1.tgz#0b5963ebd0ca70e3bc8c6766934a021821c8b857" integrity sha512-Fi6Ng5fZ/ANLQ15H11hCe+09sgUoNvDEBevVgx3KoYOhsH5iLNPn54hx0jPZ+3oSWr+xajnp2Qau9VmPsc7hTA== -gauge@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" - integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - gauge@^4.0.3: version "4.0.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" @@ -13929,19 +13938,19 @@ gauge@^4.0.3: strip-ansi "^6.0.1" wide-align "^1.1.5" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== +gauge@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-5.0.1.tgz#1efc801b8ff076b86ef3e9a7a280a975df572112" + integrity sha512-CmykPMJGuNan/3S4kZOpvvPYSNqSHANiWnh9XcMU2pSjtBfF0XzZ2p1bFAxTbnFxyBuPxQYHhzwaoOmUdqzvxQ== dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^4.0.1" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -14179,6 +14188,17 @@ glob-slasher@^1.0.1: lodash.isobject "^2.4.1" toxic "^1.0.0" +glob@*, glob@^10.2.2, glob@^10.3.10, glob@^10.3.7: + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -14203,17 +14223,6 @@ glob@7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^10.2.2, glob@^10.3.10: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0, glob@~7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -14422,7 +14431,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.8, graceful-fs@^4.2.9: +graceful-fs@*, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -14546,7 +14555,7 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" -has-unicode@^2.0.0, has-unicode@^2.0.1: +has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== @@ -14709,6 +14718,13 @@ hook-std@^2.0.0: resolved "https://registry.yarnpkg.com/hook-std/-/hook-std-2.0.0.tgz#ff9aafdebb6a989a354f729bb6445cf4a3a7077c" integrity sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g== +hosted-git-info@*, hosted-git-info@^7.0.0, hosted-git-info@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" + integrity sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA== + dependencies: + lru-cache "^10.0.1" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -14721,7 +14737,7 @@ hosted-git-info@^3.0.6: dependencies: lru-cache "^6.0.0" -hosted-git-info@^4.0.0, hosted-git-info@^4.0.1, hosted-git-info@^4.0.2: +hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== @@ -14735,13 +14751,6 @@ hosted-git-info@^5.0.0: dependencies: lru-cache "^7.5.1" -hosted-git-info@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" - integrity sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA== - dependencies: - lru-cache "^10.0.1" - hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -15094,13 +15103,6 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== -ignore-walk@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" - integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== - dependencies: - minimatch "^3.0.4" - ignore-walk@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" @@ -15108,6 +15110,13 @@ ignore-walk@^5.0.1: dependencies: minimatch "^5.0.1" +ignore-walk@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9" + integrity sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw== + dependencies: + minimatch "^9.0.0" + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -15189,12 +15198,17 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +ini@*, ini@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.2.tgz#7f646dbd9caea595e61f88ef60bfff8b01f8130a" + integrity sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw== + ini@1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== -ini@2.0.0, ini@^2.0.0: +ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== @@ -15204,18 +15218,18 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -init-package-json@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.5.tgz#78b85f3c36014db42d8f32117252504f68022646" - integrity sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA== +init-package-json@*: + version "6.0.2" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-6.0.2.tgz#0d780b752dd1dd83b8649945df38a07df4f990a6" + integrity sha512-ZQ9bxt6PkqIH6fPU69HPheOMoUqIqVqwZj0qlCBfoSCG4lplQhVM/qB3RS4f0RALK3WZZSrNQxNtCZgphuf3IA== dependencies: - npm-package-arg "^8.1.5" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "^4.1.1" + "@npmcli/package-json" "^5.0.0" + npm-package-arg "^11.0.0" + promzard "^1.0.0" + read "^3.0.1" semver "^7.3.5" validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" + validate-npm-package-name "^5.0.0" init-package-json@^3.0.2: version "3.0.2" @@ -15343,10 +15357,10 @@ ip-address@^9.0.5: jsbn "1.1.0" sprintf-js "^1.1.3" -ip-regex@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" - integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== +ip-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-5.0.0.tgz#cd313b2ae9c80c07bd3851e12bf4fa4dc5480632" + integrity sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw== ipaddr.js@1.9.1: version "1.9.1" @@ -15354,14 +15368,14 @@ ipaddr.js@1.9.1: integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" - integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== iron-webcrypto@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.1.0.tgz#f902f0cdbd77554b2195ecbb65558c311b01edfd" - integrity sha512-5vgYsCakNlaQub1orZK5QmNYhwYtcllTkZBp5sfIaCqY93Cf6l+v2rtE+E4TMbcfjxDMCdrO8wmp7+ZvhDECLA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.1.1.tgz#245c9d467075ee810343ddfa53dd4909616aaf33" + integrity sha512-5xGwQUWHQSy039rFr+5q/zOmj7GP0Ypzvo34Ep+61bPIhaLduEDp/PvLGlU3awD2mzWUR0weN2vJ1mILydFPEg== is-accessor-descriptor@^1.0.1: version "1.0.1" @@ -15463,12 +15477,12 @@ is-ci@^3.0.0, is-ci@^3.0.1: dependencies: ci-info "^3.2.0" -is-cidr@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-4.0.2.tgz#94c7585e4c6c77ceabf920f8cde51b8c0fda8814" - integrity sha512-z4a1ENUajDbEl/Q6/pVBpTR1nBjjEE1X7qb7bmWYanNnPoKAvUCPFKeXV6Fe4mgTkWKBqiHIcwsI3SndiO5FeA== +is-cidr@*: + version "5.0.5" + resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-5.0.5.tgz#6898e3e84a320cecaa505654b33463399baf9e8e" + integrity sha512-zDlCvz2v8dBpumuGD4/fc7wzFKY6UYOvFW29JWSstdJoByGN3TKwS0tFA9VWc7DM01VOVOn/DaR84D8Mihp9Rg== dependencies: - cidr-regex "^3.1.1" + cidr-regex "^4.0.4" is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.6.0, is-core-module@^2.8.1: version "2.13.1" @@ -16125,7 +16139,7 @@ iterator.prototype@^1.1.2: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" -jackspeak@^2.3.5: +jackspeak@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== @@ -16869,9 +16883,9 @@ jiti@^1.21.0: integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== joi@^17.7.0: - version "17.12.2" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.12.2.tgz#283a664dabb80c7e52943c557aab82faea09f521" - integrity sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw== + version "17.13.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.0.tgz#b6f340b8029ee7af2397f821d17a4f03bf34b043" + integrity sha512-9qcrTyoBmFZRNHeVP4edKqIUEgFzq7MHvTNSDuHSqkpOPtiBkgNgcmTSqmiw1kw9tdKaiddvIDv/eCJDxmqWCA== dependencies: "@hapi/hoek" "^9.3.0" "@hapi/topo" "^5.1.0" @@ -17006,6 +17020,11 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-parse-even-better-errors@*, json-parse-even-better-errors@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz#02bb29fb5da90b5444581749c22cedd3597c6cb0" + integrity sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg== + json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -17201,26 +17220,21 @@ jszip@^3.10.1: readable-stream "~2.3.6" setimmediate "^1.0.5" -just-diff-apply@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-3.1.2.tgz#710d8cda00c65dc4e692df50dbe9bac5581c2193" - integrity sha512-TCa7ZdxCeq6q3Rgms2JCRHTCfWAETPZ8SzYUbkYF6KR3I03sN29DaOIC+xyWboIcMvjAsD5iG2u/RWzHD8XpgQ== - just-diff-apply@^5.2.0: version "5.5.0" resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.5.0.tgz#771c2ca9fa69f3d2b54e7c3f5c1dfcbcc47f9f0f" integrity sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw== -just-diff@^3.0.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-3.1.1.tgz#d50c597c6fd4776495308c63bdee1b6839082647" - integrity sha512-sdMWKjRq8qWZEjDcVA6llnUT8RDEBIfOiGpYFPYa9u+2c39JCsejktSP7mj5eRid5EIvTzIpQ2kDOCw1Nq9BjQ== - just-diff@^5.0.1: version "5.2.0" resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241" integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw== +just-diff@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-6.0.2.tgz#03b65908543ac0521caf6d8eb85035f7d27ea285" + integrity sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA== + keccak@^1.0.2: version "1.4.0" resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" @@ -17428,15 +17442,13 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libnpmaccess@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" - integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== +libnpmaccess@*: + version "8.0.3" + resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-8.0.3.tgz#7377b2fa07f722cb68a29e1e31f19972cf01f5e0" + integrity sha512-0dU2ZZ8eWrI3JcPIEA5wnQ5s+OGeNtjrg0MHz1vcs06hRLDhZeXBWthuXG47jV1GO5ogClQi7RAFNAWVEjViWw== dependencies: - aproba "^2.0.0" - minipass "^3.1.1" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" + npm-package-arg "^11.0.1" + npm-registry-fetch "^16.2.0" libnpmaccess@^6.0.3: version "6.0.4" @@ -17448,79 +17460,84 @@ libnpmaccess@^6.0.3: npm-package-arg "^9.0.1" npm-registry-fetch "^13.0.0" -libnpmdiff@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/libnpmdiff/-/libnpmdiff-2.0.4.tgz#bb1687992b1a97a8ea4a32f58ad7c7f92de53b74" - integrity sha512-q3zWePOJLHwsLEUjZw3Kyu/MJMYfl4tWCg78Vl6QGSfm4aXBUSVzMzjJ6jGiyarsT4d+1NH4B1gxfs62/+y9iQ== - dependencies: - "@npmcli/disparity-colors" "^1.0.1" - "@npmcli/installed-package-contents" "^1.0.7" - binary-extensions "^2.2.0" - diff "^5.0.0" - minimatch "^3.0.4" - npm-package-arg "^8.1.1" - pacote "^11.3.0" - tar "^6.1.0" - -libnpmexec@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/libnpmexec/-/libnpmexec-2.0.1.tgz#729ae3e15a3ba225964ccf248117a75d311eeb73" - integrity sha512-4SqBB7eJvJWmUKNF42Q5qTOn20DRjEE4TgvEh2yneKlAiRlwlhuS9MNR45juWwmoURJlf2K43bozlVt7OZiIOw== - dependencies: - "@npmcli/arborist" "^2.3.0" - "@npmcli/ci-detect" "^1.3.0" - "@npmcli/run-script" "^1.8.4" - chalk "^4.1.0" - mkdirp-infer-owner "^2.0.0" - npm-package-arg "^8.1.2" - pacote "^11.3.1" - proc-log "^1.0.0" - read "^1.0.7" - read-package-json-fast "^2.0.2" - walk-up-path "^1.0.0" +libnpmdiff@*: + version "6.0.9" + resolved "https://registry.yarnpkg.com/libnpmdiff/-/libnpmdiff-6.0.9.tgz#7a8a1bfd5209342e852c5ee65d604b57a6c19dbe" + integrity sha512-K3Ey7VFXkasHOHa9S8SbALRMMEJkx5cHdAitJoLZH4pPL2cX89hdkNTQi8vcvjOlENbE2AjNsSjRkGhzeKfiSA== + dependencies: + "@npmcli/arborist" "^7.2.1" + "@npmcli/disparity-colors" "^3.0.0" + "@npmcli/installed-package-contents" "^2.0.2" + binary-extensions "^2.3.0" + diff "^5.1.0" + minimatch "^9.0.4" + npm-package-arg "^11.0.1" + pacote "^17.0.4" + tar "^6.2.1" + +libnpmexec@*: + version "7.0.10" + resolved "https://registry.yarnpkg.com/libnpmexec/-/libnpmexec-7.0.10.tgz#dd41dddaf5987a59e067e686d10b5189a9302065" + integrity sha512-MwjY0SzG9pHBMW+Otl/6ZA2s4kRUYxelo9vIKeWHG3CV0b/4mzi88rYNk3fv46hQ4ypIIEZYOzV/pHky/DS8og== + dependencies: + "@npmcli/arborist" "^7.2.1" + "@npmcli/run-script" "^7.0.2" + ci-info "^4.0.0" + npm-package-arg "^11.0.1" + npmlog "^7.0.1" + pacote "^17.0.4" + proc-log "^3.0.0" + read "^3.0.1" + read-package-json-fast "^3.0.2" + semver "^7.3.7" + walk-up-path "^3.0.1" -libnpmfund@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/libnpmfund/-/libnpmfund-1.1.0.tgz#ee91313905b3194b900530efa339bc3f9fc4e5c4" - integrity sha512-Kfmh3pLS5/RGKG5WXEig8mjahPVOxkik6lsbH4iX0si1xxNi6eeUh/+nF1MD+2cgalsQif3O5qyr6mNz2ryJrQ== +libnpmfund@*: + version "5.0.7" + resolved "https://registry.yarnpkg.com/libnpmfund/-/libnpmfund-5.0.7.tgz#0ac10dc7e554f3ba596089557d6f2dd6a35664b1" + integrity sha512-wRQSh2AeXFUtfHBciYha7m2+0xhX9PWa+ufMlfUFtUm6yTNsgghoZe8dciERklwhh2iax/9I+O/1lqKsGvJBaQ== dependencies: - "@npmcli/arborist" "^2.5.0" + "@npmcli/arborist" "^7.2.1" -libnpmhook@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-6.0.3.tgz#1d7f0d7e6a7932fbf7ce0881fdb0ed8bf8748a30" - integrity sha512-3fmkZJibIybzmAvxJ65PeV3NzRc0m4xmYt6scui5msocThbEp4sKFT80FhgrCERYDjlUuFahU6zFNbJDHbQ++g== +libnpmhook@*: + version "10.0.2" + resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-10.0.2.tgz#1528c6c8120bf97523bc1671dc49b48b96170c89" + integrity sha512-LF5peX3rmk2HqABmMXWhjdJ+HHHPIwMz7NXUM67MLSIy+JAExTymcQZgbGM9m/YQ6JDRPW8SBhWeWM0+vPNezw== dependencies: aproba "^2.0.0" - npm-registry-fetch "^11.0.0" + npm-registry-fetch "^16.2.0" -libnpmorg@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-2.0.3.tgz#4e605d4113dfa16792d75343824a0625c76703bc" - integrity sha512-JSGl3HFeiRFUZOUlGdiNcUZOsUqkSYrg6KMzvPZ1WVZ478i47OnKSS0vkPmX45Pai5mTKuwIqBMcGWG7O8HfdA== +libnpmorg@*: + version "6.0.3" + resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-6.0.3.tgz#6c2af127fc54e965800c53ace0b3e6e55a8a2d21" + integrity sha512-oxyQjJqvhvi0YqCOHQWLfWWre7NtWOGghX29LhhaqcDv3+Q61c4lJbht/iEEd00eucuHPjqfeh4aWXP6ftj2aA== dependencies: aproba "^2.0.0" - npm-registry-fetch "^11.0.0" + npm-registry-fetch "^16.2.0" -libnpmpack@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/libnpmpack/-/libnpmpack-2.0.1.tgz#d3eac25cc8612f4e7cdeed4730eee339ba51c643" - integrity sha512-He4/jxOwlaQ7YG7sIC1+yNeXeUDQt8RLBvpI68R3RzPMZPa4/VpxhlDo8GtBOBDYoU8eq6v1wKL38sq58u4ibQ== +libnpmpack@*: + version "6.0.9" + resolved "https://registry.yarnpkg.com/libnpmpack/-/libnpmpack-6.0.9.tgz#c1e42cef93d46c9f31e015c298232fff15bbb734" + integrity sha512-rkGVbP0amt7qNPL/u4NbH0MqhECRrvdRPcszXalYc6TP2ubEBPT54c5LFLxTLROSKjfre6PVvzc1ZNKc8jBWhQ== dependencies: - "@npmcli/run-script" "^1.8.3" - npm-package-arg "^8.1.0" - pacote "^11.2.6" + "@npmcli/arborist" "^7.2.1" + "@npmcli/run-script" "^7.0.2" + npm-package-arg "^11.0.1" + pacote "^17.0.4" -libnpmpublish@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" - integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== +libnpmpublish@*: + version "9.0.5" + resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-9.0.5.tgz#39e06b94fa140ae733e7ad0cdbbdc385ab31728e" + integrity sha512-MSKHZN2NXmp8GafDMy2eH/FK6c0BjpCbuJ4vJU4xPqCguy0w805VoRnsCwxyrvzCC13MB2tU6VOAX08GioINBA== dependencies: - normalize-package-data "^3.0.2" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - semver "^7.1.3" - ssri "^8.0.1" + ci-info "^4.0.0" + normalize-package-data "^6.0.0" + npm-package-arg "^11.0.1" + npm-registry-fetch "^16.2.0" + proc-log "^3.0.0" + semver "^7.3.7" + sigstore "^2.2.0" + ssri "^10.0.5" libnpmpublish@^6.0.4: version "6.0.5" @@ -17533,31 +17550,31 @@ libnpmpublish@^6.0.4: semver "^7.3.7" ssri "^9.0.0" -libnpmsearch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-3.1.2.tgz#aee81b9e4768750d842b627a3051abc89fdc15f3" - integrity sha512-BaQHBjMNnsPYk3Bl6AiOeVuFgp72jviShNBw5aHaHNKWqZxNi38iVNoXbo6bG/Ccc/m1To8s0GtMdtn6xZ1HAw== +libnpmsearch@*: + version "7.0.2" + resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-7.0.2.tgz#d088934c720179513baca0d8cccaddcf0da76e49" + integrity sha512-SvYcq3SmexQWhch1i/9ML+vQx82+thVMRvgtZc/Yjf6s0Cfu/87ZQ3bb6jFe/whwaXxjwdDX8MrdmNXNKG+JPA== dependencies: - npm-registry-fetch "^11.0.0" + npm-registry-fetch "^16.2.0" -libnpmteam@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-2.0.4.tgz#9dbe2e18ae3cb97551ec07d2a2daf9944f3edc4c" - integrity sha512-FPrVJWv820FZFXaflAEVTLRWZrerCvfe7ZHSMzJ/62EBlho2KFlYKjyNEsPW3JiV7TLSXi3vo8u0gMwIkXSMTw== +libnpmteam@*: + version "6.0.2" + resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-6.0.2.tgz#f83cf778785b89cdbf463dd6025669c0df2aa06b" + integrity sha512-EUTKCj1PmstpZE/MJ8QVs9L6wi4lMzD7TPyxHXiXWSsUy0/a1gKysW8TjC9dIAMVb/3okUUxiP/LIRwdShBpAQ== dependencies: aproba "^2.0.0" - npm-registry-fetch "^11.0.0" + npm-registry-fetch "^16.2.0" -libnpmversion@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/libnpmversion/-/libnpmversion-1.2.1.tgz#689aa7fe0159939b3cbbf323741d34976f4289e9" - integrity sha512-AA7x5CFgBFN+L4/JWobnY5t4OAHjQuPbAwUYJ7/NtHuyLut5meb+ne/aj0n7PWNiTGCJcRw/W6Zd2LoLT7EZuQ== +libnpmversion@*: + version "5.0.2" + resolved "https://registry.yarnpkg.com/libnpmversion/-/libnpmversion-5.0.2.tgz#aea7b09bc270c778cbc8be7bf02e4b60566989cf" + integrity sha512-6JBnLhd6SYgKRekJ4cotxpURLGbEtKxzw+a8p5o+wNwrveJPMH8yW/HKjeewyHzWmxzzwn9EQ3TkF2onkrwstA== dependencies: - "@npmcli/git" "^2.0.7" - "@npmcli/run-script" "^1.8.4" - json-parse-even-better-errors "^2.3.1" - semver "^7.3.5" - stringify-package "^1.0.1" + "@npmcli/git" "^5.0.3" + "@npmcli/run-script" "^7.0.2" + json-parse-even-better-errors "^3.0.0" + proc-log "^3.0.0" + semver "^7.3.7" libsodium-wrappers@^0.7.6: version "0.7.13" @@ -18006,7 +18023,7 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -lru-cache@^10.0.1, lru-cache@^10.2.0, "lru-cache@^9.1.1 || ^10.0.0": +lru-cache@^10.0.1, lru-cache@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== @@ -18079,29 +18096,7 @@ make-error@1.x, make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@^10.0.3, make-fetch-happen@^10.0.6: - version "10.2.1" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" - integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== - dependencies: - agentkeepalive "^4.2.1" - cacache "^16.1.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^7.7.1" - minipass "^3.1.6" - minipass-collect "^1.0.2" - minipass-fetch "^2.0.3" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.3" - promise-retry "^2.0.1" - socks-proxy-agent "^7.0.0" - ssri "^9.0.0" - -make-fetch-happen@^13.0.0: +make-fetch-happen@*, make-fetch-happen@^13.0.0: version "13.0.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== @@ -18118,27 +18113,27 @@ make-fetch-happen@^13.0.0: promise-retry "^2.0.1" ssri "^10.0.0" -make-fetch-happen@^9.0.1, make-fetch-happen@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== +make-fetch-happen@^10.0.3, make-fetch-happen@^10.0.6: + version "10.2.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" + integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" + agentkeepalive "^4.2.1" + cacache "^16.1.0" http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" + http-proxy-agent "^5.0.0" https-proxy-agent "^5.0.0" is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" + lru-cache "^7.7.1" + minipass "^3.1.6" minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" + minipass-fetch "^2.0.3" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" - negotiator "^0.6.2" + negotiator "^0.6.3" promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" + socks-proxy-agent "^7.0.0" + ssri "^9.0.0" makeerror@1.0.12: version "1.0.12" @@ -18440,7 +18435,7 @@ minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch dependencies: brace-expansion "^1.1.7" -minimatch@9.0.3, minimatch@^9.0.1: +minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -18461,6 +18456,13 @@ minimatch@^7.1.3: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -18489,17 +18491,6 @@ minipass-collect@^2.0.1: dependencies: minipass "^7.0.3" -minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - minipass-fetch@^2.0.3: version "2.1.2" resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add" @@ -18537,7 +18528,7 @@ minipass-json-stream@^1.0.1: jsonparse "^1.3.1" minipass "^3.0.0" -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: +minipass-pipeline@*, minipass-pipeline@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== @@ -18551,6 +18542,11 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" +minipass@*, "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -18559,7 +18555,7 @@ minipass@^2.6.0, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: +minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== @@ -18571,11 +18567,6 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3: - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - minizlib@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" @@ -18583,7 +18574,7 @@ minizlib@^1.3.3: dependencies: minipass "^2.9.0" -minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: +minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -18591,6 +18582,14 @@ minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" +minizlib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012" + integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== + dependencies: + minipass "^7.0.4" + rimraf "^5.0.5" + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -18604,7 +18603,7 @@ mkdirp-classic@^0.5.2: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp-infer-owner@^2.0.0: +mkdirp-infer-owner@*, mkdirp-infer-owner@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== @@ -18620,7 +18619,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*: +mkdirp@*, mkdirp@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== @@ -18637,7 +18636,7 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.2.0, mlly@^1.6.1: +mlly@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.6.1.tgz#0983067dc3366d6314fc5e12712884e6978d028f" integrity sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA== @@ -18697,6 +18696,11 @@ mri@^1.2.0: resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== +ms@*, ms@2.1.3, ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -18707,11 +18711,6 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - multibase@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" @@ -18796,6 +18795,11 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + nan@^2.12.1, nan@^2.14.0, nan@^2.18.0, nan@^2.2.1: version "2.19.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" @@ -18858,7 +18862,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: +negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -18942,10 +18946,15 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-fetch-native@^1.4.0, node-fetch-native@^1.6.1, node-fetch-native@^1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.2.tgz#f439000d972eb0c8a741b65dcda412322955e1c6" - integrity sha512-69mtXOFZ6hSkYiXAVB5SqaRvrbITC/NPyqv7yuu/qw0nmgPyYbIMYYNIDhNtwPrzk0ptrimrLz/hhjvm4w5Z+w== +node-fetch-native@^1.6.1, node-fetch-native@^1.6.2, node-fetch-native@^1.6.3: + version "1.6.4" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" + integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== + +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" @@ -18972,10 +18981,10 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== -node-gyp@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" - integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== +node-gyp@*, node-gyp@^10.0.0, node-gyp@^10.0.1: + version "10.1.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.1.0.tgz#75e6f223f2acb4026866c26a2ead6aab75a8ca7e" + integrity sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA== dependencies: env-paths "^2.2.0" exponential-backoff "^3.1.1" @@ -18988,22 +18997,6 @@ node-gyp@^10.0.1: tar "^6.1.2" which "^4.0.0" -node-gyp@^7.1.0, node-gyp@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" - integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.3" - nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" - rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" - which "^2.0.2" - node-gyp@^9.0.0: version "9.4.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.1.tgz#8a1023e0d6766ecb52764cc3a734b36ff275e185" @@ -19076,6 +19069,13 @@ nofilter@^3.1.0: resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" integrity sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g== +nopt@*, nopt@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== + dependencies: + abbrev "^2.0.0" + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -19090,13 +19090,6 @@ nopt@^6.0.0: dependencies: abbrev "^1.0.0" -nopt@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" - integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== - dependencies: - abbrev "^2.0.0" - nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -19114,7 +19107,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: +normalize-package-data@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== @@ -19134,6 +19127,16 @@ normalize-package-data@^4.0.0: semver "^7.3.5" validate-npm-package-license "^3.0.4" +normalize-package-data@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.0.tgz#68a96b3c11edd462af7189c837b6b1064a484196" + integrity sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg== + dependencies: + hosted-git-info "^7.0.0" + is-core-module "^2.8.1" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -19165,12 +19168,10 @@ normalize-url@^6.0.0, normalize-url@^6.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== -npm-audit-report@^2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-2.1.5.tgz#a5b8850abe2e8452fce976c8960dd432981737b5" - integrity sha512-YB8qOoEmBhUH1UJgh1xFAv7Jg1d+xoNhsDYiFQlEFThEBui0W1vIz2ZK6FVg4WZjwEdl7uBQlm1jy3MUfyHeEw== - dependencies: - chalk "^4.0.0" +npm-audit-report@*: + version "5.0.0" + resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-5.0.0.tgz#83ac14aeff249484bde81eff53c3771d5048cf95" + integrity sha512-EkXrzat7zERmUhHaoren1YhTxFwsOu5jypE84k6632SXTHcQE1z8V51GC6GVZt8LxkC+tbBcKMUBZAgk8SUSbw== npm-bundled@^1.1.1: version "1.1.2" @@ -19186,10 +19187,17 @@ npm-bundled@^2.0.0: dependencies: npm-normalize-package-bin "^2.0.0" -npm-install-checks@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" - integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== +npm-bundled@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7" + integrity sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ== + dependencies: + npm-normalize-package-bin "^3.0.0" + +npm-install-checks@*, npm-install-checks@^6.0.0, npm-install-checks@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" + integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== dependencies: semver "^7.1.1" @@ -19200,7 +19208,7 @@ npm-install-checks@^5.0.0: dependencies: semver "^7.1.1" -npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: +npm-normalize-package-bin@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== @@ -19210,6 +19218,21 @@ npm-normalize-package-bin@^2.0.0: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz#9447a1adaaf89d8ad0abe24c6c84ad614a675fff" integrity sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ== +npm-normalize-package-bin@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" + integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== + +npm-package-arg@*, npm-package-arg@^11.0.0, npm-package-arg@^11.0.1: + version "11.0.2" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.2.tgz#1ef8006c4a9e9204ddde403035f7ff7d718251ca" + integrity sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw== + dependencies: + hosted-git-info "^7.0.0" + proc-log "^4.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" + npm-package-arg@11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.1.tgz#f208b0022c29240a1c532a449bdde3f0a4708ebc" @@ -19229,15 +19252,6 @@ npm-package-arg@8.1.1: semver "^7.0.0" validate-npm-package-name "^3.0.0" -npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.1, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: - version "8.1.5" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" - integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: version "9.1.2" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-9.1.2.tgz#fc8acecb00235f42270dda446f36926ddd9ac2bc" @@ -19248,16 +19262,6 @@ npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: semver "^7.3.5" validate-npm-package-name "^4.0.0" -npm-packlist@^2.1.4: - version "2.2.2" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" - integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== - dependencies: - glob "^7.1.6" - ignore-walk "^3.0.3" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - npm-packlist@^5.1.0, npm-packlist@^5.1.1: version "5.1.3" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.3.tgz#69d253e6fd664b9058b85005905012e00e69274b" @@ -19268,15 +19272,22 @@ npm-packlist@^5.1.0, npm-packlist@^5.1.1: npm-bundled "^2.0.0" npm-normalize-package-bin "^2.0.0" -npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.0, npm-pick-manifest@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" - integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== +npm-packlist@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-8.0.2.tgz#5b8d1d906d96d21c85ebbeed2cf54147477c8478" + integrity sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA== dependencies: - npm-install-checks "^4.0.0" - npm-normalize-package-bin "^1.0.1" - npm-package-arg "^8.1.2" - semver "^7.3.4" + ignore-walk "^6.0.4" + +npm-pick-manifest@*, npm-pick-manifest@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz#f87a4c134504a2c7931f2bb8733126e3c3bb7e8f" + integrity sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg== + dependencies: + npm-install-checks "^6.0.0" + npm-normalize-package-bin "^3.0.0" + npm-package-arg "^11.0.0" + semver "^7.3.5" npm-pick-manifest@^7.0.0: version "7.0.2" @@ -19288,24 +19299,27 @@ npm-pick-manifest@^7.0.0: npm-package-arg "^9.0.0" semver "^7.3.5" -npm-profile@^5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-5.0.4.tgz#73e5bd1d808edc2c382d7139049cc367ac43161b" - integrity sha512-OKtU7yoAEBOnc8zJ+/uo5E4ugPp09sopo+6y1njPp+W99P8DvQon3BJYmpvyK2Bf1+3YV5LN1bvgXRoZ1LUJBA== +npm-profile@*: + version "9.0.1" + resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-9.0.1.tgz#b0817357addb1804992bd9fed363992441847738" + integrity sha512-9o6dw5eu3tiqX1XFOXjznO73Jzin48Oyo9qAhfaEHXzeZHXpdzgDmzWruWk7uJsu5GMIsigx5hva5rB5NhfSWw== dependencies: - npm-registry-fetch "^11.0.0" + npm-registry-fetch "^16.0.0" + proc-log "^4.0.0" -npm-registry-fetch@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" - integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== +npm-registry-fetch@*, npm-registry-fetch@^16.0.0, npm-registry-fetch@^16.2.0: + version "16.2.1" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz#c367df2d770f915da069ff19fd31762f4bca3ef1" + integrity sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA== dependencies: - make-fetch-happen "^9.0.1" - minipass "^3.1.3" - minipass-fetch "^1.3.0" + "@npmcli/redact" "^1.1.0" + make-fetch-happen "^13.0.0" + minipass "^7.0.2" + minipass-fetch "^3.0.0" minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" + minizlib "^2.1.2" + npm-package-arg "^11.0.0" + proc-log "^4.0.0" npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1, npm-registry-fetch@^13.3.0: version "13.3.1" @@ -19334,10 +19348,10 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -npm-user-validate@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.1.tgz#31428fc5475fe8416023f178c0ab47935ad8c561" - integrity sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw== +npm-user-validate@*: + version "2.0.0" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-2.0.0.tgz#7b69bbbff6f7992a1d9a8968d52fd6b6db5431b6" + integrity sha512-sSWeqAYJ2dUPStJB+AEj0DyLRltr/f6YNcvCA7phkB8/RMLMnVsQ41GMwHo/ERZLYNDsyB2wPm7pZo1mqPOl7Q== npm@^7.0.0: version "7.24.2" @@ -19415,24 +19429,14 @@ npm@^7.0.0: which "^2.0.2" write-file-atomic "^3.0.3" -npmlog@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -npmlog@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" - integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== +npmlog@*, npmlog@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-7.0.1.tgz#7372151a01ccb095c47d8bf1d0771a4ff1f53ac8" + integrity sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg== dependencies: - are-we-there-yet "^2.0.0" + are-we-there-yet "^4.0.0" console-control-strings "^1.1.0" - gauge "^3.0.0" + gauge "^5.0.0" set-blocking "^2.0.0" npmlog@^6.0.0, npmlog@^6.0.2: @@ -19466,9 +19470,9 @@ number-to-bn@1.7.0: strip-hex-prefix "1.0.0" nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + version "2.2.9" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" + integrity sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg== nx-cloud@18.0.0: version "18.0.0" @@ -19745,12 +19749,13 @@ object.groupby@^1.0.1: es-abstract "^1.23.2" object.hasown@^1.0.0, object.hasown@^1.1.1, object.hasown@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" - integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== dependencies: - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.pick@^1.3.0: version "1.3.0" @@ -19781,13 +19786,13 @@ obuf@^1.0.0, obuf@^1.1.2: integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== ofetch@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.3.tgz#588cb806a28e5c66c2c47dd8994f9059a036d8c0" - integrity sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg== + version "1.3.4" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635" + integrity sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw== dependencies: - destr "^2.0.1" - node-fetch-native "^1.4.0" - ufo "^1.3.0" + destr "^2.0.3" + node-fetch-native "^1.6.3" + ufo "^1.5.3" ohash@^1.1.3: version "1.1.3" @@ -19855,7 +19860,7 @@ open@^8.0.9, open@^8.4.0, open@~8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" -opener@^1.5.1, opener@^1.5.2: +opener@*, opener@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== @@ -20163,30 +20168,29 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" -pacote@^11.1.11, pacote@^11.2.6, pacote@^11.3.0, pacote@^11.3.1, pacote@^11.3.5: - version "11.3.5" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" - integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== +pacote@*, pacote@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-18.0.0.tgz#974491c8b5a40f42830bc55361924ca7c7e45784" + integrity sha512-ma7uVt/q3Sb3XbLwUjOeClz+7feHjMOFegHn5whw++x+GzikZkAq/2auklSbRuy6EI2iJh1/ZqCpVaUcxRaeqQ== dependencies: - "@npmcli/git" "^2.1.0" - "@npmcli/installed-package-contents" "^1.0.6" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.8.2" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^2.1.4" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^11.0.0" + "@npmcli/git" "^5.0.0" + "@npmcli/installed-package-contents" "^2.0.1" + "@npmcli/promise-spawn" "^7.0.0" + "@npmcli/run-script" "^8.0.0" + cacache "^18.0.0" + fs-minipass "^3.0.0" + minipass "^7.0.2" + npm-package-arg "^11.0.0" + npm-packlist "^8.0.0" + npm-pick-manifest "^9.0.0" + npm-registry-fetch "^16.0.0" + proc-log "^4.0.0" promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.1.0" + read-package-json "^7.0.0" + read-package-json-fast "^3.0.0" + sigstore "^2.2.0" + ssri "^10.0.0" + tar "^6.1.11" pacote@^13.0.3, pacote@^13.6.1: version "13.6.2" @@ -20215,6 +20219,30 @@ pacote@^13.0.3, pacote@^13.6.1: ssri "^9.0.0" tar "^6.1.11" +pacote@^17.0.4: + version "17.0.7" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-17.0.7.tgz#14b59a9bf5e3442c891af86825b97b7d72f48fba" + integrity sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ== + dependencies: + "@npmcli/git" "^5.0.0" + "@npmcli/installed-package-contents" "^2.0.1" + "@npmcli/promise-spawn" "^7.0.0" + "@npmcli/run-script" "^7.0.0" + cacache "^18.0.0" + fs-minipass "^3.0.0" + minipass "^7.0.2" + npm-package-arg "^11.0.0" + npm-packlist "^8.0.0" + npm-pick-manifest "^9.0.0" + npm-registry-fetch "^16.0.0" + proc-log "^4.0.0" + promise-retry "^2.0.1" + read-package-json "^7.0.0" + read-package-json-fast "^3.0.0" + sigstore "^2.2.0" + ssri "^10.0.0" + tar "^6.1.11" + pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -20254,14 +20282,14 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.7: pbkdf2 "^3.1.2" safe-buffer "^5.2.1" -parse-conflict-json@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-1.1.1.tgz#54ec175bde0f2d70abf6be79e0e042290b86701b" - integrity sha512-4gySviBiW5TRl7XHvp1agcS7SOe0KZOjC//71dzZVWJrY9hCrgtvl5v3SyIxCZ4fZF47TxD9nfzmxcx76xmbUw== +parse-conflict-json@*, parse-conflict-json@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz#67dc55312781e62aa2ddb91452c7606d1969960c" + integrity sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw== dependencies: - json-parse-even-better-errors "^2.3.0" - just-diff "^3.0.1" - just-diff-apply "^3.0.0" + json-parse-even-better-errors "^3.0.0" + just-diff "^6.0.0" + just-diff-apply "^5.2.0" parse-conflict-json@^2.0.1: version "2.0.2" @@ -20431,12 +20459,12 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== dependencies: - lru-cache "^9.1.1 || ^10.0.0" + lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.7: @@ -20485,7 +20513,7 @@ path@^0.12.7: process "^0.11.1" util "^0.10.3" -pathe@^1.1.0, pathe@^1.1.1, pathe@^1.1.2: +pathe@^1.1.1, pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== @@ -20629,13 +20657,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: find-up "^4.0.0" pkg-types@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" - integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.0.tgz#3ec1bf33379030fd0a34c227b6c650e8ea7ca271" + integrity sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA== dependencies: - jsonc-parser "^3.2.0" - mlly "^1.2.0" - pathe "^1.1.0" + confbox "^0.1.7" + mlly "^1.6.1" + pathe "^1.1.2" pkg-up@^2.0.0: version "2.0.0" @@ -20644,17 +20672,17 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" -playwright-core@1.42.1: - version "1.42.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.42.1.tgz#13c150b93c940a3280ab1d3fbc945bc855c9459e" - integrity sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA== +playwright-core@1.43.1: + version "1.43.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.43.1.tgz#0eafef9994c69c02a1a3825a4343e56c99c03b02" + integrity sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg== -playwright@1.42.1: - version "1.42.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.42.1.tgz#79c828b51fe3830211137550542426111dc8239f" - integrity sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg== +playwright@1.43.1: + version "1.43.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.43.1.tgz#8ad08984ac66c9ef3d0db035be54dd7ec9f1c7d9" + integrity sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA== dependencies: - playwright-core "1.42.1" + playwright-core "1.43.1" optionalDependencies: fsevents "2.3.2" @@ -20699,6 +20727,14 @@ possible-typed-array-names@^1.0.0: resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== +postcss-selector-parser@^6.0.10: + version "6.0.16" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz#3b88b9f5c5abd989ef4e2fc9ec8eedd34b20fb04" + integrity sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss@8.4.14: version "8.4.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" @@ -20714,9 +20750,9 @@ preact@10.4.1: integrity sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q== preact@^10.3.3: - version "10.20.0" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.20.0.tgz#191c10a2ee3b9fca1a7ded6375266266380212f6" - integrity sha512-wU7iZw2BjsaKDal3pDRDy/HpPB6cuFOnVUCcw9aIPKG98+ZrXx3F+szkos8BVME5bquyKDKvRlOJFG8kMkcAbg== + version "10.20.2" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.20.2.tgz#0b343299a8c020562311cc25db93b3d832ec5e71" + integrity sha512-S1d1ernz3KQ+Y2awUxKakpfOg2CEmJmwOP+6igPx6dgr6pgDvenqYviyokWso2rhHvGtTlWWnJDa7RaPbQerTg== precond@0.2: version "0.2.3" @@ -20799,11 +20835,6 @@ private@^0.1.6, private@^0.1.8: resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== -proc-log@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-1.0.0.tgz#0d927307401f69ed79341e83a0b2c9a13395eb77" - integrity sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg== - proc-log@^2.0.0, proc-log@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685" @@ -20814,6 +20845,11 @@ proc-log@^3.0.0: resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== +proc-log@^4.0.0, proc-log@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -20851,6 +20887,11 @@ promise-call-limit@^1.0.1: resolved "https://registry.yarnpkg.com/promise-call-limit/-/promise-call-limit-1.0.2.tgz#f64b8dd9ef7693c9c7613e7dfe8d6d24de3031ea" integrity sha512-1vTUnfI2hzui8AEIixbdAJlFY4LFDXqQswy/2eOlThAscXCY4It8FdVuI0fMJGAB2aWGbdQf/gv0skKYXmdrHA== +promise-call-limit@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/promise-call-limit/-/promise-call-limit-3.0.1.tgz#3570f7a3f2aaaf8e703623a552cd74749688cf19" + integrity sha512-utl+0x8gIDasV5X+PI5qWEPqH6fJS0pFtQ/4gZ95xfEFb/89dmh+/b895TbFDBLiafBvxD/PGTKfvxl4kH/pQg== + promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -20887,6 +20928,13 @@ promzard@^0.3.0: dependencies: read "1" +promzard@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.1.tgz#3b77251a24f988c0886f5649d4f642bcdd53e558" + integrity sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A== + dependencies: + read "^3.0.1" + prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -21041,16 +21089,16 @@ pure-rand@^5.0.1: integrity sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw== pure-rand@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" - integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qrcode-terminal@^0.12.0: +qrcode-terminal@*: version "0.12.0" resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ== @@ -21093,9 +21141,9 @@ qs@6.11.0: side-channel "^1.0.4" qs@^6.11.0, qs@^6.11.2, qs@^6.4.0: - version "6.12.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.0.tgz#edd40c3b823995946a8a0b1f208669c7a200db77" - integrity sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg== + version "6.12.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.1.tgz#39422111ca7cbdb70425541cba20c7d7b216599a" + integrity sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ== dependencies: side-channel "^1.0.6" @@ -21175,9 +21223,9 @@ quick-lru@^5.1.1: integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== radix3@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.1.tgz#60a56876ffec62c88a22396a6a1c4c7efe9eb4b1" - integrity sha512-yUUd5VTiFtcMEx0qFUxGAv5gbMc1un4RvEO1JZdP7ZUl/RHygZK6PknIKntmQRZxnMY3ZXD2ISaw1ij8GYW1yg== + version "1.1.2" + resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" + integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== ramda@~0.27.1: version "0.27.2" @@ -21283,17 +21331,25 @@ react@18.0.0: dependencies: loose-envify "^1.1.0" -read-cmd-shim@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" - integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== - read-cmd-shim@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-3.0.1.tgz#868c235ec59d1de2db69e11aec885bc095aea087" integrity sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g== -read-package-json-fast@^2.0.1, read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: +read-cmd-shim@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" + integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== + +read-package-json-fast@*, read-package-json-fast@^3.0.0, read-package-json-fast@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" + integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== + dependencies: + json-parse-even-better-errors "^3.0.0" + npm-normalize-package-bin "^3.0.0" + +read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== @@ -21301,15 +21357,15 @@ read-package-json-fast@^2.0.1, read-package-json-fast@^2.0.2, read-package-json- json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -read-package-json@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.1.2.tgz#b444d047de7c75d4a160cb056d00c0693c1df703" - integrity sha512-Dqer4pqzamDE2O4M55xp1qZMuLPqi4ldk2ya648FOMHRjwMzFhuxVrG04wd0c38IsvkVdr3vgHI6z+QTPdAjrQ== +read-package-json@*, read-package-json@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-7.0.0.tgz#d605c9dcf6bc5856da24204aa4e9518ee9714be0" + integrity sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg== dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" + glob "^10.2.2" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^6.0.0" + npm-normalize-package-bin "^3.0.0" read-package-json@^5.0.0, read-package-json@^5.0.1: version "5.0.2" @@ -21374,7 +21430,14 @@ read-pkg@^5.0.0, read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -read@1, read@^1.0.7, read@~1.0.1, read@~1.0.7: +read@*, read@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/read/-/read-3.0.1.tgz#926808f0f7c83fa95f1ef33c0e2c09dbb28fd192" + integrity sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw== + dependencies: + mute-stream "^1.0.0" + +read@1, read@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" integrity sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ== @@ -21400,7 +21463,7 @@ readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.8, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.8, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -21423,7 +21486,7 @@ readable-stream@~1.0.15: isarray "0.0.1" string_decoder "~0.10.x" -readdir-scoped-modules@^1.1.0: +readdir-scoped-modules@*, readdir-scoped-modules@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== @@ -21700,7 +21763,7 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" -request@^2.79.0, request@^2.85.0, request@^2.88.2: +request@^2.79.0, request@^2.85.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -21871,6 +21934,13 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== +rimraf@*, rimraf@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" + integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== + dependencies: + glob "^10.3.7" + rimraf@^2.2.8: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -21954,7 +22024,7 @@ rxjs@7.8.1, rxjs@^7.0.0, rxjs@^7.5.1, rxjs@^7.5.5, rxjs@^7.8.0: dependencies: tslib "^2.1.0" -safe-array-concat@^1.1.0, safe-array-concat@^1.1.2: +safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== @@ -22165,6 +22235,13 @@ semver-regex@^3.1.2: resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.4.tgz#13053c0d4aa11d070a2f2872b6b1e3ae1e1971b4" integrity sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA== +semver@*, semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + "semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.6.0, semver@^5.7.1: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -22189,13 +22266,6 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" - semver@~5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -22278,12 +22348,12 @@ serve-static@1.15.0: send "0.18.0" serve@^14.0.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.1.tgz#3f078d292ed5e7b2c5a64f957af2765b0459798b" - integrity sha512-48er5fzHh7GCShLnNyPBRPEjs2I6QBozeGr02gaacROiyS/8ARADlj595j39iZXAqBbJHH/ivJJyPRWY9sQWZA== + version "14.2.2" + resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.2.tgz#af7678a5d893aa5048a6f94e5262cefc34a32f71" + integrity sha512-MktTGv3ooijGxd67iQVocNdiHaOdNnEApGj7At4qHUN44XDaLFfrqbEtj5mXf+QNqyig/VdHYMRTXWRQj6TEbw== dependencies: "@zeit/schemas" "2.29.0" - ajv "8.11.0" + ajv "8.12.0" arg "5.0.2" boxen "7.0.0" chalk "5.0.1" @@ -22305,7 +22375,7 @@ servify@^0.1.12: request "^2.79.0" xhr "^2.3.3" -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== @@ -22426,7 +22496,7 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -22445,6 +22515,18 @@ signale@^1.2.1: figures "^2.0.0" pkg-conf "^2.1.0" +sigstore@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-2.3.0.tgz#c56b32818d4dc989f6ea3c0897f4d9bff5d14bed" + integrity sha512-q+o8L2ebiWD1AxD17eglf1pFrl9jtW7FHa0ygqY6EKvibK8JHyq9Z26v9MZXeDiw+RbfOJ9j2v70M10Hd6E06A== + dependencies: + "@sigstore/bundle" "^2.3.1" + "@sigstore/core" "^1.0.0" + "@sigstore/protobuf-specs" "^0.3.1" + "@sigstore/sign" "^2.3.0" + "@sigstore/tuf" "^2.3.1" + "@sigstore/verify" "^1.2.0" + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -22481,11 +22563,11 @@ siwe-recap@0.0.2-alpha.0: siwe "^2.1.4" siwe@^2.0.5, siwe@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/siwe/-/siwe-2.1.4.tgz#005a8be3e61224a86bd3457f60fdaab626f2d1d4" - integrity sha512-Dke1Qqa3mgiLm3vjqw/+SQ7dl8WV/Pfk3AlQBF94cBFydTYhztngqYrikzE3X5UTsJ6565dfVbQptszsuYZNYg== + version "2.3.2" + resolved "https://registry.yarnpkg.com/siwe/-/siwe-2.3.2.tgz#0794ae25f734f3068de0ab093ddd2f7867bc2d67" + integrity sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA== dependencies: - "@spruceid/siwe-parser" "*" + "@spruceid/siwe-parser" "^2.1.2" "@stablelib/random" "^1.0.1" uri-js "^4.4.1" valid-url "^1.0.9" @@ -22582,15 +22664,6 @@ sockjs@^0.3.24: uuid "^8.3.2" websocket-driver "^0.7.4" -socks-proxy-agent@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" - integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - socks-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" @@ -22600,19 +22673,19 @@ socks-proxy-agent@^7.0.0: debug "^4.3.3" socks "^2.6.2" -socks-proxy-agent@^8.0.1: - version "8.0.2" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad" - integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g== +socks-proxy-agent@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz#6b2da3d77364fde6292e810b496cb70440b9b89d" + integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A== dependencies: - agent-base "^7.0.2" + agent-base "^7.1.1" debug "^4.3.4" socks "^2.7.1" socks@^2.6.2, socks@^2.7.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.1.tgz#22c7d9dd7882649043cba0eafb49ae144e3457af" - integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== + version "2.8.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" + integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== dependencies: ip-address "^9.0.5" smart-buffer "^4.2.0" @@ -22900,20 +22973,13 @@ sshpk@^1.14.1, sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@^10.0.0: +ssri@*, ssri@^10.0.0, ssri@^10.0.5: version "10.0.5" resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.5.tgz#e49efcd6e36385196cb515d3a2ad6c3f0265ef8c" integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== dependencies: minipass "^7.0.3" -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - ssri@^9.0.0, ssri@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" @@ -23074,7 +23140,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -23092,16 +23158,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - 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" - -string-width@^2.0.0, string-width@^2.1.0: +string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -23145,7 +23202,7 @@ string.prototype.matchall@^4.0.10, string.prototype.matchall@^4.0.5, string.prot set-function-name "^2.0.2" side-channel "^1.0.6" -string.prototype.trim@^1.2.8, string.prototype.trim@^1.2.9, string.prototype.trim@~1.2.8: +string.prototype.trim@^1.2.9, string.prototype.trim@~1.2.8: version "1.2.9" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== @@ -23155,7 +23212,7 @@ string.prototype.trim@^1.2.8, string.prototype.trim@^1.2.9, string.prototype.tri es-abstract "^1.23.0" es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7, string.prototype.trimend@^1.0.8: +string.prototype.trimend@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== @@ -23164,14 +23221,14 @@ string.prototype.trimend@^1.0.7, string.prototype.trimend@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" @@ -23192,12 +23249,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringify-package@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" - integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -23225,13 +23277,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -23256,6 +23301,11 @@ strip-bom@^4.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== +strip-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" + integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== + strip-dirs@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" @@ -23479,9 +23529,9 @@ symbol-tree@^3.2.4: integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== synthetix-js@^2.74.1: - version "2.100.0" - resolved "https://registry.yarnpkg.com/synthetix-js/-/synthetix-js-2.100.0.tgz#393d0d9a5406487aa0fb92f30a7c0b40def3d055" - integrity sha512-ecsd5hhV4OxT6X6i0SN9++ioDjVRjYmdmqtVsdRqR3ap8rAe9Vpi0vladFDeT2dN0I+P7fyWkcESgJRkrXcXYQ== + version "2.101.2" + resolved "https://registry.yarnpkg.com/synthetix-js/-/synthetix-js-2.101.2.tgz#9394967368fcf8183743a4b05d49889fd7fdbd21" + integrity sha512-g9ZOwV6lBYm536mY9vbEMdmO3Slr/rMMqKyVr+LaQAlk/dsjtstbfK5/8ikty1U7FYaO6xNQqst4GZuhk9kRUA== dependencies: "@ledgerhq/hw-app-eth" "4.74.2" "@ledgerhq/hw-transport" "4.74.2" @@ -23493,14 +23543,14 @@ synthetix-js@^2.74.1: ethers "4.0.44" hdkey "1.1.1" lodash "4.17.15" - synthetix "2.100.0" + synthetix "2.101.2" trezor-connect "8.1.8" walletlink "2.0.2" -synthetix@2.100.0: - version "2.100.0" - resolved "https://registry.yarnpkg.com/synthetix/-/synthetix-2.100.0.tgz#7f10b7a8e74fb08a5a6d3ebc6d7589240e928e00" - integrity sha512-KNnAT0RLN7jcjA8cQLjpsrgz1K80OFgY3BhwRW+8ofX83bfkYy6Tw3wfioHDAbtpV8LL6sd9I9Fm8uNFlZNiYQ== +synthetix@2.101.2: + version "2.101.2" + resolved "https://registry.yarnpkg.com/synthetix/-/synthetix-2.101.2.tgz#2d2c411b6b07392706624a4ea639b9f5f63d7b00" + integrity sha512-DlSsL1KiRy/oSCpZPYLdRXdCklBIbjjuzy5A0JlJ5Aq0MNNjhovXTUWiwn75y7c+wmL+rOK+qv5YZkmWH6eD5w== dependencies: "@nomiclabs/hardhat-etherscan" "^3.1.0" abi-decoder "^2.3.0" @@ -23544,9 +23594,9 @@ table-layout@^1.0.2: wordwrapjs "^4.0.0" table@^6.0.4, table@^6.0.9, table@^6.8.0: - version "6.8.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" - integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + version "6.8.2" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" + integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -23620,6 +23670,18 @@ tar-stream@^2.1.4, tar-stream@~2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" +tar@*: + version "7.0.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.0.1.tgz#8f6ccebcd91b69e9767a6fc4892799e8b0e606d5" + integrity sha512-IjMhdQMZFpKsHEQT3woZVxBtCQY+0wk3CVxdRkGXEgyGa0dNS/ehPvOMr2nmfC7x5Zj2N+l6yZUpmICjLGS35w== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^5.0.0" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + tar@6.1.11: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" @@ -23645,7 +23707,7 @@ tar@^4.0.2: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.0.2: +tar@^6.1.0, tar@^6.1.11, tar@^6.1.2, tar@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== @@ -23657,18 +23719,6 @@ tar@^6.0.2: mkdirp "^1.0.3" yallist "^4.0.0" -tar@^6.1.0, tar@^6.1.11, tar@^6.1.2: - version "6.2.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" - integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^5.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -23713,9 +23763,9 @@ terser@^4.6.3: source-map-support "~0.5.12" terser@^5.10.0: - version "5.29.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.29.2.tgz#c17d573ce1da1b30f21a877bffd5655dd86fdb35" - integrity sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw== + version "5.30.4" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.30.4.tgz#62b4d16a819424e6317fd5ceffb4ee8dc769803a" + integrity sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -23741,7 +23791,7 @@ text-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== -text-table@^0.2.0, text-table@~0.2.0: +text-table@*, text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== @@ -23800,7 +23850,7 @@ timers-browserify@^2.0.12: dependencies: setimmediate "^1.0.4" -tiny-relative-date@^1.3.0: +tiny-relative-date@*: version "1.3.0" resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A== @@ -23937,19 +23987,23 @@ tr46@~0.0.3: integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== traverse@~0.6.6: - version "0.6.8" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.8.tgz#5e5e0c41878b57e4b73ad2f3d1e36a715ea4ab15" - integrity sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA== + version "0.6.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.9.tgz#76cfdbacf06382d460b76f8b735a44a6209d8b81" + integrity sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg== + dependencies: + gopd "^1.0.1" + typedarray.prototype.slice "^1.0.3" + which-typed-array "^1.1.15" tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -treeverse@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-1.0.4.tgz#a6b0ebf98a1bca6846ddc7ecbc900df08cb9cd5f" - integrity sha512-whw60l7r+8ZU8Tu/Uc2yxtc4ZTZbR/PF3u1IPNKGQ6p8EICLb3Z2lAgoqw9bqYd8IkgnsaOcLzYHFckjqNsf0g== +treeverse@*, treeverse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-3.0.0.tgz#dd82de9eb602115c6ebd77a574aae67003cb48c8" + integrity sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ== treeverse@^2.0.0: version "2.0.0" @@ -24059,7 +24113,7 @@ tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -24076,6 +24130,15 @@ tty-browserify@^0.0.1: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== +tuf-js@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-2.2.0.tgz#4daaa8620ba7545501d04dfa933c98abbcc959b9" + integrity sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg== + dependencies: + "@tufjs/models" "2.0.0" + debug "^4.3.4" + make-fetch-happen "^13.0.0" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -24216,10 +24279,10 @@ typed-array-byte-offset@^1.0.2: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-length@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" - integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: call-bind "^1.0.7" for-each "^0.3.3" @@ -24235,6 +24298,18 @@ typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typedarray.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz#bce2f685d3279f543239e4d595e0d021731d2d1a" + integrity sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-errors "^1.3.0" + typed-array-buffer "^1.0.2" + typed-array-byte-offset "^1.0.2" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -24285,7 +24360,7 @@ u2f-api@0.2.7: resolved "https://registry.yarnpkg.com/u2f-api/-/u2f-api-0.2.7.tgz#17bf196b242f6bf72353d9858e6a7566cc192720" integrity sha512-fqLNg8vpvLOD5J/z4B6wpPg4Lvowz1nJ9xdHcCzdUPKcFE/qNCceV2gNZxSJd5vhAZemHr/K/hbzVA0zxB5mkg== -ufo@^1.3.0, ufo@^1.3.2, ufo@^1.4.0: +ufo@^1.3.2, ufo@^1.4.0, ufo@^1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== @@ -24353,9 +24428,9 @@ undici-types@~5.26.4: integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici@^5.14.0: - version "5.28.3" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" - integrity sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== dependencies: "@fastify/busboy" "^2.0.0" @@ -24415,13 +24490,6 @@ union@~0.5.0: dependencies: qs "^6.4.0" -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - unique-filename@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" @@ -24436,13 +24504,6 @@ unique-filename@^3.0.0: dependencies: unique-slug "^4.0.0" -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - unique-slug@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9" @@ -24687,7 +24748,7 @@ utf8@3.0.0, utf8@^3.0.0: resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== -util-deprecate@^1.0.1, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -24794,7 +24855,14 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: +validate-npm-package-name@*, validate-npm-package-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" + integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== + dependencies: + builtins "^5.0.0" + +validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" integrity sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw== @@ -24808,13 +24876,6 @@ validate-npm-package-name@^4.0.0: dependencies: builtins "^5.0.0" -validate-npm-package-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" - integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== - dependencies: - builtins "^5.0.0" - valtio@1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.0.tgz#c029dcd17a0f99d2fbec933721fe64cfd32a31ed" @@ -24894,6 +24955,11 @@ walk-up-path@^1.0.0: resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e" integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg== +walk-up-path@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" + integrity sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA== + walker@^1.0.7, walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -25436,6 +25502,13 @@ which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, gopd "^1.0.1" has-tostringtag "^1.0.2" +which@*, which@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -25443,14 +25516,7 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -which@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" - integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== - dependencies: - isexe "^3.1.1" - -wide-align@^1.1.0, wide-align@^1.1.2, wide-align@^1.1.5: +wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== @@ -25494,7 +25560,7 @@ wordwrapjs@^4.0.0: reduce-flatten "^2.0.0" typical "^5.2.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -25529,15 +25595,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -25552,6 +25609,14 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@*, write-file-atomic@^5.0.0, write-file-atomic@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -25561,7 +25626,7 @@ write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: +write-file-atomic@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== @@ -25579,14 +25644,6 @@ write-file-atomic@^4.0.0, write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -write-file-atomic@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" - integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^4.0.1" - write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" @@ -25763,6 +25820,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + yaml@^1.10.0, yaml@^1.7.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" From 959ccbc1f2db5e8fbfc3d6d02a4233cd2b1e90ad Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:08:17 +0100 Subject: [PATCH 002/263] fix(test): fix not being aware of local network context --- .../contracts-sdk/src/lib/contracts-sdk.ts | 33 ++++++++++++------- packages/core/src/lib/lit-core.ts | 30 +++++++++++++++++ 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 3c0ae8fdaf..068672bf7e 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -570,10 +570,11 @@ export class LitContracts { public static async getStakingContract( network: 'cayenne' | 'manzano' | 'habanero' | 'custom' | 'localhost', - context?: LitContractContext | LitContractResolverContext + context?: LitContractContext | LitContractResolverContext, + rpcUrl?: string ) { let provider: ethers.providers.JsonRpcProvider; - const rpcUrl = DEFAULT_RPC; + rpcUrl = rpcUrl ?? DEFAULT_RPC; if (context && 'provider' in context!) { provider = context.provider; } else { @@ -581,7 +582,7 @@ export class LitContracts { } if (!context) { - const contractData = await LitContracts._resolveContractContext( + let contractData = await LitContracts._resolveContractContext( network, context ); @@ -601,7 +602,7 @@ export class LitContracts { // if we have contract context then we determine if there exists a `resolverAddres` // if there is a resolver address we assume we are using a contract resolver for bootstrapping of contracts if (!context.resolverAddress) { - const stakingContract = (context as LitContractContext).Staking; + let stakingContract = (context as LitContractContext).Staking; if (!stakingContract.address) { throw new Error( @@ -614,7 +615,7 @@ export class LitContracts { provider ); } else { - const contractContext = await LitContracts._getContractsFromResolver( + let contractContext = await LitContracts._getContractsFromResolver( context as LitContractResolverContext, provider, ['Staking'] @@ -651,7 +652,7 @@ export class LitContracts { ): Promise { let address: string = ''; switch (contract) { - case 'Allowlist': + case 'AllowList' || 'AllowList': address = await resolverContract['getContract']( await resolverContract['ALLOWLIST_CONTRACT'](), environment @@ -850,9 +851,14 @@ export class LitContracts { public static getMinNodeCount = async ( network: 'cayenne' | 'manzano' | 'habanero' | 'custom' | 'localhost', - context?: LitContractContext | LitContractResolverContext + context?: LitContractContext | LitContractResolverContext, + rpcUrl?: string ) => { - const contract = await LitContracts.getStakingContract(network, context); + const contract = await LitContracts.getStakingContract( + network, + context, + rpcUrl + ); const minNodeCount = await contract['currentValidatorCountForConsensus'](); @@ -864,9 +870,14 @@ export class LitContracts { public static getValidators = async ( network: 'cayenne' | 'manzano' | 'habanero' | 'custom' | 'localhost', - context?: LitContractContext | LitContractResolverContext + context?: LitContractContext | LitContractResolverContext, + rpcUrl?: string ): Promise => { - const contract = await LitContracts.getStakingContract(network, context); + const contract = await LitContracts.getStakingContract( + network, + context, + rpcUrl + ); // Fetch contract data const [activeValidators, currentValidatorsCount, kickedValidators] = @@ -1048,7 +1059,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope const events = 'events' in receipt ? receipt.events : receipt.logs; - if (!events) { + if (!events || events.length <= 0) { throw new Error('No events found in receipt'); } diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 54234bced2..358eefeed9 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -87,6 +87,7 @@ export type LitNodeClientConfigWithDefaults = Required< | 'litNetwork' | 'minNodeCount' | 'retryTolerance' + | 'rpcUrl' > > & Partial>; @@ -110,6 +111,7 @@ export class LitCore { maxRetryCount: 3, interval: 100, }, + rpcUrl: null, }; connectedNodes = new Set(); serverKeys: Record = {}; @@ -310,6 +312,34 @@ export class LitCore { this.config.minNodeCount = parseInt(minNodeCount, 10); this.config.bootstrapUrls = bootstrapUrls; + } else if ( + this.config.litNetwork === LitNetwork.Custom && + this.config.bootstrapUrls.length >= 1 && + this.config.rpcUrl + ) { + log('Using custom bootstrap urls:', this.config.bootstrapUrls); + + // const provider = new ethers.providers.JsonRpcProvider(this.config.rpcUrl); + + const minNodeCount = await LitContracts.getMinNodeCount( + this.config.litNetwork, + this.config.contractContext, + this.config.rpcUrl! + ); + this.config.minNodeCount = parseInt(minNodeCount, 10); + + const bootstrapUrls = await LitContracts.getValidators( + this.config.litNetwork, + this.config.contractContext, + this.config.rpcUrl! + ); + this.config.bootstrapUrls = bootstrapUrls; + + this._stakingContract = await LitContracts.getStakingContract( + this.config.litNetwork, + this.config.contractContext, + this.config.rpcUrl! + ); } }; From 12dc32ab5623b7ccd8d047ba3ed1c49b3e0d3bb5 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:11:03 +0100 Subject: [PATCH 003/263] feat(helper): introduce siweMessage creation & authSig crafter helper functions, and fix circular dependencies inside auth-helpers --- packages/auth-helpers/src/index.ts | 5 +- .../auth-helpers/src/lib/craft-auth-sig.ts | 50 ++++++++++ packages/auth-helpers/src/lib/models.ts | 1 + .../recap/recap-session-capability-object.ts | 68 +------------ packages/auth-helpers/src/lib/resources.ts | 6 +- packages/auth-helpers/src/lib/siwe.ts | 9 -- .../src/lib/siwe/create-siwe-message.ts | 89 +++++++++++++++++ .../siwe-helper.spec.ts} | 2 +- .../auth-helpers/src/lib/siwe/siwe-helper.ts | 98 +++++++++++++++++++ 9 files changed, 250 insertions(+), 78 deletions(-) create mode 100644 packages/auth-helpers/src/lib/craft-auth-sig.ts delete mode 100644 packages/auth-helpers/src/lib/siwe.ts create mode 100644 packages/auth-helpers/src/lib/siwe/create-siwe-message.ts rename packages/auth-helpers/src/lib/{siwe.spec.ts => siwe/siwe-helper.spec.ts} (95%) create mode 100644 packages/auth-helpers/src/lib/siwe/siwe-helper.ts diff --git a/packages/auth-helpers/src/index.ts b/packages/auth-helpers/src/index.ts index 6f47917e46..7d809648a1 100644 --- a/packages/auth-helpers/src/index.ts +++ b/packages/auth-helpers/src/index.ts @@ -1,5 +1,8 @@ export * from './lib/models'; export * from './lib/session-capability-object'; export * from './lib/resources'; -export * from './lib/siwe'; +export * from './lib/siwe/siwe-helper'; export * from './lib/recap/recap-session-capability-object'; +export * from './lib/siwe/create-siwe-message'; +export * from './lib/siwe/siwe-helper'; +export * from './lib/craft-auth-sig'; diff --git a/packages/auth-helpers/src/lib/craft-auth-sig.ts b/packages/auth-helpers/src/lib/craft-auth-sig.ts new file mode 100644 index 0000000000..42bc8fdb18 --- /dev/null +++ b/packages/auth-helpers/src/lib/craft-auth-sig.ts @@ -0,0 +1,50 @@ +import { AuthSig, SignerLike } from '@lit-protocol/types'; +import { ethers } from 'ethers'; + +/** + * Crafts an AuthSig object using the signer. + * + * For more context: + * We are only using authSig to generate session sigs. In a newer version, we will stop accepting + * authSig all together from the node and will only accept session sigs. + * + * @param signer the signer must have a "signMessage" method + * @param toSign - the message to sign + * @param address - (optional) the address of the signer + * @returns + */ +export const craftAuthSig = async ({ + signer, + toSign, + address, + algo, +}: { + signer: ethers.Wallet | ethers.Signer | SignerLike; + toSign: string; + address?: string; + algo?: 'LIT_BLS' | 'ed25519'; +}): Promise => { + if (!signer?.signMessage) { + throw new Error('signer does not have a signMessage method'); + } + + const signature = await signer.signMessage(toSign); + + // If address is not provided, derive it from the signer + if (!address) { + address = await signer.getAddress(); + } + + // If address is still not available, throw an error + if (!address) { + throw new Error('address is required'); + } + + return { + sig: signature, + derivedVia: 'web3.eth.personal.sign', + signedMessage: toSign, + address: address, + ...(algo && { algo }), + }; +}; diff --git a/packages/auth-helpers/src/lib/models.ts b/packages/auth-helpers/src/lib/models.ts index 6e9492fac1..1a34a89905 100644 --- a/packages/auth-helpers/src/lib/models.ts +++ b/packages/auth-helpers/src/lib/models.ts @@ -173,4 +173,5 @@ export interface ILitResource { export type LitResourceAbilityRequest = { resource: ILitResource; ability: LitAbility; + data?: any; }; diff --git a/packages/auth-helpers/src/lib/recap/recap-session-capability-object.ts b/packages/auth-helpers/src/lib/recap/recap-session-capability-object.ts index 1fa747a53d..33a7d3fa4a 100644 --- a/packages/auth-helpers/src/lib/recap/recap-session-capability-object.ts +++ b/packages/auth-helpers/src/lib/recap/recap-session-capability-object.ts @@ -9,7 +9,7 @@ import { PlainJSON, } from '../models'; import { getRecapNamespaceAndAbility } from './utils'; -import { sanitizeSiweMessage } from '../siwe'; +import { sanitizeSiweMessage } from '../siwe/siwe-helper'; import { AuthSig } from '../models'; export class RecapSessionCapabilityObject implements ISessionCapabilityObject { @@ -22,75 +22,11 @@ export class RecapSessionCapabilityObject implements ISessionCapabilityObject { this.#inner = new Recap(att, prf); } - // static async sha256(data: Buffer): Promise { - // const digest = await crypto.subtle.digest('SHA-256', data); - // return digest; - // } - - // This should ideally be placed in the IPFSBundledSDK package, but for some reasons - // there seems to be bundling issues where the jest test would fail, but somehow - // works here. - // public static async strToCID( - // data: string | Uint8Array | object - // ): Promise { - // let content: Uint8Array; - - // // Check the type of data and convert accordingly - // if (typeof data === 'string') { - // // console.log("Type A"); - // // Encode the string directly if data is a string - // content = new TextEncoder().encode(data); - // } else if (data instanceof Uint8Array) { - // // console.log("Type B"); - // // Use the Uint8Array directly - // content = data; - // } else if (typeof data === 'object') { - // // console.log("Type C"); - // // Stringify and encode if data is an object - // const contentStr = JSON.stringify(data); - // content = new TextEncoder().encode(contentStr); - // } else { - // // console.log("Type D"); - // throw new Error('Invalid content type'); - // } - - // // Create the CID - // let ipfsId; - // for await (const { cid } of IPFSBundledSDK.importer( - // [{ content }], - // new IPFSBundledSDK.MemoryBlockstore(), - // { onlyHash: true } - // )) { - // ipfsId = cid; - // } - - // // Validate the IPFS ID - // if (!ipfsId) { - // throw new Error('Could not create IPFS ID'); - // } - - // // Return the IPFS ID as a string - // return ipfsId.toString(); - // } - /** - * Adds a Rate Limit Authorization Signature (AuthSig) as an proof to the Recap object. - * This method serializes the AuthSig object into a JSON string and adds it to the proof - * of the Recap object. The AuthSig typically contains authentication details like signature, - * method of derivation, the signed message, and the address of the signer. This proof is - * used to verify that the user has the necessary authorization, such as a Rate Limit Increase NFT. - * - * @param authSig The AuthSig object containing the rate limit authorization details. + * @deprecated - to be removed, as it's not used. */ async addRateLimitAuthSig(authSig: AuthSig) { throw new Error('Not implemented yet. '); - // const ipfsId = await RecapSessionCapabilityObject.strToCID(authSig); - - // try { - // this.addProof(ipfsId); - // } catch (e: any) { - // throw new Error(e); - // } } static decode(encoded: string): RecapSessionCapabilityObject { diff --git a/packages/auth-helpers/src/lib/resources.ts b/packages/auth-helpers/src/lib/resources.ts index c17956bcb5..dee4c794fa 100644 --- a/packages/auth-helpers/src/lib/resources.ts +++ b/packages/auth-helpers/src/lib/resources.ts @@ -1,4 +1,8 @@ -import { ILitResource, LitAbility, LitResourcePrefix } from './models'; +import { + ILitResource, + LitAbility, + LitResourcePrefix, +} from '@lit-protocol/types'; abstract class LitResourceBase { abstract resourcePrefix: LitResourcePrefix; diff --git a/packages/auth-helpers/src/lib/siwe.ts b/packages/auth-helpers/src/lib/siwe.ts deleted file mode 100644 index 74544c1a64..0000000000 --- a/packages/auth-helpers/src/lib/siwe.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function sanitizeSiweMessage(message: string): string { - // Unescape double-escaped newlines - let sanitizedMessage = message.replace(/\\\\n/g, '\\n'); - - // Replace escaped double quotes with single quotes - sanitizedMessage = sanitizedMessage.replace(/\\"/g, "'"); - - return sanitizedMessage; -} diff --git a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts new file mode 100644 index 0000000000..2f82343767 --- /dev/null +++ b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts @@ -0,0 +1,89 @@ +import { SiweMessage } from 'siwe'; +import { BaseSiweMessage, CapacityDelegationFields } from '@lit-protocol/types'; +import { + LitAbility, + WithCapacityDelegation, + WithRecap, +} from '@lit-protocol/types'; +import { LitRLIResource } from '../resources'; + +import { + createCapacityCreditsResourceData, + addRecapToSiweMessage, +} from './siwe-helper'; + +export const createSiweMessage = async ( + params: T +): Promise => { + // -- validations + if (!params.walletAddress) { + throw new Error('walletAddress is required'); + } + + const ONE_WEEK_FROM_NOW = new Date( + Date.now() + 1000 * 60 * 60 * 24 * 7 + ).toISOString(); + + let siweParams = { + domain: params?.domain ?? 'localhost', + address: params.walletAddress, + statement: + params?.statement ?? + 'This is a test statement. You can put anything you want here.', + uri: params?.uri ?? 'https://localhost/login', + version: params?.version ?? '1', + chainId: params?.chainId ?? 1, + nonce: params.nonce, + expirationTime: params?.expiration ?? ONE_WEEK_FROM_NOW, + }; + + let siweMessage = new SiweMessage(siweParams); + + // -- create a message with capacity credits + if ( + 'uses' in params || + 'delegateeAddresses' in params || + 'capacityTokenId' in params + ) { + const ccParams = params as CapacityDelegationFields; + + const capabilities = createCapacityCreditsResourceData(ccParams); + + params.resources = [ + { + resource: new LitRLIResource(ccParams.capacityTokenId ?? '*'), + ability: LitAbility.RateLimitIncreaseAuth, + data: capabilities, + }, + ]; + } + + // -- add recap resources if needed + if (params.resources) { + siweMessage = await addRecapToSiweMessage({ + siweMessage, + resources: params.resources, + litNodeClient: params.litNodeClient, + }); + } + + return siweMessage.prepareMessage(); +}; +export const createSiweMessageWithRecaps = async ( + params: WithRecap +): Promise => { + return createSiweMessage({ + ...params, + }); +}; +export const createSiweMessageWithCapacityDelegation = async ( + params: WithCapacityDelegation +) => { + if (!params.litNodeClient) { + throw new Error('litNodeClient is required'); + } + + return createSiweMessage({ + ...params, + }); +}; diff --git a/packages/auth-helpers/src/lib/siwe.spec.ts b/packages/auth-helpers/src/lib/siwe/siwe-helper.spec.ts similarity index 95% rename from packages/auth-helpers/src/lib/siwe.spec.ts rename to packages/auth-helpers/src/lib/siwe/siwe-helper.spec.ts index 9917630967..1237744647 100644 --- a/packages/auth-helpers/src/lib/siwe.spec.ts +++ b/packages/auth-helpers/src/lib/siwe/siwe-helper.spec.ts @@ -1,4 +1,4 @@ -import { sanitizeSiweMessage } from './siwe'; +import { sanitizeSiweMessage } from './siwe-helper'; describe('sanitizeSiweMessage', () => { it('should unescape double-escaped newlines', () => { diff --git a/packages/auth-helpers/src/lib/siwe/siwe-helper.ts b/packages/auth-helpers/src/lib/siwe/siwe-helper.ts new file mode 100644 index 0000000000..e34b438c7f --- /dev/null +++ b/packages/auth-helpers/src/lib/siwe/siwe-helper.ts @@ -0,0 +1,98 @@ +import { SiweMessage } from 'siwe'; + +import { + CapacityDelegationFields, + CapacityDelegationRequest, + ILitNodeClient, + LitResourceAbilityRequest, +} from '@lit-protocol/types'; + +/** + * Sanitizes a SIWE message by unescaping double-escaped newlines and replacing escaped double quotes with single quotes. + * + * @param message - The SIWE message to sanitize. + * @returns The sanitized SIWE message. + */ +export function sanitizeSiweMessage(message: string): string { + let sanitizedMessage = message.replace(/\\\\n/g, '\\n'); + + sanitizedMessage = sanitizedMessage.replace(/\\"/g, "'"); + + return sanitizedMessage; +} + +/** + * Creates the resource data for a capacity delegation request. + * @param params - The capacity delegation fields. + * @returns The capacity delegation request object. + */ +export const createCapacityCreditsResourceData = ( + params: CapacityDelegationFields +): CapacityDelegationRequest => { + return { + ...(params.capacityTokenId ? { nft_id: [params.capacityTokenId] } : {}), // Conditionally include nft_id + ...(params.delegateeAddresses + ? { + delegate_to: params.delegateeAddresses.map((address) => + address.startsWith('0x') ? address.slice(2) : address + ), + } + : {}), + uses: params.uses!.toString() || '1', + }; +}; + +/** + * Adds recap capabilities to a SiweMessage. + * @param siweMessage - The SiweMessage to add recap capabilities to. + * @param resources - An array of LitResourceAbilityRequest objects representing the resources and abilities to add. + * @param litNodeClient - The LitNodeClient interface + * @returns The updated SiweMessage with recap capabilities added. + * @throws An error if the resources array is empty or if litNodeClient is not provided. + * @throws An error if the generated capabilities fail to verify for any resource and ability. + */ +export const addRecapToSiweMessage = async ({ + siweMessage, + resources, + litNodeClient, +}: { + siweMessage: SiweMessage; + resources: LitResourceAbilityRequest[]; + litNodeClient: ILitNodeClient; +}) => { + if (!resources || resources.length < 1) { + throw new Error('resources is required'); + } + + if (!litNodeClient) { + throw new Error('litNodeClient is required'); + } + + for (const request of resources) { + const recapObject = + await litNodeClient.generateSessionCapabilityObjectWithWildcards([ + request.resource, + ]); + + recapObject.addCapabilityForResource( + request.resource, + request.ability, + request.data || null + ); + + const verified = recapObject.verifyCapabilitiesForResource( + request.resource, + request.ability + ); + + if (!verified) { + throw new Error( + `Failed to verify capabilities for resource: "${request.resource}" and ability: "${request.ability}` + ); + } + + siweMessage = recapObject.addToSiweMessage(siweMessage); + } + + return siweMessage; +}; From 541c66a3c6e86ef8b9843f09c1297b6853c88ef8 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:11:26 +0100 Subject: [PATCH 004/263] fix(polyfill): fetch --- packages/lit-node-client-nodejs/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/index.ts b/packages/lit-node-client-nodejs/src/index.ts index 7836b62701..ba66b7aa4a 100644 --- a/packages/lit-node-client-nodejs/src/index.ts +++ b/packages/lit-node-client-nodejs/src/index.ts @@ -1,4 +1,4 @@ -import 'cross-fetch/polyfill'; +import 'cross-fetch/dist/node-polyfill.js'; import * as _LitNodeClientNodeJs from './lib/lit-node-client-nodejs'; // ==================== Environment ==================== From 762c428f3ee754f4d727647d56040d66a83820f2 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:12:22 +0100 Subject: [PATCH 005/263] fix: add specified litNodeClient back to ILitNodeClient interface --- packages/types/src/lib/ILitNodeClient.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index af3d5dfd0a..e8b12e5755 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -22,6 +22,7 @@ import { SuccessNodePromises, ValidateAndSignECDSA, } from './interfaces'; +import { ILitResource, ISessionCapabilityObject } from './models'; import { SupportedJsonRequests } from './types'; export interface ILitNodeClient { @@ -318,4 +319,14 @@ export interface ILitNodeClient { * */ connect(): Promise; + + /** + * Generates a session capability object + * + * @param litResources An array of ILitResource to be processed. + * @returns A Promise resolving to an ISessionCapabilityObject. + */ + generateSessionCapabilityObjectWithWildcards( + litResources: ILitResource[] + ): Promise; } From 23620d5bbdc151335031ec7052805af858dc9687 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:14:06 +0100 Subject: [PATCH 006/263] feat(auth-unification): add support on addtional parameters in authNeededCallbacks, and a higher level "getPkpSessionSigs" function --- .../src/lib/lit-node-client-nodejs.ts | 92 ++++++++++- packages/types/src/lib/interfaces.ts | 150 +++++++++++++----- 2 files changed, 195 insertions(+), 47 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 53ea9aabf2..42ba2ff2b4 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -106,6 +106,7 @@ import type { ValidateAndSignECDSA, WebAuthnAuthenticationVerificationParams, ILitNodeClient, + GetPkpSessionSigs, } from '@lit-protocol/types'; // TODO: move this to auth-helper for next patch @@ -490,6 +491,10 @@ export class LitNodeClientNodeJs expiration, sessionKeyUri, nonce, + resourceAbilityRequests, + litActionCode, + ipfsId, + jsParams, }: GetWalletSigProps): Promise => { let walletSig: AuthSig; @@ -517,6 +522,7 @@ export class LitNodeClientNodeJs ); if (authNeededCallback) { log('getWalletSig - flow 1.1'); + const body = { chain, statement: sessionCapabilityObject?.statement, @@ -527,6 +533,14 @@ export class LitNodeClientNodeJs expiration, uri: sessionKeyUri, nonce, + + // for recap + ...(resourceAbilityRequests && { resourceAbilityRequests }), + + // for lit action custom auth + ...(litActionCode && { litActionCode }), + ...(ipfsId && { ipfsId }), + ...(jsParams && { jsParams }), }; log('callback body:', body); @@ -718,7 +732,14 @@ export class LitNodeClientNodeJs logWithRequestId(requestId, 'getJsExecutionShares'); // -- execute - const urlWithPath = `${url}/web/execute`; + + let urlWithPath = `${url}/web/execute`; + + // @ts-ignore: for testing only + if (params.version) { + // @ts-ignore: for testing only + urlWithPath = `${url}/web/execute/${params.version}`; + } if (!authSig) { throw new Error('authSig or sessionSig is required'); @@ -1797,7 +1818,7 @@ export class LitNodeClientNodeJs pubkey: pubKey, ...(sigToPassToNode && sigToPassToNode !== undefined && { authSig: sigToPassToNode }), - authMethods, + ...(authMethods && authMethods.length > 0 && { authMethods }), }; logWithRequestId(id, 'reqBody:', reqBody); @@ -2750,12 +2771,20 @@ export class LitNodeClientNodeJs // -- (TRY) to get the wallet signature let authSig = await this.getWalletSig({ authNeededCallback: params.authNeededCallback, - chain: params.chain, + chain: params.chain || 'ethereum', sessionCapabilityObject, switchChain: params.switchChain, expiration: expiration, sessionKeyUri: sessionKeyUri, nonce, + + // -- for recap + resourceAbilityRequests: params.resourceAbilityRequests, + + // -- optional fields + ...(params.litActionCode && { litActionCode: params.litActionCode }), + ...(params.ipfsId && { ipfsId: params.ipfsId }), + ...(params.jsParams && { jsParams: params.jsParams }), }); const needToResignSessionKey = await this.checkNeedToResignSessionKey({ @@ -2772,7 +2801,7 @@ export class LitNodeClientNodeJs authSig = await this.#authCallbackAndUpdateStorageItem({ authCallback: params.authNeededCallback, authCallbackParams: { - chain: params.chain, + chain: params.chain || 'ethereum', statement: sessionCapabilityObject.statement, resources: [sessionCapabilityObject.encodeAsSiweResource()], switchChain: params.switchChain, @@ -2858,6 +2887,61 @@ export class LitNodeClientNodeJs return signatures; }; + getPkpSessionSigs = async (params: GetPkpSessionSigs) => { + const chain = params?.chain || 'ethereum'; + + const pkpSessionSigs = this.getSessionSigs({ + chain, + ...params, + authNeededCallback: async (props: AuthCallbackParams) => { + // -- validate + if (!props.expiration) { + throw new Error( + '[getPkpSessionSigs/callback] expiration is required' + ); + } + + if (!props.resources) { + throw new Error('[getPkpSessionSigs/callback]resources is required'); + } + + if (!props.resourceAbilityRequests) { + throw new Error( + '[getPkpSessionSigs/callback]resourceAbilityRequests is required' + ); + } + + // lit action code and ipfs id cannot exist at the same time + if (props.litActionCode && props.ipfsId) { + throw new Error( + '[getPkpSessionSigs/callback]litActionCode and ipfsId cannot exist at the same time' + ); + } + + const response = await this.signSessionKey({ + statement: props.statement || 'Some custom statement.', + authMethods: [...params.authMethods], + pkpPublicKey: params.pkpPublicKey, + expiration: props.expiration, + resources: props.resources, + chainId: 1, + + // -- required fields + resourceAbilityRequests: props.resourceAbilityRequests, + + // -- optional fields + ...(props.litActionCode && { litActionCode: props.litActionCode }), + ...(props.ipfsId && { ipfsId: props.ipfsId }), + ...(props.jsParams && { jsParams: props.jsParams }), + }); + + return response.authSig; + }, + }); + + return pkpSessionSigs; + }; + /** * * Get Session Key URI eg. lit:session:0x1234 diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 04756060b2..258333c7cd 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -2,11 +2,6 @@ import { Provider } from '@ethersproject/abstract-provider'; // @ts-expect-error JSZip types are not properly resolved by TSC :( import * as JSZip from 'jszip/dist/jszip.js'; -import { - ISessionCapabilityObject, - LitResourceAbilityRequest, -} from '@lit-protocol/auth-helpers'; - import { ILitNodeClient } from './ILitNodeClient'; import { AcceptedFileType, @@ -22,6 +17,7 @@ import { SymmetricKey, UnifiedAccessControlConditions, } from './types'; +import { ISessionCapabilityObject, LitResourceAbilityRequest } from './models'; /** ---------- Access Control Conditions Interfaces ---------- */ @@ -79,6 +75,10 @@ export interface AuthCallbackParams { walletConnectProjectId?: string; resourceAbilityRequests?: LitResourceAbilityRequest[]; + + litActionCode?: string; + ipfsId?: string; + jsParams?: any; } /** ---------- Web3 ---------- */ @@ -179,6 +179,7 @@ export interface LitNodeClientConfig { storageProvider?: StorageProvider; retryTolerance?: RetryTolerance; defaultAuthCallback?: (authSigParams: AuthCallbackParams) => Promise; + rpcUrl?: string | null; } export type CustomNetwork = Pick< @@ -888,25 +889,14 @@ export interface GetSignSessionKeySharesProp { body: SessionRequestBody; } -export interface GetSessionSigsProps { - /** - * When this session signature will expire. - * The user will have to reauthenticate after this time using whatever auth method you set up. - * This means you will have to call this signSessionKey function again to get a new session signature. - * This is a RFC3339 timestamp. - * The default is 24 hours from now. - * - * Example value: - * new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours - */ +export interface GetSessionSigsProps extends LitCustomAuth { + pkpPublicKey?: string; + + // When this session signature will expire. The user will have to reauthenticate after this time using whatever auth method you set up. This means you will have to call this signSessionKey function again to get a new session signature. This is a RFC3339 timestamp. The default is 24 hours from now. expiration?: any; - /** - * The chain to use for the session signature. - * This is the chain that will be used to sign the session key. - * If you're using EVM then this probably doesn't matter at all. - **/ - chain: Chain; + // The chain to use for the session signature. This is the chain that will be used to sign the session key. If you're using EVM then this probably doesn't matter at all. + chain?: Chain; /** * An array of resource abilities that you want to request for this session. These will be signed with the session key. @@ -926,38 +916,30 @@ export interface GetSessionSigsProps { */ sessionCapabilityObject?: ISessionCapabilityObject; - /** - * If you want to ask Metamask to try and switch the user's chain, you may pass `true` here. - * This will only work if the user is using Metamask. - * If the user is not using Metamask, then this will be ignored. - **/ + // If you want to ask Metamask to try and switch the user's chain, you may pass true here. This will only work if the user is using Metamask. If the user is not using Metamask, then this will be ignored. switchChain?: boolean; - /** - * This is a callback that will be called if the user needs to authenticate using a PKP. - * For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. - * This callback should use the `LitNodeClient.signSessionKey` function to get a session signature for the user from their PKP. - * If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. - */ + // This is a callback that will be called if the user needs to authenticate using a PKP. For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. This callback should use the LitNodeClient.signSessionKey function to get a session signature for the user from their PKP. If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. authNeededCallback?: AuthCallback; - /** - * The serialized session key pair to sign. - * If not provided, a session key pair will be fetched from localStorge or generated. - */ + // The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. sessionKey?: any; // rateLimitAuthSig: AuthSig; /** - * Used for delegation of Capacity Credit. This signature will be checked for proof of capacity credit. - * On both manzano and habanero networks capacity credit proof is required. - * - * See more here: https://developer.litprotocol.com/v3/sdk/capacity-credits + * @deprecated - use capabilityAuthSigs instead + * Used for delegation of Capacity Credit. This signature will be checked for proof of capacity credit. + * on both manzano and habanero networks capacity credit proof is required. + * see more here: https://developer.litprotocol.com/v3/sdk/capacity-credits */ capacityDelegationAuthSig?: AuthSig; -} + /** + * Not limited to capacityDelegationAuthSig, we want to be able to pass in any other authSigs for other purposes. + */ + capabilityAuthSigs?: AuthSig[]; +} export type AuthCallback = (params: AuthCallbackParams) => Promise; /** @@ -984,7 +966,7 @@ export interface SessionRequestBody { siweMessage: string; } -export interface GetWalletSigProps { +export interface GetWalletSigProps extends LitCustomAuth { authNeededCallback?: AuthCallback; chain: string; sessionCapabilityObject: ISessionCapabilityObject; @@ -992,6 +974,7 @@ export interface GetWalletSigProps { expiration: string; sessionKeyUri: string; nonce: string; + resourceAbilityRequests?: LitResourceAbilityRequest[]; } export interface SessionSigningTemplate { @@ -1545,3 +1528,84 @@ export interface MintCapacityCreditsRes { capacityTokenId: any; capacityTokenIdStr: string; } + +/** + * ========== Siwe Messages ========== + */ +export interface BaseSiweMessage { + walletAddress: string; + nonce: string; + + // -- filled in by default + expiration?: string; + resources?: LitResourceAbilityRequest[]; + uri?: string; // This is important in authNeededCallback params eg. (lit:session:xxx) + domain?: string; + statement?: string; + version?: string; + chainId?: number; + litNodeClient?: any; +} + +export interface WithRecap extends BaseSiweMessage { + uri: string; + expiration: string; + resources: LitResourceAbilityRequest[]; +} +export interface WithCapacityDelegation extends BaseSiweMessage { + uri: 'lit:capability:delegation'; + litNodeClient: any; + capacityTokenId?: string; + delegateeAddresses?: string[]; + uses?: string; +} + +export interface CapacityDelegationFields extends BaseSiweMessage { + litNodeClient: any; + capacityTokenId?: string; + delegateeAddresses?: string[]; + uses?: string; +} + +export interface CapacityDelegationRequest { + nft_id?: string[]; // Optional array of strings + delegate_to?: string[]; // Optional array of modified address strings + uses: string; // Always present, default to '1' if undefined +} + +export interface LitCustomAuth { + litActionCode?: string; + ipfsId?: string; + jsParams?: { + publicKey?: string; + sigName?: string; + }; +} + +export interface LitEndpoint { + path: string; + version: string; + envName: string; +} + +/** + * Signer that has the ability to sign messages + * eg. ethers.Wallet or ethers.Signer + * + * for context: This is a common interface so can keep this package clean without + * importing external libraries directly + */ +export interface SignerLike { + signMessage: (message: string | any) => Promise; + getAddress: () => Promise; +} + +export interface GetPkpSessionSigs extends GetSessionSigsProps { + pkpPublicKey: string; + authMethods: AuthMethod[]; + litActionCode?: string; + jsParams?: { + publicKey?: string; + sigName?: string; + }; +} From abf9c6ebeed3e06f9a98dfda0913bef77ce18261 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:14:36 +0100 Subject: [PATCH 007/263] fix: migrate types over to `types` package --- packages/types/src/index.ts | 1 + packages/types/src/lib/models.ts | 170 +++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 packages/types/src/lib/models.ts diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 0275f0369f..f80142dc7e 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,3 +1,4 @@ export * from './lib/types'; export * from './lib/interfaces'; export * from './lib/ILitNodeClient'; +export * from './lib/models'; diff --git a/packages/types/src/lib/models.ts b/packages/types/src/lib/models.ts new file mode 100644 index 0000000000..550a63eba1 --- /dev/null +++ b/packages/types/src/lib/models.ts @@ -0,0 +1,170 @@ +import { SiweMessage } from 'siwe'; +import { AuthSig } from './interfaces'; + +export type PlainJSON = + | boolean + | number + | string + | { [key: string]: PlainJSON } + | Array; +export type AttenuationsObject = { + [key: string]: { [key: string]: Array }; +}; +export type CID = string; + +/** + * These are the user-facing abilities that can be granted to a session. + */ +export enum LitAbility { + /** + * This is the ability to process an encryption access control condition. + * The resource will specify the corresponding hashed key value of the + * access control condition. + */ + AccessControlConditionDecryption = 'access-control-condition-decryption', + + /** + * This is the ability to process a signing access control condition. + * The resource will specify the corresponding hashed key value of the + * access control condition. + */ + AccessControlConditionSigning = 'access-control-condition-signing', + + /** + * This is the ability to use a PKP for signing purposes. The resource will specify + * the corresponding PKP token ID. + */ + PKPSigning = 'pkp-signing', + + /** + * This is the ability to use a Rate Limit Increase (Capacity Credits NFT) token during + * authentication with the nodes. The resource will specify the corresponding + * Capacity Credits NFT token ID. + */ + RateLimitIncreaseAuth = 'rate-limit-increase-auth', + + /** + * This is the ability to execute a Lit Action. The resource will specify the + * corresponding Lit Action IPFS CID. + */ + LitActionExecution = 'lit-action-execution', +} +/** + * Prefixes used for identifying various LIT resources. + * + * @description These resource prefixes are also used as valid IRI schemes. + */ +export enum LitResourcePrefix { + AccessControlCondition = 'lit-accesscontrolcondition', + PKP = 'lit-pkp', + RLI = 'lit-ratelimitincrease', + LitAction = 'lit-litaction', +} + +export interface ISessionCapabilityObject { + get attenuations(): AttenuationsObject; + get proofs(): Array; + get statement(): string; + addProof(proof: CID): void; + + /** + * Add an arbitrary attenuation to the session capability object. + * + * @description We do NOT recommend using this unless with the LIT specific + * abilities. Use this ONLY if you know what you are doing. + */ + addAttenuation( + resource: string, + namespace?: string, + name?: string, + restriction?: { [key: string]: PlainJSON } + ): void; + addToSiweMessage(siwe: SiweMessage): SiweMessage; + + /** + * Encode the session capability object as a SIWE resource. + */ + encodeAsSiweResource(): string; + + /** LIT specific methods */ + + /** + * Add a LIT-specific capability to the session capability object for the + * specified resource. + * + * @param litResource The LIT-specific resource being added. + * @param ability The LIT-specific ability being added. + * @example If the ability is `LitAbility.AccessControlConditionDecryption`, + * then the resource should be the hashed key value of the access control + * condition. + * @example If the ability is `LitAbility.AccessControlConditionSigning`, + * then the resource should be the hashed key value of the access control + * condition. + * @example If the ability is `LitAbility.PKPSigning`, then the resource + * should be the PKP token ID. + * @example If the ability is `LitAbility.RateLimitIncreaseAuth`, then the + * resource should be the RLI token ID. + * @example If the ability is `LitAbility.LitActionExecution`, then the + * resource should be the Lit Action IPFS CID. + * @throws If the ability is not a LIT-specific ability. + */ + addCapabilityForResource( + litResource: ILitResource, + ability: LitAbility, + data?: any + ): void; + + /** + * Verify that the session capability object has the specified LIT-specific + * capability for the specified resource. + */ + verifyCapabilitiesForResource( + litResource: ILitResource, + ability: LitAbility + ): boolean; + + /** + * Add a wildcard ability to the session capability object for the specified + * resource. + */ + addAllCapabilitiesForResource(litResource: ILitResource): void; + + /** + * The AuthSig they insert would own a rate limit nft and can put restrictions on how it * can be used. + */ + addRateLimitAuthSig(authSig: AuthSig): Promise; +} + +export interface ILitResource { + /** + * Gets the fully qualified resource key. + * @returns The fully qualified resource key. + */ + getResourceKey(): string; + + /** + * Validates that the given LIT ability is valid for this resource. + * @param litAbility The LIT ability to validate. + */ + isValidLitAbility(litAbility: LitAbility): boolean; + + toString(): string; + + readonly resourcePrefix: LitResourcePrefix; + readonly resource: string; +} + +/** + * A LIT resource ability is a combination of a LIT resource and a LIT ability. + * It specifies which LIT specific ability is being requested to be performed + * on the specified LIT resource. + * + * @description This object does NOT guarantee compatibility between the + * specified LIT resource and the specified LIT ability, and will be validated by + * the LIT-internal systems. + */ +export type LitResourceAbilityRequest = { + resource: ILitResource; + ability: LitAbility; + data?: any; +}; From 7dbed05d00e3fa520b4a49c9b200d415f3fd7880 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:27:01 +0100 Subject: [PATCH 008/263] fix: remove unused testing code --- .../src/lib/lit-node-client-nodejs.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 42ba2ff2b4..cde9abac88 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -735,12 +735,6 @@ export class LitNodeClientNodeJs let urlWithPath = `${url}/web/execute`; - // @ts-ignore: for testing only - if (params.version) { - // @ts-ignore: for testing only - urlWithPath = `${url}/web/execute/${params.version}`; - } - if (!authSig) { throw new Error('authSig or sessionSig is required'); } From 50978357c2538e306e54a7139249a9c968b68161 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:27:20 +0100 Subject: [PATCH 009/263] docs: update test commands --- tools/scripts/tools.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/scripts/tools.mjs b/tools/scripts/tools.mjs index 595aaea285..40b889ed7f 100644 --- a/tools/scripts/tools.mjs +++ b/tools/scripts/tools.mjs @@ -1329,8 +1329,8 @@ async function validateDependencyVersions() { ` ❗️ Before publishing, make sure you have tested the build! - yarn test:unit | run unit tests - - yarn test:e2e | run e2e tests on browser - - yarn test:e2e:node | run e2e tests on nodejs + - yarn test:e2e:node | run e2e tests on nodejs (legacy) + - yarn test:local | run e2e tests on nodejs `, true ); From 41108df70037d4d8d2eced4901fb9e0393482802 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 18:53:06 +0100 Subject: [PATCH 010/263] chore: remove bun and update gitignore & comments --- .gitignore | 3 +-- bun.lockb | Bin 1796628 -> 0 bytes local-tests/build.mjs | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) delete mode 100755 bun.lockb diff --git a/.gitignore b/.gitignore index a7c51e3dec..2eb071aa86 100644 --- a/.gitignore +++ b/.gitignore @@ -70,5 +70,4 @@ storage.test.db .yalc local-tests/build -local-tests/setup/networkContext.json -note.txt \ No newline at end of file +local-tests/setup/networkContext.json \ No newline at end of file diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 06f94ead1f05e73510f7ed3f85430e3bc1594a87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1796628 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⪙C*Qk#%_mUwwe8MaMI2fKsXee{k}uO-gt--q1dLEB}DQao)}8}oqoYE zE_Dcke`>9*mBg8W42QDWX}ktE!}EAuqKSB4>53WmC)=^d4#ZKJFnfzt?^JAbSvSoD z7KTRGbcDIo*tCzafBsQD`ekb_n7)VT80L7fjg{t1T8y0zV@Ei&Y%fJAg(W&957Tz# zrbT)AW7>OX<%R!%u3OEdohq7E$4)qml};WS*&(F_5tNH_$zzj4$;yo*B-#xTTpP|( z^oWoJ4kI59u5Wwd3*%8tAXM=ziu$xbYS@M6Axea@wJfnVIetv8Qc?9#iXhc{=rE!s zf=VVVUkq_$8yX>(YOQkBcZAsLtt?e36|4SShhevym`9&>);!}d%GURH0mW>hU9VCC zRC!;Ol|<~?%J$vF;2ObM>~jbMtT=9LY$#8bq+NPn{iN=D3)hDR)=~ZOjtbioX;f8K z3QP6&JB*Ftv>S(p!t%wCJZuvoo0t_P$xm98rH-Fy`ua{?@+z6w^Mqz6lQd>Ejv<*u zMxLc`=Xhj+?xrgu}x8w3Egj z2+n#lWVfVdOIacENOqV)@ zq0x;DBaM&mnvdm$eC<{ZBlsC$@{vCT)D8b9vAS$b^ zpYCLWSK!LPkW9)$v5li6C!mGvsODCwX{dUlC0dQM=&V`UI4xOFL@^!V*k$PL zAOVCNWzl}gr99ix=4ipsvjToH?jjvZdE;!Cf(|I4r5ve59A!b7=E&%9QsG{dYl!br zXm6J|6z%~>z^k+rn(EmLW_v?Qn4k74?1tlJLx@3%q`iJ}5Yd|yY@YV9!y1Rt8j?{; z1o3i-0}u`+`AU}WU4udtd*xQ5P#o{Kr*sTOkJ{Lj*=ZpbJ7(4-M3NT6UM^YXFi0+i zkyRj(Sjmm=y@!NAlFX=xgcUnfZ-Ns@dqN<-7jnY5;xLkWrm|u*uuS!S_Wk$|J>w<5 z2nTx@THm`-pkx>phZ5aXA`fX%svU;CZATTA%9oM{%f(OpwGyd$R+&Vq8tC^_!9ITA{Q zZPIF*#wOA=p%#lmQD7@Y}jinWWE2}9f@QL@S;Y1QKW6-$d2 zTY+t0}bgm2Fg3tbM$mD6#cItre$5F^!cp(xTV} zWOHH$`s#}MvL~YX1V+{|PL7VaN-LA(_>^j`a`9th9NBv6Y=2cM5eq|O9N80=WSz$? z3E8F{pP5c)ZQT)lX(_qxFpehZ5LOA1g!4l(Nm}YstyQkx?50$MqeNxCu`s$EH+FTx zm4f+MbuGHa@zr@!D@r7jAT{>z6;Mqi)mYAmDoNl#yzKP(RCZ!r=7#%CLiia7D|L-_JsQC z%L}T8`eb?%$%Hc~?d-AFijp#6A3lf1M%=6pZ2`IQy}?$9V*Idw>U>&$Z0BckWm}^A z+Jiz$Yz8VftEM!EnnF6#(lW~FY=l9Xh$1A59;#<=u}5-cqqO!!V{9)ckPGaLQ&VC; zMUU1DQkeD%!Ct0Y>!eCLuzT}9BoTYT(C+dP13y{xK7=8O*zLxwC^c?;n?i1~P}1oz zB5tybjJVkxQc@0ztvi~3zM_?6?U(g-z2iIo)rT;|k6pi&i_+qxQrO3dOV`ews9%gv z*Dc`%G@ShcUiB;%MfPfd?JsCcwBJeA?)gj@_9nT#j4F(tTRfdB3`u6AEORKsP|T9FlC|HtV#XkeM@iJQid5+bGjb%;<_hBBF2ihx+TXt8I`tsw>};VAnY!m#IF(Y-0oU&*Ev zjxfZH%^kL)B~WQv6nhccmk*(?^BzN=IsP+j|tm+jbuk#+8v)^pwvAuWno$K={of{CzL++1=Ju@M#>Dhn(3l2ASA zYjmg0mlFaPqU4>%Y8Lw<3B|0VQ9>=rB3E1gj1J)f%Ii>l$t2PfHc!iqP@2P8?2EwO zM2r2h(dM7_6uvmZuziwQM_NW6zOzsm;>NUIxrz<5_fYkEM(Mp>vP3BMevqxA%1hSl z{Y>@kU6^J!HomeDsxZV&bQP%*)hrgPu25{3!xox9#agROC}vM=bl9FcqB7O(Eml2y zLD%S@o+!V!cJX}G6*o4E({MtxLKM?kqNEukq1emM&EfoG4{7Jl4ltxISgN zGKp4?hobBGrEWRqDo?go72!9IjxUym@GL^`ryh@0{(n^5v@jI*wRCKJ;& z-oGKA;uXoFhw9l^ zVspoIEzSI8AHtAKqPdd>sSw3z(cDQZ6VYNiD>~Am)H})MoyKx>NTaZjEP99^d$-`- znLCEUxx*tZH177dP~Kk#h!oL-ACprzf^mctFFDvV!JlkHIR~%4#3molN#S%a#>G+}O{H zv!d9Ov+}sH&q3_@55SFNQl4b(&PCU|!q3ik1;yS4%R0uJoVM96Co6^|`yXMHZGUgq z2%N#1nZ3>2c)se2pXBw5O5-hhN~@mj3+yQ#_xD`GhV|5-hdg1Jwndhj_Q-ct7lyd8 zJt#XPC21|2P*%JvI-BH3t2=2cc8DW;KGWnV85A@~%g=c*r0)R}f;0##fb2CA9g>Ny z8Pqm<->b?(lr4@Qp`_)<-Z-?~J=>BOV)-1R#D3iy?abNM_o`GFl8Id%lM-J}*jpir zt?5F@s`5yY&*+^wtxl+|Cg6|5G!z}Y}Q$<9$#{#ODyk+CCM*->|Cpv!-QKvG5%aA`9VY*$9xuQy4-o#zUM6!)Q*dE2Y}1Tz!q}UlIJd zuH>K+)$A=+y^aKeP&ldvt07h$q50%C1_moyW!`P9)=&62BdBT`AKvqXNX|2vV zAmkG?2&t!j<9VtFK7bKjrLvB%Op_RPzgHZj#n@1#5z*`tQk?3Z(lIK4(d?ul43+iN zE}o})kOnaFp+t$JvUvTT(yBLlV0>++9JI3a)GD4QgeyQO@2Ld%07i5llD%ZGe88}G z)uA7$4silH25G)imXtHL3?rfYB0a zmvBn8XSp!?52?u6m6xtAd{KmO00_w)mrwt38o&oI?75~!H5-Q69gc-&tPhSjF*@2q zc{1M@M;OP3#@A-HR!J#JR1Z`D!}h_<<9MW{!Z7lV6W_L?Pjn0zR)JrW#h+iKwL6VK zuo00?={~Ib>Ma%xw}H^;XwWQ8dxv7+@QR#`XjVCN0m0;u6#=6G3>yteqBqV9^Cbzx zuz8jhW5fvAaOsrL3wtd*SG{dONa}=23R@JOs~-3OMpHsFGpr=QNXjCuZuT1)=Y-Vx zN>!Y!1%h2qFh{{QQ8!8!OD)q6pM1^6L zr`?JYk^>Q zFGRm&+FRes7s6d2Bv*9RC>095{PN_JF(Nfl^ZkQk{ zgzC$Y>fZ!{*>C3fYBzZl0%QS<lJUn4i{eEu5%bC#6U)bR>%&s`mg0b`>BRiZ+WC3IVc6 zU}PB)!!X^-D$f~p(oWxN5HTZ8P68pi>yVL;5QC$U9m6cJ+A9{ty~W~W$Ry1&O4E0S z5mg9xfza&ch;QGbNeCEIU?lB@FIEzxBVjw$PpMcKJ11+mR>p_`!|tpRbqu_(OhpBx z0Svn@Mkz2~Wk?o1RBzZ6&2}RA%97AR*b9W@o!_Dz#|ni2K7g?`)C}(TR2Hk=V^Z}D z!)BUxY&|yUAyXI&rfNNtz3`QX5RL%BEFW{y=!Ou$2QZR*rLqkWm$`g85+^7 zdbJh^Mg!?1N?J)g1VT$V!-$d=0g@;iqjF|NF8Re9Qo_T1pA1vyGP=3Q1>)z1~x*3o3wN z>tPyeL*yhzKGY3gy@+Fsovn3^T~(ru1!=JhG_=r zNJEP-hRmtp_a*_w9O(vDKPTkh_Io`N`a`JVKj$yu$}M73S;72$x}I{dRMvX zcK{(D^5NS*QG@_KLJW>3F??~77&azp+Q;dbGOy5nvef4g6{mquAHaylloX_;!Z3^u+6!T`pHheF)-2H)AnTi! ziZein?%MKBxUhX`03X0e>P1>A3?rYgd!_nUx#(TIRPW=kcjo%eRv{b#LS!$9l7SCk zw1j+cRMJwhYFS*G07(5N;f)X>&3LjWNdn^m4BLS-pZY1=#q(lE5+m0tr;3Wz07U?c9*T-2)hiY!G3@e)g3XR$xA%!VsaVGaWujy0dJQixj-+S>m3urD z!X+TsWwS1?GAJ1^Y)Mg9X^lC?1Q;gIG+eMhaWZIwUeNJ1;-Xdv>w#dVJdUec#bP0V zj}XIG2Et8Zm^_u2c1#B5r58d_tloNyRc|8@qFYO>otB1&KxlR*lxCc*eI+6qAWdM{ zh_F4q%8)F2s9tT8ZWpq(?<<~!7D5LQqMHybA(GD_1n>b2TUwbXUdqAnX{$O(I?Cf^ zX|onrqVuVv(A8USvFe=x!X~E|s+mEaz_8btg*sMXC1TZY*r-uej<4NOeT*tFY=Nd` z`*J}7lNk2F0=4(OX_&-FZrp@bLKq<(i&}K?&6d8c3pfFWQBlTL0~pcDOggmn@#O@g z0t~x3Bt8`TVr=;|Z z*_s8Tam%~F2{6i|0@46RdD0lZwOmg20ikR@fMK^o%Fv9m=~%Qae%mpNUUUPYY(9Wd z=9q3TcSH^V!7jba7>}~4fPMp`Jb5nKQLZ#^1Ho)>8L|LId2?jI&T=KO4+!Pafbjr^ z-K^uSQ|>O(uIvML=>{wjs^E2vhGfx0s|ct7hFwc=734mpy=cp*P#6o_^i#sD2%zF! z!f10VQC2z@?y1NfEeiph0HfpI9b@I*_@AlQV3^IxIwo`XmCH#t5Td;n z>F~Y&mxeMw#Ey{q@`HrqQ8FNsh%Byv1cv^%O zAlUtQ?$ol(vu+^d-CP${0P;FiACdruNs}`q3l)ZuyqhlkQpBj<%tO+PteSNg2$6OZ zH|<>%@Bs|7zZ%Q5GsG}Vv!oNgGLUVY=9n#Ml&SC}~M6(X~gU-qY&VAt2aHE!3$S zr|MV0y64)Dt{bw?{!2uiSS%vI2te%Oh#l?^1!t}=B|>-z1Tz<9 z+!T73Fzf7b&|VNd?e8#lpNaoUp9mUlri&e_2WbMMDby^^ zFqIW+&ob3(JF8`#<4Jk=N>m7-0vM6~_0_956^7B`ILSJy6P~Ha?N5w|FD2sSDiF$( zCinox#&AT)V_GWKpOf9=i1>bQCN9m%=S2f^vwZ*IBoOkB3nKV(z`BwpBmoT53g-FF zu%|Kdi7{ol&mlS{UC?c8=FncH)$eOSXm>Qo+9@tYhiHH-fMF{@8d(xw7=tcW#qxp=VA#bnsSvVyDi*7*Vc3dF49Y`g#oDt>^_E?dc1oIxeGzT~ zVOyx*!Y$Q0P6PM=hVAyKQNCLBG)B^9`O>0#pyRT3e3SymbqG80IFcBVeiA3GL@Tev zS2H4~Mc4rZyI@yK(N~HU)q^a6Vb)g|iqm0iP1u~YJJ*`4g`D_mhd8+mglLCC+B5J0 z4Ev_2+A8*yMZar>e56I#2L$^ywpuFor2%959|B|k^@^PRLz_5I?90hLAnZ%%Raykd z0vP4#chik>#}rfmqwG-yhRKsUpJnG-byJ*VMF1zjXbIQ$jB6q=l5^E}h1P6ec1!zC zX+&Ck0ZxFCw4TE9)lb7Xnb6R**EF+k>$khyyHcKMZRcJfM0!CUGVlQmd+mU7^lgu- z;SK|`07mrSOC!ZPr4H3yc1JI`GspLy7SV-pyKDsT0gSvG)2vh&MpKBv`yakC6({HJ z>Z{Pq$$|hXfDt{Yp>AcECBU%9EW9ex{u9ZPhd7ykPjht?+E5N@skj6Ly8%r(q&Y+b zWC0A@LlZ;!K3J-27)D1LyT?9+G3dT_z|x1bve*Iyn`N9IBVyR>r`RDHzy~mFHOh)H z;X%0ww}24c0U_PK*Sj%3fMFJ#d{93nRpJ#p-c5}9huX(yrQ$9SHalyP6#-)kjHa?M zMm&lmWYMfWK(IU5lrPsa-}xFF4`4*EKKSYc$2y5&*CWbHJIj`LYo4;DJbNj1s7H(l zFrxi0C6Sg2!`S9Vm6|PIiUyX8j>(U;*J2K-NIOR^0KuM*uw|CJYv2PI&Ea}T>zS4c z!?5o!kdrL?Utm0`$Q=&p$c}L)921a|{wWIxiR%|-;j8HyS3o$FV~!H7M``ztgB*rE z&*aY4cT~u=D4F3fqWe=U^F4%d)M40OMf>2i*93rYC|jIFeCL`d6(tTLxiG0psaOzG z9EM#ar4cCcg>l+pg4kv#aB@;%o!-(Fe@a2N_gaHVL(i*CI z7MVJTW(VOr*F>xcneH&6C-}-&y<)NIo^Tj8<+9QNh<67ie(6_?_`)(Vv&fN=4~0q% zQCVS|!gJNT>M(4B&N|ibzM3Ws3B*v8JEpM9Ud~lN#tgHvDA`PhVWaEIgs2i3rXkUL z3FR2Wy>4jOLmFKZC4C(?E#b5yjxSfj*y1pv=OD!Jm8>uT;ZUO8Hc@Zr^aq`L-sVqNCFB(j1OT7AiKy zFlazX3%8m+hv<+zqW6w@Ih1zOEfg~WP)CGciX_#$?l7YH z%XTXB#gIgz6`a(h9UDi;0Vh-{S(b^@7-NQag+{@{RC^s_`mV!>-dSb7@8AeS0cVxE#vvB`>Q|HkGyHjD2ue3HXz0eWy(?U z-E)eH?GD2(y_KgJa77Q*d*U$iP8u{rli^iX6d+cwpTpSbFeV_Me5A$L=P+#c@(X}G z(qaH2hLV*M+kcz3>nA^ojjrB9QM}jDvBgP*msV*GVThaE4n?yztrf9t&He<2FEyg1 z({U5s7iIgj`Yvv4!IBk8ONmhIjSaTuMu01Z&mn&7>L}W9GGAq-a8yr}*ywQPjD=6D zCqiio$7c#q)CZD957lb`jNU-uxG-O3MFC><`29t_b-}x|zT-=L^(Aha9XDLVS(0@F zY%@?OzOzWQ9CrNJQ%uesYMjcDEPAM3k{>pqrfDV?g+QTDe)=bpE472t@ZG!$p~mr& zcT(j}fVWuE+JOTO!)$bIKtoy#$-{O>Sugm0@d-VZB?4(kD^c4^*!-o8FkbqkI8lybUj*9)M4Yf)S}HcWku7f*V0-8CFr*!=PEW}NecG|Da@=%; z7?gM=5?_jh(#LVLH_t*Bud#K1uvx!~ ze}pu7)*VU?PMxcANR1Wi^+n&Y6^vkkqTc`&78yA!Nlx6&;w?ngRV=s`hi7Z3%F^Cz zvCi~Hjdt?-=DJXOi$%#RU(owBM4+vn)LWB+d?ARA$j16|Lcl^4lL?iU!|gji(Ff_i3i?V`3akIx^Y%hxrjj-*tD9?;C z(T^*$LacPmL^ppklJPE}yz*tes+pCS@s0|+p`I1vn!~V_Co9Hte_8lvM5RtAK63kZjjca$hMtx$jQmH6wpS!|HK$`Z+x{G?s#jyX=E9iw>liN(3(VYfF) zMHX&`I!bK6$K{FWX|HYUAqOrs9agp*XyV2`TtYeUvNf$-9RbPT3i=8~VqNDj@{So@ zEUJuT6+2YV9);W0FWKPTK-^*QI)ovClxLdlQFwWau1(&iaCm(sN_NG~^IzBd=UEkX zgc}#T8z|JYih9OjG=~O6mf2@u)ThQJdcA-g`5r=f=da_h7*fquQVL1+mOEbT`8C^c z@}|85Z+dF?6gAa^?@Nc|VcO1CSr#hCjM+m%kQiSW5j@Lbm|Z3Y+lwil7dwPukFS$< zIqjzXX@PJX)yLn6O@8Jv z;cMAp;URwP=9_6Q_0E@uIEJ{{=Eh2MIPE+f z?6_%m7-?4DI3+tBhOK?OiS>#dNr~9imD>7BMHrGuo8yL*5Fss!NyNrRZADQr zPFN;Nb~}mK7F?Do?Z}9m&5j#UQi=kVi;}nhz9MJ0XQiuYd9m4SmYQuzNmgF$KA>9r z@+4lIP)!_y5L05iw^$HsVgsYR3}iSIGb5zLmkLs+UNyY7n2VpZgCi6h9^#XmIwm|0 z(PBTbTi_Ip6v%r(g#27_GD&U=-U0ONi1E>}XN}zwge3b%iq4@skf_ z!ZKeRVc6|kyC+U=#=wg!;uSlDA(=#b0#cC`#cV9?01?zjF*;bLdZMK{lnPPO(qb!M zQYz{pEhR~*WJT$4{IKsVQn82Hc4LaWXkU4-KT&Ky6VE$3eAgSc=OGM@j@hMhQJNhs z#1_8mtVE!?_P%{&m1rG(w3d0B0BYgw9aPnGkb z#(J?4R1)Q8l?;Q|2INF#LDgO()stMC93_KLpSt2Z6AMwA9g1|e*Uk$Hgkq1|l8+8m z6@M(W1S>&qL;p9v`@cW?S==v59>TcnH1@2cYCw?o@uupONp|YkhZ}b9C;xd!O^lak<{E_ukrPt+l_s*4k_Dv(Iqfr6(mt z7>bFVjfui}Bk3eW>Di}VY_;d;lte`s_BjHJh}xHq&6N}pyFTC*28;0RX#8L4DI(?# zEy!I-h}}f7)n453z1Jnuw-@jOqmL!_Ilzc(9}LAL?)D8qFIo%k&sV|xYPu4tJj ziWTuD73sn3GyF3Pr)`DO_%$n}Nzvc&FN z>_~RVi_+0iWNnN!dxVzjjqTYi+q4#l=3?wk5wW#EUdYp2411Z;&cpP9zoi)UhzLa% z5Cn2PIS`83HF%H_A+w>NLZ%V}T5P)zLlfU)2VUYZG` zUWH;0SJ{~U>Qm%DJfl*gcA23iBNjx*#($t&hkn_K4EW< zt;^KZihZ+Bakq*eEXMWH^vPCh=?F>3<7g8lp7YSB72}#U_)QeMLq!DcP)coSz7R*8 zQVfmJY#M1I$VOBr7U>GbMml#b5WG~n0E{nQnIT)Qe?y7Fdb zw8B-jCe^!9B+W&!PqNuPyWFuAw)(PN|}i!hWa z`)Zc(f9B+rCW_rFBUkp6pqM{1BTIx{g7E_!()S>;Jy+_|bFyNxGg-oj=0=s4%4&Ne zZ@DHOVl~N~zl@nIQDp5rni~s6T__KwtPe{h&!NJw|EXj%Sa#&jVqwS|+bNag2rX@* z#N3fRCH~m_vwtJP_C(LcktG(BnY0eDZ+cXUp_tf*7>M#P|6~?fA{4vJMXv5w=Ku-C z?z~5?_3_8*?qf00q?8klqO0%!6w3^IS|khioNq>D=huso$At$yPSqY`e222NV(5x zWQSsMEX9PabE68?kvBrIm8~y|U8l$Y{#c71N^?z?#M~)aA)8UzGuoZ>vE}A8KIRXj z)d%C}gb}+F#+DxCl%_ZJS=<*T#wW)H>ByE1$)EVJS)bAQEMdgIcM!Jv>Y~yGL_*m) z8sR?o8*ESTLBbGnSMODs^lk4rn=mwst9o5^VaS`k2_<)Ag)9{N&#$&l%M!_?JB~`v zKBf{^v*M3ySLI7r-b9vg73jMX49k->DNE{>C^l8w+v@V?gM_htlxdv9eZ8^&%S+^3 zD`=T4QDkRF*_OK_XhVrLmeNv>Y*%2<5p>Qe#jvM5=8dwx6hkqwHCDR;q0zIh(u}N~ z0mYSHT?mv(-&RM9t1Kw>=UU1(d)mwX`R0BphK-GVHiLPF-NDF4R6C1&soo`^FXYRo zP5{@Xj>aagQgS28*0Mw>I};!!L@ABQiz%+QvN0y~C3p5TEqQ)4|G4MN^{I&xPxNU| z>3>_;pZu};hvsP?TpANac2n|)XHY(i$SqBO?CizXjBW1vCX~g=pM%K~&EisjY^9z_ z7_=cbU!i(kwgn13k(Jc!D$-MAV@J(arJvH8Ninf2l?TwCmXyZC))QMDX&rw{G2~6m zV~&t~MYXd?Pbjl#d^l_RjL)+vCLbjXA`_#pKQjqMQSFNo=fFPx*jjCo?Hd#O#|f5e z^kPU%_KjlF=QCp(V$da9Nf?_k7nL-<7XO}OON$;LCdm>Z%_;WU4Sk`ldg+0lJsvU~SsX;NZdv(~| zB#Z37IhT&GoipOvx=%#pjXm*VO!}Z~LL|=*@&$GP!>$1PT5(~)^pu^2`yy~Krl)K- z&==#z>7fV*fDqTQeZ~WR0ORD)5dlVA!*UKVCOJj(>cxfA{!Q*&M@#O`2?3q}!)7dZ zdF$~j*(6J(XBd{@JY&+9;&pw|^wdm>r`E4Yy-O}Dei|X@tSya6R0!|`7&hO@<7kwQ zh+)`gh8WM>eI0F-9cyox<~N=(tl;LZT2+KoK(Kv->}OPSiflmVz_7dWYAe|!9O)Ux z&XFgR+EwMkc;iM{K~MVJBfU~XAd0Z7{k7Gl2S0!j_e6-1J1TXIdTzD#*~Sybs++3W z*`_&;Cxj1yFgsec$Yn%xiVzSBV9X>8@swkeaHMY-cBRZV%<|=v8oOK=n{U=xfP$VY zA295EMhtqPOy_Y|krnU+7?$DG=gPxbpHqbK+%3~nyHY&aif5xzD}Dq*>{7TR?lB@Y z3}$!f3XWI+!)6KlXDo7yVzK2`MUx1*Ua%J-TmeGNR7!gI0SsIDWQEX)*Hxs4SOCM; zaOyLjx!wrlp4)U@CP$VKZBh}!`y&LlW*kawfFHn!>k9fI^js?p!|o%o4d0F`wPW#O zozIBS=bXA52(zPAD|hu~Z}Jy@jI1Cp*N5vdZ0{-DTwA37%U^z zo&Y0u;k=rcY!Z(2?zm%`|7jRdnqRr`5W+4X*t#c9DFQkNhGiC`$d#{j^)-x-lP8Mj zqmzQ*a@qar60JEDa5PFixd;S{CR;M1!bY{TNDqDhV^8vf8043pM+{^42!nU9h2LpJ zMQ`s?or~xNEhvp9tN_MLEw=!ZRb;JU#PjUC(7JR?7T&4+WJ``J&&@eSR_q1BZ1RJg z+|ghULVzE@uo2NZq4_q+k~+qzksXuTRpr9ic$chTEc9E|99I_tJORdRvVyxc@^g0x zbqsrltHcJ{CXB^*>#WM&8B-$V6d`;F1e<5#u%$bD*7@dOyBMs_f_Btx~cNbkLSm0eUPLJv=XVYxvs_*=T}thrCC zc<%f_C#lGfkAYybB)9J-0!9QFc8ymu*NG!548!aYpDS2S5yp$lmErOvHzq>(0SIHtH_EC4^B^gGRO~D0SucZ^n$;dEnOB+CMyhMW@HD)MKbDj73tmm zQ1wjG)uJgA!rMTwy^?Z5l4gtMvGm{vFl_ZChT_rGZ#%AIm>rA*cNoOUDZ;qrVa<0U z^s!<`4S~2s$|nhTNAHcA= z&Xp#2o)f!{VP^r_QBs7le3j-pM^xM#BaO8+JNz>VF04fTnEOk z6bssLFMf01+|hWzj%TK)K1>+2fqp2*zJdhzh@is%NATKy{&)CKexX*i)R8XMtjV1* z6^xD3Q8T4T5`AsJ zZ~+4YhKf*gETE3`r#EZuBDc?V_Y4s1%u0mZvjBBv!!;m$oV?)GcAwEe0Dy6_mRF^@ zIrIGV)E9#gU5IFn#JT-z9z!;VpcfWl7 zn3Ud`haC-+JK#}ij_!PAdg{koL`%;_Pi~u@I$lHI3Yt^2_Q4Zi*m+<;ZUEy-&5lw} zzIb(d>gyUpX*A&pFg~kclv=UlwdtuJ1|h%-V0<~kDA@sOOxDg!PhA@!aM#r%KY%cU?A5Aq3qqIdwv5}9$e0gRzpx^@5c7(LNGakT*^Fp7sbjg9C=h;g@h#g1I zvn()vs%2N{3U>0X>8aB-gdSrGjQW0|biTiEu)2@zvnxk-1LND8C#A7i{`MS<2r!0S z%P)LKcbT;6l=^{K0HZ$3c(*>MXgB-hyVFze)uLI704speTy;vb>!w51a|vgA=??B& zAPl}nsbTQFGTjZG6jR0Xox|1jqGyH!BhJlz&hHN&8M^LaJm&}_);`{?zkO05U9Nb- zj-&PLs(xPnGsqrH+50dQ@pBQsOZcBto81WS(PMSAp6l`4pu9Id^-Qv!v!&;q&EvY? zotvqOj3To1eIZanD{`NS2;m?Q>Tivxk4aPr7_bqB;viWW#@-aq+_u7&{)!J2i`=!i ziEtbUW`q2Y#w02m5DQ?un*7jcNLGgNT*Am5O<}9AhfXLKl#rY2kq}M*!D2xh*g7{y zg@9N9<3P=iQY#F@o}cEPQ($T;vSZ6heWsM2i0ew7M7pp77&Eo(l&li~Lg^XCv4kN{ zN~5vr!)g9k7(fX%H$S9*2?&;1xqZt&A)s?$9I5$HYQ=(6`n+>)%cd3Y17X-|0Y8B8 zLGnXZC-o{cd(dCi%NA_RB> zjEDxWqWfWNPcse8(|;c>#rWwnS;5TW6<=2pN6y~{uOdjJUbnH5TSwV0ddLVzE@*fz+Ixx<(p zod@VoZdByUw)4~chESNp)_q3xA`rF@LO|zpgfVPP_IzH=PRJqd(3v-7%)XZM^^i3Koh{bjrR@QZsfSw$F&zO2qwuAQZG^*j)E zr NF9T%*#uON~gXZkwnC6x`hP_Kq4E^Td2xIRBjR-AZ9C}t{f)5z*`r_9Q!`2S0$ZGsQx2DD}fIHY5z%A#WzxK)LL=S#u2&qB(%jm9Q3!qgz=#0DMwM19!*35yfMI9Wz8GKqsQnfZv}T|>u~gy-jJHy5 z5rZpdX>Q&2lkPyUHRDhkixWVwyOp|=Qi^~P0fz0v2aGB(Y|qAXA`9)wDT?P~m$a83 zUg8Ha%|ESm5G7> zgFx6d%5e7IBg28QJz;S5C327RDlm4|?2v_k>nze+@v~M8s*_vl$)OPfTk>31dOpLL z0>hpUYmXxP0M}WhXBbbXSkMmcwIu5VsOUZTi{?m49Eh%-_5&fFb2Bd_p;lLs9{d1C zeZA;vSC!Q97E|LD9{Uv=`PVp?YV@0yUu1uH} zY+srk?4&)OJ=eL?y)XGPlSYMp@V7J` zR};qWgrQzaG5*o7=;;v=WQowas60tVSb9ml^pcZbBC92g7`e$sU77Js!my=77@BxI z?kd6nL_)ERJzujcDMGn1VH`=r!VNK(kK7^*Sz=prS|Ujfl63#@uS`$vOLlM(?PCYO zxK$g5z8F6yjJPS0yAh?Q^5mcXd%C4d4iR!ugrJB%JDM)s%$8;dzffs>P~?+i`4iiZEn}p_Gg)dlAY%`w#T6k#jCLH>wDCr_r^W zUyN$W*vN|4D;VT){pcHyxHU>7^?+(;kzO*y7BcGhS;(GA7m+ z0YpNvDMN%lL-U8fTD_vp9TfU3U+zdm@jx&8>l5+vRnVf$QLgrRuY^Ez_5oR*^e z@qei818v}M>FL4ZF*BO{v?MoAs_s?G9lQt*fS~DDW@;FYpO8zrFhufS1cu~ z_SsgKp5hTFOKMBn*0RczUNU5MG;ygSgR1InbwNCuFwBhHw!#wzzl2H;Cd3n!?l>wv z1!T77jilpRi!VL9ZD6ly_VvcDrViEYP(PEX?D(hukrI_HxFAcCi(re8owPOSay?RC zc9ODauwU*DOHVHvm-^M^BrhbFCI9z-tlOrP@WfE+3%@*ACw^iOxfJ7zgb}yc*j^SA zv#Ur?@rW07D3P=afimg+%l}025U11^TgYZ>3t1@!ziv(QR@U{n*_Tl2mXvNE62!3k zQWlU%b_Sz#2l8pf4o(yfjs}PU>MGI$L_&%411%{H$iMv0^q*PTXCH)h$%?pK?{j}% zzSv$_mXxMh9fhqGTOv*>&A7%j2wO^;i?T6AW%r=PogZkdE=BaFbbNpJ*L9go%NdhW zPwXzLU0e!-G^ePqPb$%1JKE8AbnDkbIaW|dmLx+g&18V+Bq%|ART-Atw!#($AQDQf z?i}1)v9#iJKU*hICRQzv*Kg7}!Ld_! ze3qE;keyBYo5#|#+aVTLPF}uO()aS;Rz!`8dT93CJeJ`%ZO;RP4ie7pEa_C zQSIxEO&lTTj*s*;!gj7<>s$o-CY1fjpV?ZLXsM@OR}qFRiSt!gtENmS|LE`Nvsmgs z*B>F+BiUhlvo}*bYzFIws`9OAdGlCyC?0lOmD#~8EA>VwwxdyN(PrPxCH?+A(yL3ZmFPDZ>+F6hdQSS!Y&l&=9*?EIn(#F z^?Uz=e9^SY@q;?@<(8E4b|G;G_>4tvScS1OVc5evCVZb0g%W;uiU-rH#3NZE6dN0& zNP_CbB3-+I7Yj5ejwa6}5Mf+MF^SDUZhPVjL*CfZ+BZl3_21KOv1DATc08PXv6zyd zyChaIjwKA+2rx(FBXuSf=_($tkCqWiN|&N!h=r6L_j&$r3&2~+jJ^r~ZL(v>APfbh zzP?Wir{vABzCFm6gUKH|Uok;SlC5b;EUl8r<}NB-MP=6@f9_BI*jrJ3$Jie8?oM`a zVePY!{NZouKcVlsVRxh7 z?gFid$eTmS8*vqzt~{-djqQt$Ck$C2nv3zfe_u}mc;e1o4y#r)-`%=dov}7WX(3s zW9c1D7_&7y`UWKajnm?0cOA#FWF3%DS&o&)GiX4>389`6vLj3+RjdPi00aXXjFzq;p~B;n@xh4WPs!f$V@WB zu6V_h&Lk@RpA&|ChTu*#q8p`S`{(~qkF0WsL)OWP4ao{SP3899#IT#ZduzEaeCdv( z(t{bvk~lliqg;!GVmATfvrs(Cl%|IzswKP5Ql%L3#?oE)Q*y^h-u$corTR((TbCl( z#%?x^3`c{Mr-Xv;6zBrNIOo5t2Mgg!8yr7^YF-6KZ)3MN^cT zU8RX)8#DRS)v_uRihU$vXBr#kdC6KNj1wuY<_+UPer{ZZp_m*)vROHW3jhIkax{fF&GbtuQPTgeuk-kuDJ>vLscO~g0An9#S{%lW{a8&qP z`l^R4i3glS?;90c8~ggRF!?hK(3oVMhYrZB$ybAK8TKTVGpdlSi6Ar6~5LFLABX=|Dp$e>SI4o~hZ< zP#t?Hj9(H)>_FL|)EC9oR%-1}`l7@Qe%UzIiHbnF_Oj6XDJJA`HR)@~p;}}$(v?nI ztFlBIhg(*vfvU3#MT!gAWwz^qN*j~St4#!qy z$zGVES4(As=-9?C5QgQw`NDGs`I6;gC?d9}=IF4LS|SvCNKcg9Ok;1d`MDI6xX0GV zpX!5g+R;xg|akR5-T;cBzHF|4ErxkmaiOLV)V_|ndFUHivqB-$P&dQRsvqH zn+O)-1gT5#?q}W>S_r-WEVeA}@F|EukO>b-_=SEb$G*OP#vQ|=Q zkE7DFClPk$Auo3p6IU4aVN)An@y7MrTjAsVTLA#G>F`*r~c}8!W-q=1= zTx#SL=_|6acgtxl9icpuVlp?M39!5uvU-|Cr7wTt+%u_VRo+CgJIx#+UCULq$JK?h zDMiKZy=&G;HmG{RlIS7oxK`AK8yi;u`5B2t}M*)NV-C?SxheN$;}m^*g3=eVeiDq z9U)fo$s2n@(-%YD*t*si0VpksMsp25t6s^ejJsaM(B8ot+?Y_HTlxF^YNjCp>t1P zf9%{te~8`}rT%oXY4^Be`D1U{*}hG@QcG+#usO&~VcwQvXml(l%oHNXB2+tz^z1p0 zjj%?ivtdOj4EryYarH%&zTO;6d7{>$l}=l$vP3c2Im*~RF|il+ZN1lCxYUyGV2Zvu zfOlfpK6iC$dSfFjZmA`9&tce|-M5lA_H|HRkgck5uvRn*}j@|oEe)L6|N&aw8z>>SxsyDkv z7`AJ(r;5Y&v5Lu#QMS<|S(#kx_#-``4BOvt1B||Okl8lGlG)nmD0e$tNus7d!>$9D zCx3=T_REA}SH{eF<=Z4rC~taWD4KbF=dpc8tMB+cp8Oe>C-zUHhuHx$k|o35)w6xy zOv*JzJ2$3nqcb=2co>S^hpF%UXlqVUwp~eawKJf2Iqj(OhTYsmI!6oJ->y?pJ8jsT;4Yvb`DichTU_wv$^G3 z-`OWiVufY4C}Sp#b90PmQr^>+KAEy&!NMs+$n9VD$&TYduswx1(wIc0k9YvX?j@B( zg7|d|i>N#i&9&o^>4j5v#!^e6=OTOogd=G@gdm!Wz$v$I%073h-bHgUo>;hWYWFBB zm>Ic6JzW5TjVW7;n}Z@<_yG)C3rj3uA9W0i1>?xy(sli@MGL2f-F>uOh(NgweX?8)96l%4cI5v}$%u3oVM81-FU>4?A+U>qOKlH3_W+hoVi z8yEW5(lfVuULgWw*v=B30AtuW_THNo`gglN08i*mZafr=OF*#aa(xlt2QcDY5RRzO zQSB_!d*J4U{)Oa98x(E>&yHyVlrtN_L^E7sn&aLVor>#m2;>2Ft& z-g`jUJ}4^|EFL$fkQs^1S*RJ$VCumTu%PL*Yo z+Da~ccmj-FX-vc`&8>&-(E8ms7UzNR@}RtcAHXm_`dVQab{6T2@$?eSGDefvoVja; zqW=XDPNi6|^}YBlUBBT6Fow;urF+Y_h98V(FQ59mxpoSY&%ZeKQZ{XGr@dq1vkW+4{9I6P<#pT1|| zRD8A~_kJBCrAWXEVAxer?rNh*3uE?P?VmXgeXRHe2xbGbp=V|R!>-wBSAPuK=MbYL z9*V`xebuu7K>D1EfMMqWp%N#jNFSpLjCj_}wvtW4k=~=rtM|1gwW`X6@DmWs21b%x z&DW}STU`k70~mH?rE_}j$ks9J?izXGxAoiPN%xWaoBQ}uD-MkiWJB&ekqw9iFwUm+ zLcNPN?QR~|G4>`5jYTQO))hLRu_b?n-t4t`EWICq@J_NpoKhPQ3t-gmY?WfHe?SPd zBDXbtlGUFAVP>cwz_681`OO}3imX5^fMGj~ThWl?n!9odFNIzl)Hgjjtk z?QvcQM$FS(AJ~_yKrDb^>jnA5DBT+@e5i`RXlkYqv8%|6=YcSr@*+0|LKVV~K(Ke2 zxk`vDtu88EL}KIzG3Y~Xj@L1EBv1P8a-MitV@j(z7Nu640>UsG5DQ=ozA6Gn>R!{q$PEgCoY0SxnlZOPBY5yk_L>Yf(u zXKUpbs+~m$umTwN-{9DQIDE4|r_?d*4mL-m&ziMjt)7_CgFXoG1Q>Rgkyb3palv&e zo;;>|Qsm`ElQ4A*o2ykm>ywHwZhBl#t2n0OPHIiLbhiN^Y~ZIXN^=YG1jgPp&xD#g zF48v)+wsvl#W7tlKDtaTWq278ZjN8`fs$X%Gq_tUvDZPC_ zu+;aGuheTuWrd>p-xx5p7^r^_cCz zupJ+-G35)Y6N{`sEPyeS@-w%8feT~(dU--lZXAdrgv&sfNjB)JND^vw73skbVA%7& z+!-odVchz(W?A1z%mTr_Y>?Q@jNEH~*#JL)VV~V)B+1W>XdPo_wB|4#r5LYnkS83G zhkGEr_e^zn0D$6eD@81TVfR1e8*x}JocZbd4cNZ$%M5?-Z%%y!f(czOYE#AG4ud<5 z(s(?*Q8R5RT5}aHMfeN|v!gL#>(Vs`eq4u z1?}f=k9h(NoA0!M81e_z&LX|d&uQHvLP-$PcJ+zI zp-p-!z_VGOGa5Vr#_Y%nMwDw{PLU_CZeBQL|FxT~=*PV|&7mU%SOJXsQ*O@qoKnZI zaV1au5{xIG*V%;YZ=W^iG!V=N^;;1FzmT3aql2dW|19lZc&Dpj0QUq0;~Xry`Q<*`Sd2I2;;4-)idiVG?io$ ziu7Q`2t%tyZajo>;6TKU^Iph| zX2}3MfU$c}G@jh9HKVT;*MMM8YnW4vM`>Olp1`p4YTq;3L$i9~qr58Jr@RRSdvAa# zl{-JEtIS%rqq=GlK@w_p73qBeglE!tQu{XiO48MuGU*|fz^L!oa($^|*qDmPamgvt zU$;}4$yVf+TJiM=K`lim*&!Pc3t-HS;+dP5vY6B`cBKk;7P(gfRg7)Bs#l4W9O=RnV8r<>H=6827`N{h0$Vell2EIwNN+n3;<|`)RFbaNlt~YM0K=|T z`9=z7Np7iQ)c1{C|5ywksHos)&s|Tw@+znaD=N4!!;TXK^`c5L3K2}h2&Io?S3A`tA9#yE&uf`C{6qn_xwQ(yfpdtEpE z7=b=1b^-|X@hFWY`~b!aDG_N`pYbq^c%av3%HH`#)svi&kdC6c4+uMxAM`<7X?0QQ z!jF*^)YpYYS6j*I7`Ay-EKA2^-+tYKB|2N@&en<*z_9Gh?Y+elVAy7*FUBozR>wp= z3sr( zv&j$LR4QF@5DQ?~>dWjdDY9biTh(axK{x}1I0N)SfFHp4Xp|RU}0^xWXQ+Y8d0+K6Yh$b-X;eYN7ZDQPbxO!nz zf+8#40Ya?*#4n8m`~b$G6bo4(blE$OO3yGXp28@#WAhQMoI)7aYm;BG0vL81Irln5 zSal4GM&C2h=A$~J_O;?N5H^lh-`q&jmx>?2uob7IeHCNsm_C$9ZthKxD#9Kh*afe~ zG}o4jAHc9#rty%BJ#`i7Av=L#FFEo$l_huO5yqnTs^^hhFW8e1uGJ94rN*QpUHAbE zo9*QFvBEIy_EzpItFlja96YWYz;{WMNreC_fMKI5PjbDfW7urx<3tw8>}dR7>D~6e z9#CknHNH(w9eHNdL(XbSqn&cKz$Q z(*GU^HruH~ZjUhqMm;aC@2{OBD-a7{#9k}c2BHe%r4yR%TDRK!yq+tBZ-HQssY`aP zRU6<3F!rRgfbPNM`XVcCJgMx|mD%+cw{wJW5D0ebm8-9~?QQB@>B0|S%p^ZFPwSfF zkLnmUraBAcj*Ku?e5h-F&9c&Ho&-XDu8+68E|Cq01u$l6d#$?W_@g?;C!^f~TSzv( zwMnFR?389mZWM(q1b6}ryFaHLbS_pM!_H?M3*tzo{>D-1-FaGP#J;1t3kY_#EI&%~ z;zuCZ`mJ3>DFUJijNNHWiNRlaI4%O>OYfeKWJT^cG!ZTU!ScIrB;dygLw2c`NmTmN zA1gQeu30lcu0@0EYR|cT^3-?&iyr(s}m8nW`tbt?89K`C){hS(b|; z1o#0A+v8}xkgOTM=CSk)V|KJ&H1)cUh4JjC+T-+%<~bmkABsg+zg3xRfFHm(n*5Lz zxmP8^c;GXg0s30;77zxn7r;1}{E%H$f4l0^M=XG0FVgj$XWPzdx29Mq!@4Y>tYQT) zY*aNOliEsN$B2KMAbAcI#?(2jTJ(T(taP5eGD1)^OA&q=At(~12pCgf*m;EOcW!$| zN|7)O%Poy6k6}+0`ewM6pTg5ypVs z7BFVh3atL+<0Oxyx8+N%e2V6zmXZtM8zAf)odv{|Ru`2nVgZcZ2}7}vKV9u96ULnv zG)FY1x&8=Y-w1)6+}2ea;0G}5x@s84Oo~O{xw_{oWd&oQGXX7~R1^z%0t_3GzVS2+ zTf>Es>yhkO`L*t@5rJbONvM^3B9x4ZdV(Lohz|tb4V>I{xQ=1>DtZ67&vS)m zzR}Cn?44_#&{6Fy(t{_!h^vVwJ6qL-b&U8hitf_YwcC$`vHDv*ha`tDQ!R~f)#ma46wE<%a413nk_RH{FIwHXMVd2!N6boXo zeLsv?J%t0PiAB-)=AxpZwR2)qR}ca`0mjDBsL~4l=9D@{{kcLZ#uGnkf55!TZA~j> z#ZN$(8O@SD*@;+;F#1|y7`A)m{hU6l&eorFty&U?YAj#{Ff1CxD8W%Y4I{1x`e58~ zNh=rgvm~an;vf(#J2}7l*Z@C(v1c?_i6L}UJB#!T!|sHzJ%3B*`;yDmH@5ER?6)qI z6|VzfXYzyc-2SO61o#0AyYo6=#Q?@TH9LgQzPgI^mR-@hMNXeleFq3O%QP0bJ6PF( zSPZtpFybw`KAu$V(5jV-BVRUO)fGiaR&b<*@aYJFc_A(}CKc(z4`A3?V8C1jMm*&v zc4;i`|9L3FyFi#7trzsa)CR-?7`ARPp4{zdY>C%ZD)9tHJOgA*wQK5XPgxzqeCeAR zFaM%dhf&D2plZc6AjBF@Np7k5QL}>WC7XmLz17!rt*S^!l8bN_2=>H(Kz;+m){ESn zl6A5cxdn{bl%M1=zjCpJu^S+ot9>y5kx=ZcI27f;Ab;LWme^i;s3pVv`Ln;Q9O-KZ zzv@>j7{^t=%7ZS-K3PsD49hd)l;;Q_Dkwr0+9WFdKl+vG8m5>`YE8KiZm3w1o9Dt8 z#Ck)H^0qb)@vAFV#t#d_*H;RevW7x999{IB_Sz;I^ zXI=Iuj877VJqO|b_V~3rZ=Ud%P&vX`J36r zU*V(LS)>PugcAF8Hp?C1CQAJ(D)&0SiDLgQg7@=s=L~HY%KGGwS;EojlV_(AhMj*o zD!K8f+M&qKjLzb@aFf+}b1_BC%^=OR>{`SZV~S1060 zE{g0}n|z7?khL7}lCh_*B0c$HDI#uH%c@NJfAFgdr%t4yy|pUNs0-n#N&b&8#gz-;)O?xZ7 zIVOqWjsGh>h1A|&;0nUu+#(d4boP}{Z2JIyC7XmLJ=?L)rUc#8gfik*3LTgyhFY)<2A?<_Gta9H*CTZAERj*aq!2&Jj^ zQ1a$f!st7He@+-5k1$F$dKGW<0pXH#r^|xanar>SjdQ9&{UOqq4VR=&|gjvCcJFTeYHm@fBqW_ z`7gARCFJ!P7g=IUqI}6kk|il5dq-1-%}XI(nga|u6PDx-3=AGki{Jgv7fxMFzR-u< zO+*!8Ciyb#zU0+}@%1Rp`gl@-(2!`vXl_@L-UkW8PIlz+w{&O$kx-r=1(gV;+5Uh2 zExj7f+nSuYxoe1g;nxS~-#@T@t{+exB}amo8972x>9y5!6*D-hG({#7ud7H85DCRj z543<&m%lkhD1Y!@>**J>T-*`_+Y8yivK{WhWf%4LR`O)SD5m6>dSW{e!zh_4G*)&f zrgj&fl0I`^D9gS?Ig>^kT5$;CU`L80=0EA0~|VQ$WaHS&{L$s|Z8RSh|vnoj~>~Ae8E5vsRF2y1K8(gkkAw zb}*R4;cL!0MHqkbcl4d|vZC}_)h4f9A_`+!jtS6_6-iR~oI#jwZt_IQWa4m>$LG^w%6)z``7%gku~$X&t+BMgnp?hy(t zk(8QUMS95)JI9bkha~E1PMP$oH@nDZ!j}%N-R#;qaz)t0n^dG*4+w)%lJZRyOLzLg z-`oKb${+r{>g|I`9#rK*uzT-zrt7;sJfB9_(mmG$*&;g>)w5}A7*&>BG@)!wme~F7 zk~C#s!jL7OCQEWHAOcGTMIT$%;F`kZzk=Yuht^hA0h!#|G=w2%W=76XQaWvfVh?#4 z5+dZ=3oET!l}b4sze}{S75ik)lQVX<%N-J-R#3FtWron0+#-l4TAax>M;LaKYId}u_L+4Gh@CVQ z)>3blCT~vF=6|j=^2YACA0LGAyT83~>WdmesV6TaPwb&i-)JbNpVTZVjYl%X9v#S# zQiy{I!*(*lC=H05iI8x>N-ePjsSj?cCDq-XyeU2P%bO2sLsM$W@)XyI2%}LN5leSF zQ8A*ti&(k<$Q#=Z4Ty<0?}FgDBByBXTB6lA@1+5eGsA`^jZA$pD>bD0EQA5!sFY&N zjWd7ozcvS^G(+recRf=zXp;t5dh%r^%^7Z{DCs-%?EKAZW+Ifv_2D$WhQYSE?V&o_ z(Ac%Nt%~$yh&Og8fuq7q$t{ZP^T`{#p`nq@^+*_35{BK()FYWv42`gD6xlj=bm_4y z5sKYvW}Xm9QfhV;>Dj&a9VyqSFQ2;FN+ygiQcP?)k|&Z$cN~?TyxEy7VZKt*H?q4D z3b*gM2((YOyixI|qOYlZ|6RZk0DL|D@*Ls=1B5} zJmQp|w&cxBLZKH#(o96Pv&fRgX>{z0g1p>l5L_6qCk$KH6cNcfji_MA8=HTeH@OJx zLApYDHpPUo;6o!xso7Pe_geDD<__c0CnmDQ<}rKa8k@V$$`YZ(N=>BPA{2Y{T2aALV=Q7zx8Zt7!izNNpcsCmBT;@@8)C z+1mIBJHw2mBK_4cM(?4EC%-0PN&iT~IFrUkH(c`Gg^#hhJ|?uH)RHa95?hr@vX!37 z8+*6^)MzE(%2aBHys=qKOSCgUbz+ev_DY|*OR5Vc1)rwo@uu(}*t&d1JFL z*8*ACM5*6}Dvhk&WV||B2RM(_gL)iCr6+$bjZio`ca3Y-;5Sk1I+R?ZNv7Nc??%9^s@HeLjL;l!my)36`MW>0f zeY7(1Gry&8`&B<}D}Qp=rlut`qfDWsG_s0{jSu&1C3!1b>^yjG6cgf!+T$HNpVOO%@ta$Op*%557z>VW z?o1Yn-7(*p#-=ZZeKylp*uEI@W_FMzcCXtaA`eT?qGwX3*^||w-s~RajoqcbI0!>= zy*dcRUY$8V2t$?(L$UqZFLPpvq2%sfH9wVCx2HU@6{#dA_l=3h$3Ad16vbBBz9{wviCyvZ#juZ`+pdlK8_n=OtHJAOjD?VUiuykRqTg;R(=w}?wt*)ZU5(@vqi1DQS)-#0ea$y}ifTjdrdf9!SizW!ML zn;ra^5YJ}0MRB#eOSbM4gJ+KBXpO@ZhT>|L@GdjUaw8M}Hc_^vwCHP#{pTWE`PuaY z_|4seH7zlezL8Z_Y^N`5(Me&Ep3R~iqnPv=W4opth9PePWk{yjs?ayG52U$c&-VLb z98VZ~MsXeD%`i(8*|L(8$$DE+*a59r;5|(uvP3Z%mM6Bm z-ZmQJK6B@6it8JLFyzhLL^ft%AAj~$@}%$Fkw3%EJVJ>v?lTAPP5#)M27UdpyD702 z^ogsynVT_=Cq|QIOjWMgV{5^%(XsV0a;?wUC?>;ZpiqYS!yTsnjX>W#`E(92 zycNT@usVbj>Kb98*g2yFfgK2?dcDy%CU(7H&o%mD$eYNvJ~Qy1G&;l1qIQ?co&qrA zS#qPRsLGpR`6?89hQ{;f4fySQ9vwCV?Nb_Y4ji%;*n2U|lp!c#OP@@!f3q-brM7*6 zU1#%-Tkgm}bu|Ap#z)fbLit9GoT7ZQ``(uKyoboE{#@nM=f&y4I~d)@`iDZ-F9 zb{-`HfBE)bPHCbHdyZ{aO~WwkO44@J^n&XEW1CZ&-q`v$6vh6>LErnt2hte7pT=1E z(RYk(rDi0EM2m8YqSE}90!CIAO~Mg|vTZi`qg9~qT5XXfcAr)DbL55DA?qf2A-VM7 z4KQri$8~_wDD`E@f<={Y6c@63>Y~!!1%#Peen`^QnlkCZ4`A3+R?U?jBMS^$S%o{P zf61l)&~(!ZNu)WBO7A@&*!@pt1i3x@00!=IA}ET*xL%ulS%Id&m`ND9`5-J|tX-&B zl*}`t2;npkY%SG1>k$iJ>`s1g&0+go4D6IsIfx+Q4M&8eFTyiGz*;o`0ZkFa6?1^G zbPh1?9)y7}GUWSI1EO(oFv62S!2RL@HrxsX++iAkfTl?Fd*%RRm>oaE3havqc=8eu zRt`eA0SLHnKfnew#l)TqjA6NX6;|L)umPUD2LwEs8G!H-5QgQ%EkL+;kPR>&tLLyt z7{=fg3w8{fWhVwB;QTSQx>r2Wkf|{Gi-GaukaX9O3EqM`3d1T#i9WFKby(1b%;#X% zZ`1;>tp%2YEK5U=J00sIc+p4H!uqy;+j!9;P}*wIZ*H8!=D>^Ix@~Eb=Jp%CMT^Li zkhb+fFS&)HYytmFpj4T5JyQC211MQHI-iu)oBX(qQgk!^u>V_KkCfHh{Fs#ZcQ}8E z^GR7<>hw}PV zlK%rJ`@I6net&j)&E=S9wHj17_rSxC*F3Xodc-n4qFXI^U|ok2cp+_T!Dty?=;hV| zkFji`1TSpyc?(9gjasze`xQ+*#<$69v$QRK(Kc*}TA<|eVia($pPHr%PU+!|eq5zw z-Ryi)_H>IMlk)ghKdw@q{~mTeDfL!@lC{eDIh5^IyM7mCq}D=@d9eYM?Vj;=q^v&c z$E1`$=f|Wx-sE&MDC4mel(;X0vUE|ZY;!$Qw%-m)+*#+hQR44%z1^besc@ z(?zLr(Dka6_P*_WQeFXn;K!s~Jw5?tCY^VF8zs)?kkhVjU9UI@a(4Ick9tyr@N-gV$E$ z6VK+DhhFp%weT(aXyXM+)EKpCHgn2$i~P7s$-2q;q^$DJ0^_w5l-Ato^e#|l(0zWq z9F&EW{XGau)=KC1p|o=q+LNvUr5(IiLdf;})1b8PY4AxmxV(*0^sMVW2TFTi0A)X0 zDRfGl7yX!&*)ju4)(+?AP^#|6AL8%zcBI7L2TIm{KYkOGaeaqOr__7b<%gVKrHspQ z@M+&^P-fTXpzQBU*YBcK`P%hzDDC;i@xSwSq~w3^^atmYvig%#-fv^+qO|*G*Q-+U zuQ|VsvVY7f*J##!?SM2_k3fdvD@F}D@Io(YwAI>1Z&8c3!HX7X+R-+oQR9xO*<08g z$iC*oOg^o$7GX)OcQ{?* zdZgqp1?5=X?R-+kX1O1eQty60CZ+sgP|mWoE`QAFnVqSl5IQu@$r;kk{5A*GF`*T(bf zG_;7`+EAixSO8#0juyd-7JerK9rz9dwLp0sO>PGOG48@2w!51LPIwIA+hUIG>byulg}5BlnsglhU^xe%wZR z)pG!H;v58J`?tN_VQ<$)secr5o&i2|y*5g`Q!Xdv@o7KqqRis6u2-dOe-3>1|GCRa z8OIBtlz-)XQm%(T`7tTwm;9KN$Cv#$hq9laz1=U~j+8jp{J2WVN2WkRi>($su&(2^ zNkfnEHWXSi9xtTPwyoCPTX&1-qa4NOoJY+3XzMNd=$3{BQNy#!>tfZ05-|;Fpad^! zZPIRDNZV?G99a^)|G#Q&mbQ&Y=;d0<+1Rz(`*9m(`$dp*?Oy77C6w*&@^(3t`paCOl*jk_F)5Fi`!Ol)zaNzUALS`OUhi^J z%AfY*DrKxTIiHkzoBf!S5!~YZtL{7$A|p5 zi?YANu2-czSDpi(^7AeytTZz0uC5ErA!cKn`9Ta<^Vc+x!S=Tdl3%ZoOy`wKkjEczy?W;$C9zX8%3Fnhif1UH6a()}79UEMKqw7^EbNgkNZv*9;x&xGU?FD5# z_PhK5DDmF*<9D4N2IYSEq{~l(vfUY%e+J4zO1-Z^8J8cOU!}yq3_j`4E+=Iie(~cf zCI6bsG0$9Me2w}|Y4F&*DFy2~p6>?6^vkiyK?yxyd4cCwtu;TwzNm#&ZM=|1E%f{j zXswUX`*)=lW3(17*?4fLl`}H`CSu_G(%LA*7=;DFiyHG~0j3gX$s(sWacZHEQuAh~ zw>Y1a`iuRTlzO-OF)5Gl@Z&0FESG`L_V>A*lo@=#ACt2E3Q*d&(&ejMPD=eXpwxTR z`K07O=KRN|Qf6|+?eSw$;_dZgQYOVgP}=>j%MXF_NyJB>?B`QZ zmMSIgS@1bt7eIOZH7Hm4E1>M>DkuvnkAL>#97?=vu21SY>>SLjF|}?zdTDKGkJZ>y zv(}~uHP;Ji8?R03D+FwA>n%{|l-a^75vzqXP@<2h`O04F!|&tOc!B3nn;;Ej_Im?P z4YcznP{#8%r%OONzAIe*ASnA^>2x(HOO+D&3D;i-%Hxf$N6Pk_{Fs!-FMzV&mq2O9 zD^6c^`F2o_-z+E#DckLG{%+@!Qg4sTUw1w!tB3H15kCRS{!W8Z|07WL`w8e%pcn_# zSghu`mzu9;_JYe>l>Pkz>e2NUh%;(F3aC-rcz(q?Mh|MP7d6jf zw1_?eIrKbBYQ5ppH;xw;gkB)~nvS+%pJzl3FWLrPn+2g4c#PBnY;bA&B2ePr0!rQ6 zK&g3`^X~(t-U?8z{f~gMkdnW~k4f2nEhsH|%=x6`KjFuuZ1$Dy4m|f=|)w_`^|p$LVoU+VKG>`#S;3LP~p1IsMrAq|`qHO8rkk+5hLx z|I+DKpe&?3DO~bnQntV1^k?Ujl79`9{UR4p!_a!oM+rRkYEtT3EqGu#FKTVlKyH&p z+vp>BQEO`(mUioPO9PpsKHkgF3%saBB$)$-61>p!ndD<&diYe^b&>3jM&O0bzEcBo zNV{#OEeqLfAZ0I$fJ2*abi5qO@w?siyC_|{AA0olA=j@`%Aa)k(=I1v^(8;9Qrh{7 z^Q)A8Y;!&-$8W}uNjb8+{g{-q`+y&JQTllpdhGWoDEm3)?MQk29w_}g0m^<)IsF)v z{hkBmcwGQxA?0lU36!{(onNKoUv)kyaj${0KV+UutmeCpF;XI#UR&EXX*aJ;8pv(6 zwidyQ8Vq$y{R~<2(q|ud-BLdXLaz-u`sl9t{2vq3wzkn*w2hk2^_o@Dq8l%y5rc?x zNP`!(kVbDIZL39#sD&Sa64I#AzG(~qaThvWD&_2Y&GlwnUZrfe!{s|cIXZh?kCgcPK zACq!N_Aw~ipK(4Z_0ED4|D5wld3@fFN&T#Xn!f|!GR$Mtd<<$lKXZZSnKnib9dVA; zr0m^zw9jh6ixwdbUU#j{(l+F7z3?r1YeQ+{MT@9KZ*3m=>QakP#MEaXq=6UG;6)!% z3qPVoNW=P&1}~7q0^%*gO9a%qfiDv{W&2zFxQo*J#n2;N;`&ue+@;`imfiHu1`u|ANJ!aCI1oUlhUupK-u3qP}=vj%iAdRo`sw^n_RC-$$uVv+Vg_TNs0TS z^Ivj4DfM3VV^ZS321=am&L^ebtRHt#>g{m-olbXw5^s+m@Ac!?L0L!{hl9?42b3d! z6qMs}5|o9MIH#O`aw#Y! zcl+^up!De>P!>{Jx6+TRly*Jhd{Q2-a=IFnxNDt00ZN>8PS-o#;B+G>^*4bMXS4HP zaJtpyFT4B|=f4Wd@!sLbyFi%_Z-LUkcR`7F$mwBF_HzuB_8bSL-bp_`3Q) z1!Y_=IR9(sf9J51jabI>Jb~0#_L?5lTrZ@=wYGucxrnwQ zjkawyT5Bk6QUG;G+gi*uFYF61ak1xC`5juA8Sx8gw1{W~Uc@T&+N7Zuwb0|q`*z+a zaLTN^+mA_U%_E>}vC8Rcmy@#ZN1eac>0>S@WxL1yxJt=?0(`b#2g)qm?E25UJ}Eta z(T_=~|FR!fDR<{Pz^9LUoxbUMRmy%3IG>cqZ#g{(%KSX)$H$z$=kz!zOO?{Tli+jw zPP?3x{4=1m_cP~LDf#EXXaDCxnWzyZS&1%1@yw^KxykEP@>kY7kz|Y)FSrbN5my~xwSx! z7QqW!+N7b^CXJYeG-43EKw%`O@ljD~EdpilH}RvR4a!w&sq5Y4diQ`5>0Z~bQsS-v zpY&nZTj}%>Q1-J1l>M%C{$oxbcm9)pyw2%UPS=C->BAO3-U`Z6r5v*v@EMUkE+^$0 z^EN2^KLkqq54)U{_Pz&7yWV$xl~Vr$=aW+Jq#u(~{-Ga}QhwU`A32}&KJYL3F)91~ z8PszPH6meFxK2)ueKqyCwj0mSGd1M$J^<%<(OaPStUw>!*;&87nicfRSTy};hE>_>&_=-ybe159p{r$|6QktoE~<11eB#p zsejb@RZ2VF1E2JLmy`1N1Ss2`^y5>YwEv9rKXv|DKR)O5JSYn(+kXzqczy*++;2d+ zKK%sBQl-?to_qZTb<6rycN+gh~gMT@9~=YGct zwnW?TDEf#Np%-|e7t-KGEn2kcv5#r|J4|NnEubt_%5%(J;1lm|P{wh&>$Oq#u>x|^ z2ff`xu3x3hzsFtvgv&|UZk^Nhpxhz82+DDJ4U~4wfTq<3lw}tv+wJjVQtIvX<0@sG z-vFQV04Q+}`SDTLCnf#|pu|1t^3zT~0j2#HKv_tM_l+Nu^7wmD+VKM@<9x~aS3x}= zQDebus?{DG@yIqQk*wx|^y$wpeL!k8Iupb|D`aUQNDRE9a{}WK! z^#v&H{tlFQKZ1IkQDZ@zUB_x3XYiuNmL`oBzOF+rq){Vyv&HHbUf@OB;I-8ljV5yF zh0Vc>8Y9&7GNfTa)I#c+4aYp!P~$AU5gT*r-wMjrq<%)P;YDwu7kE*N-h2dr z;^SDWwdqA4Q48egH;{d#fb8pB&F1JgP}-1#*H(+RQ477`b=SIW32DToyN_rQ{dTvA z_(hATvF+#!PVw>p?>F5E%9ZY3zD&@dxcr%V()pyc`)NNW<(n6;gK~u424(N>x}22u zA94B~D87MU>N`Ka2ul5*oL&ZHA@$sJ4zjsc^9X>q2Kr4YF`7Kjr5cJy3cSE;YumOQ#n=Y5#Yi#6dQ>q*;UTI;rn<(8A;5Xx7%(vN1f5IHXaFKH7L5 zakTIpM-4;bR^_%0z496(Wxj=d5w&%YuEezGxU2)^3ceeZSl_UZsq}3Fnhi|3lY5<@B`6tCaX3IiHmFo$+H*+W$2u@xFCFDcgMq z$`$KpP`_3~&Ew)ah!AQl<7+-cYkI`D7Q06^+F-npg4MxmlLksiqvp8_TcQ@dMJ-xH z&DV&UADk68;+7!MZUtrUi$STo1eEbz0m^y#7%27Dx%_ER_P7C*?KV1n&go`QmMSIg z7Vz0_tIJ85SFeE*e}~gOpw!#zbf44LK{<+V`SC$e7E;>rj`QCI<=DONa#G@d=={$> zsecZXco#s~-&de4RZ6{YoKH%yr@Ons0A`d+K~M$Rl^ItwzeS+3&N^4Y3K!B@FHr#YpeNsHpbFu z!O>a7C9aS%b~mFPv-UPnda~GYNNM{Wp!D?~Q0grQiOWatzOcvQ#PU`^x#GZ2z^>Z=Byn>F0N@ z|Gn$CQTlxua_V0N^>Or;$S!Z&tkIq(&-16&BJ@0~A&nY9u0!F77;?02<3-!h3trTs zZScBl(V`8xjTcc1-+Y$9U*>W%R$+mk=b*QCq}Sad+J-G*bDNas)CIW2p#C%{N9q<( zwpt9z`yLOv{2@@R(oprq`@QNqPJ+DDlpLvi}R9 z%=n9-ETq)C1WMd1&L^eaS3%uhmtYi7^YsEXpFgO1gi!MspcZXI+E(*1s-d*$!6fDZ z^rA)Zd_LAJ2x-&;Ie1a?Gcr(u7rjN>;DwjbBJ{d>-EBikbDEwJ#`M2Ph-rWkyma)}?`<;TmM-s^O^(-lr1bowwT@m7MezctQZ z>&H)mvXC-|H-NI=XPs^aW&7uyz5q(Sm;Lw^Q0l+t$1{Gs!;g15-Q{#QDBHgQ%0kL4 zf7g#m+20{QCMEt+P`3L3lzyB7rQT^!#^+-{{sfeTl>ARY+5VjKN!jka^S=aT|3A3A zN~w3z`K11C5NeblUtDH2_F}b=Mh!xj`U*Uzt>+q~K2uN&9#@-Yzk%G=TUf>DSzFKh z8gigSE&2^!^bsf_jhbgW`Und`>gyV$ffv%?h0VS{9@8S)@{(}*BU4lOncB)fD5S)E z(dkQ|^ldvR$MgUw3n`D^2c`WdK>4Wn8&DQfj=+zgwCpM<^?m{Mk#P>v*KJ?L6oL(9fNI0ZMzm1?9M3^JB!gR$Bm>@uCKn z^W0ao2%bj=Jda&X%3Yq}`FPi)es2vtf6|JYM;0~Dm0F8HiGIT>MtaF=i}V^$YCrDu zDNq(t=GjKj1)$G@GCyZrPD)R9INc3OoYz68LHGOdK~UOo1e7>OogM?7#_@4b%1=4} zG$=FR2T&GL+Hu+CS3uok)I64`xyQ8{uRsyinx4-c@I0GQ^BAGVVlARApGO$a?;=2t zo)|A|iMG=tDO=pK#`JFmrImMpvXJulEZR$DV8ylXTbo zEDa?eebmZPqK}2Bj_EuxGMj~So&Zxc-`7oy?w*YgLf8EU@!9wViy=|zpPHD1(08nuwN)qJgkx~~>& zh|=t>&F0`mTVEZ4;;Ul~FOZ`aD8Y-GuZa^;_++CQjX;S$qDDw-5q-4r0wrpU+WfbP zG9I{-f$%Yc^WP?#!jZmhl<~;<7E!jK99>@eYTYLt95iNXv)OhTd8+<;Ang2FX1_Mvhd2${@c@D$xZKC{k zQqN?M39`|nX|<3ta!qOQd`8yVhP15~EuxR$wY6yD`J9{BZ}icI64J0BYW`dkeS}^c zia#@{*%ByiE!w2rypXolq7Pq1YPN**-)ybT(zZy3Uaoz9j{;ss+qR4dX&bVyy)_gD zt~mo3)AY#CDN*OYP1No;&3~IHlLF8Gk&-;C&wraJW)EWF^BgswgQ)r1gc^(Kg|w{} zdTn^oBJ|p7(Ke)QJimiG(Y`RwoZY_|bMYq3gE!uc(cr?2?9uc9oenT2~ zQEO|_EsYjob6X!FjTUV+o|EUlO_VXm8!re3b9?^VL{pX{8opyAK|$t^srhaIQqQrP zp66nX*M=8*e%*%_e$`rQ8+}AA@Y;AGjaumW9ne}Iq4)1fEyidqT(YtB_Z9!G@Z9&M zHCtkgVibZGHRj9ww~5+rV*cAinJf0KqFhntzfF|Uz1Z4Fc}CRmqHW-Xr6G-4;4$mwzfF|U!sp$v(dVe2aytKQqKpb=122F^ zHP5jc&-1CqYt!pSi59*V0xx*oZA0qw7Hxeegj(=I&u0>(J}*$i$1AV%H>A zP7QdW*XBn^Y0Lb#iKcL+Zx>~>=D$tUbB5`Jf_aFVXCrF4(zX`Ci(24y*VTl4upCTeXc;YYNMn$Pu`RnejwFQgHJhmyLYk7yCn@HeEv3*@kXc=O*TYS+f|-zIALI{$5=SY`NP z4T{x#4uRKJ3q7B8(BtH`wmxIQ^Od4jdmDQ5-zI8#H~(#-o?W2X5 zb%@+U3(v=iZKIE95w$?}^F|FX+J;{6a%ung2FXYn+wkU^7xsDP!z5hnxmA9L7CfJ4HEFbnXaruwD)ic65}Tx;R8 z0z98Hs0B(}AAu6JZoTLu^rGfheKo5hF5z!(Es&!{@WPfhY3Q{{Bc>sZ7z8g+7|Ho> z6J=!VTSXa<`EL`&Y~;s>QO4Iiub}7IgqqI^)VQ;=wtk&d(~A~uefaD~i;%YQLK=8s zK}f^Ws6~sYMO&YPHJbx3T0|}E3zX@tod&f z^;zZdzc-*Kw- z5gtV!(W0%7&9LRbZxgi~oc}ga&l>z=UC));w~pdw5@#oP+&Eh;T13q= zu7(nLA!Y8(f19YCG3LKbl;4@^t1oJvP5e*^3UUoKUk_`wkouJpq@HW2@&4-kw~6wb zNIfRC@9p&1f#;D$%|`$=KO@y@ZF)XZ(2H6iN56sWBZU_D@*0jUYSAM44PF~^@Y-t8 zHfo_4yzW}JEg_A#boUW0qTlWo5x-~=HMX7qHc?~{{&|8&3N?=?|DghkNxN%pErJ&{ zAHN!M8!uXfRbfFJFIu$W`5k5S%R9T~k>A4tFIq$`dJA6k8@#A_4g)W0VHNk!^WP?# zVvm1@?^hG3`C2xH=MjfAYCbY!cph;`eZ54D>4q^!Ew^pxmDj?zu-Tuuz=CxEoc}h_ zG#<5Y*Yr5ocs@gGJRe{1cB2VK6*Z4DY9S50HeQ=FP(m6tpVR0gYJnWJXc0AEBhWT@ zyaJg2Hc?v%=D$r8d5qh`ewN~mVievlZ15b$fNESVQJVBHn&N6H9r4sq8=H3$PWd%gPKQh49~|9(zaT( zjhc_cL}bsCn%)y5s{(~9`~0_wrqRN`)$}-zsreXCx(y*ni7J5XU|29#^X#U$o zk#+b8r{@}Ko@=Q2OsVnw3LHEZYa2D60X1nL`?(WR&-)s3phPWf310LOC?SoSXFK`` z3qtDq0!RZdq`?cDeSbWrMYQE5;qphOrtmZWZK8@Ug5fbOsQKulg^wU=KB}mBCf0Z% z_1uM&BR&6ZqWpGJ7R*@G{9Q!Ud=Ay5es2vtJg)Q>9$D~w=G0mQijNAUJ_4xWq0{`g ziE3S4J<43vSTG`}@kXZA_(GV~_!gDb7K~~h{aV}Uk(4dwzfBZDK&gJaDA$ktZxcn# zm*AH{pX0KCU}u4%NW~0E`NeQAK9_}g@aY2m`W;(mM=4%7ma)l!nPaj@F2*{ zMf~~0-?+315KA_VGXYt>rl0 z_5l9u- z{o{80z4QG$jEBGLf9F?k1X=Z!aaO)?^!NVZ-9O`C`yO;&wTBCw$|5NILYwgO($k+U z|NUPDFDTAL6HZjHR=cS+TrUHJBt$OJ2^r!nz zp!(G=^j$TFCtj6BCw(6NG2_4RDQk_t-{Y5|c_UH|N1GTiy1*g2{%0|lF8nYUKjQa` z-}~D~uDp*5hx#r2;^)J!eF?ksF&I&`i?_N|7I8ohMBn?Ea)0!n?*8ikBkeuBEUT(@ z@ya>poO8}O=bXAySI#--TnZ`z27-!!2~=XlQan6QB3Kal_C1p6|W; z5B$FG%ystJZXMNkj925EVXeLP-gC{gPn|kdRh48d*I5#ga-45>^RuFF+`OA)FqEZvu8p{-5u=Kd{^$;1(K#YRo zgP473p<)Lr<2EnyQ_(VwpS(?f0Vg9tX;I)SrKDn1quNQ8|{q-jCBZ=lOhR#hT zwAYFaMzx?FHY2`-5aj*q{m(#SQe8TI{pVK8R@x!GvT8MjAzeIh9vSW?hv=#FU9bch zH-Mn?hpBJ$c*%;qq5>Xyks2qv$93+%PgGFQ%zES>q76~rjg zNMI7ggrSXbbl_{ZfjNvEF`P_aL4%04G!^CZ0h#ESuY#hBeTBg)^_g(7icLOwzi@?R z%Kj-(Jp}{jKY#wW5Xn*L>=HmdTT^Ru*bu~oOflOR*vVI@$Q(;Gj=d%|+< z>jE#F@mgdjWE}vk$^2zS;SqdqrivPT*7*7wb*2Ll#iju;`5Ax>zxr7SE?WcbfCL#0@le8d`{~l9eN{KF zKZp^(W!5`NeRRlVn6m0XE&?9Z1h$>RcH0k1FJY;+P-S%q0yGWE38*b*Nv2kY1H5Ki zptC|h`aMIqMmq%z+;Ky29gQ>Cq&`j}HgO9ba!P)$N)ZfeWGVrIFA?{d-T)og*Ge~?TN=&T`cZm5DgYEbb_*SO@+ernjU2Ct34U4Q9q^?Yp{yx zJl)~~&fHaY1u$c4?2eb+CqDf#RG~e_75l0*ZD&ywkIG5n3G6F2HeD=D}xG$CZhp zOjXzW`AhLrGRGOFJPm7KQHDfqdY5C&Dx5M{fw#uBFILq5_}(Ky*Pes|ob%zL;r(9) zTRcyn*=mPGd6~O?{c*4zUzy3=cXFd48eF0ESgw*9>>Fc)DT7T>nnif8Gn@U@%g*Bc zEv9htqpc)KghctgF!xrq?CcLncdC7dS1_5@t^r7wZzwxuO50@!!HXcN$2=)uw zMcHKW1+Xu)`xXy-oyR&)(u3aTYzqMIsqf5ujcxuieRC$uz_UcFtz+FaSC)YL%GCAW z`SLD$tUA~;O92Lh>(-)Wybhr<=dCZ($cBzmZ}t!#AMSYR@g&?{Z&94t97uY`=dkF~ zexnmKpwPZ@j?wdEE(ms-A-5M+wTVPcgF@p4j2qD4492VV9mQur(77~cZi4=1+tV8p zZ!l(bqyejd*xd0B2*!R|W@=9=MA3LUn=E5RS5DYBe)#jX%<>`auxoOO>dvesfNpE4 z2m6n&-EYJ6F&M+|&&*%+jJtBm0QCOTWp_)zF;|UBWE=;|=s4>W8E8CEv~md6<%f65 zn9+RyI{{M_%fXj|!ZA2;Pxb3GKC=?d=0MUSRjgrh4dIOtBh~sD(e3H|*KW&Dhc+;B z1o_6>Gr8Cg0hTnt{?k;=l-~ofEa}qC*Y5xa(m=34A2?=}`AgN87gqV%R^R;UVEZQ2 zDi%o(vmzKINQ7WIF=_b%R7G^YClmvKPc=c>W{nG5&;0v z+X6{*N;i3T=8}35oyh!ULu_MFPl150SD#&S2vZTtu|zHf$Bw4huiR;A&Gq}i1($le zpe)Ov@+`NMj?6Jw!w*rLzf48H;K}wd4r0d8en;M8T9x^kiYpJygC+{-ejs^6Bwwol zMbUhn6&wWiH<@=HSMq=Dx4|mDjb;9_>t_NqCx8KJx6C?0 z6NK}arTm*(dKnj>fm_iKH0JHax=vC}L=G_OCARda&*YZdn-4*G`!+D#T<@iHvoVl% z>gmiDv;bmX1uPcv_Lf%xHgb4OEh(2F#X22OCu4BcBlGBCb_?brkPjL!0^@E%K&x#N z2J15P)?vk>En|HQ0@&F4LA>mx%5?B+Uvy=b=;3>rq1#hisYqigg^#GnzW&RxYoEtN zA8WOWaR{6rRz6;DG1!u6u*KpQoX6+BS2oyTkQevGoB<9*fHyH7%gS=54d*I@+^yn8 z2lr_dl@3)EpdIrUZE@R)S2kFdWw7kyM|rbt&^U9*6Qp70)NNeVAMFIVuDW!94a$oZ z;RxCR30Ry99dqDp7>rWC>Pb-3LJGjolfVon@y$r{7mM!`rk;jr)7v?V7`ucz@D7YB z%?xK?s(RQm1QVmPtI*ia@;bXlA(*3d>nW(|mCx)!{OKnrcI=n$sFQGGeTuVBnZN9~ zgQTmspFu2cmtK3MduJA^Agsdy3bS)Mzjd>%GgGE_)QdWdm|ZHSe5r8b0p;76S09(P zdhQWmd`mXhYzCxV5!U)TRA^_=vas+mhNG}Ck-5Yz0!Jd$O7?4R8p!i!D3<9!V3$2v z)nrV?nT;vqnA3s;zP8u9h3}=AzwCNXtUuxwn0H6r4ma6_}I>wpwTFK$kalu4MFmc!r;OSrS%n0&J(kjxhiypSI3sg?z8NuS)M z9i4(U`_8YdS3T&TP;Gu;zZtqSuQUvrh#WG#w+2jr6Hm9ndG z5t~G&6&P^!NlQDD8G~uXdec<1wZ%%c;ReUozs6B6Tiya_A`WZ>Bq+R0f3OD$_I<5x z-XkjQOVVFup^(+gi?@(6SfB+w3;SI zf&v#Ezz0A;35dD09wg(~m+n#z6y-I~x&<#BGX9LbRBz7s1byAlbOx4KyooAAP=oft z7)sgPTZF?)n_yw8 z3@@)Pstsb2X)yl5k9^$it)ad2#YDb}5iHR`K)8q$%MnbBZGmNfbjMn_i%JQrL(DYE zT5y9!<$8;@j%WF}j0T0XiU9has%wNwHt1UgV7=Vl)z34%n7~e!YQ+d(ui(RNY2f*9 z&>z6)B)6+#UB?XDG+4uT_|0E-a?+9r;a1%98E8d6yTC3EtS@A+wlyrz*h7EevmxM2 zr8)MIS55C@@zqZCRwg(w2~wHl4z;HrCg}TSrP(A%I}fbj-EBb3Q8&6-RSGnqEbA~# zG~x6_CYgr%Jol3HlY*W7S-$)^VlxtCX&RIT8UxU?g9ekT^d_k7cPr=`POlF02x2NuqvG3vr=ViWx?e~=*&8n-a0K~IbHI)p>no$wuZA>wMM(M#zl`gPmJ+*0r zUHqZ8`HLyFCkyk!UGq9-xG(P>+lodn?R5VHQ7av;K6mZAZZh!nXIWhaF^@7S55V~R zjgQavrkS4hOtX~Q7I558pFg$c`$MX%Zszr}7_9NI`fUhqJ9d#S38TteFiM`ubvd4U zInaO^5#Tr3N6j<)^Vi85 zz)F0;UcNVV`akde*>g}+*-cU=`Ain@xCVzTw$XSH&johgdBT_1di%GlFMSzOJ=kzh zy%`N=8z9YQ@D9tXyWkqESosq!jo>pZn^F34)U!2EJ@P7)d)UCOqE%rzVF2XM^JIWY zW8EWqPBT*X7|g6{E1`rlXi=cEA)li3 za%K+@oe##caHs)0XOjfp`F_@ZB+usK!}x>hCbKb+%0mlS7E#}=u8F}BTOKpq0Tjz< z11lhQ&^Z+`COptw%SD%+X1sYfZ_^tIazxK-&uW`7rn$fpf6A$MQuE&%Rpfli?WFz7 zZ-1RLC#R_w9)<3Fg~ZNL#X31x7afAW5C;aZBz#q9pz@FgdTM$MjM>DiOc$kg9UBbd zx7_A0ddbpcUimhL0Q2cmNnw+W*2;KU4Z)%*gJ;iOPB4)Snk$wgQSt6Cd`VRBiqLo_ zlOQPWG8B3nFus-4YBmbe&U3OGOLkQrDN6<{VJwhq2zP8xgVH&@tBxP2Cp%58sMl6r z`y-PK=;?DPy87iMMm&`s-k9`f1I2yyfos#-gTveOJP-!ro`HNj6+RZzEDLO46s$NL z3~)Z~XJaDK$v2(^O9bW9&f{LNMyHxgZj|-|D{Rw1WhI!woOZoAY+i+_uieL5rjODY z$U2TxjkPcfm`iLmIptt4-QEX23euq5x>Yzqhs}Gf@L>qNdT&H~*t!ceOXLmKbm*SpvLpt?_1p5YfhIBY$nP9S570N*sE8?Gjc-M4-9GPN?U;VZlxH2-WzmOG^ zxC}N866^-7hH3*wtPSMI2K3_n21~m1mSDjk9Vl=P2%hC5tx?sm%qDjFLg`3ntFHGq zUGrN^hLIb0%L0uT6-G0|8W)=q=?*3oaQOW9*V@9a-fgghZ-$z`m=*y2EMRE^EXiz9 z!QcBP*ebic9*KS7v<%o=FFj*E0WW`vmo&ZgIFz5CDU;C<=ARjL(_J2Wh}gMmo}mslVr5=r)QvCjvfg&{j83gOb4-|H8_Z-taqBY za!)8f(4e>MlEE@ni?Ja|c1#)|Mg;2z_((;^lVf(5T+rwO7~uBF1K_EBL)$W5f!I)c zSqjQ7lUeYqzXaQ4lQ)>tYcK~Z_|!a zdyf8U#cv?lV1O=_+zm1u-Y({S+AbSx>eJhl^ZpRrZbePj(HCVqCx&w(vEfdffV1!j4IxeRHeM@1GvH530cueiLN=va2zF&hJm$ zQW>2oU`qj1_iC3BO#xWjYa!J#0IwTtq@||5%%&t@3j!jp-60AyIy_{&jtv9%*XPfG z*&aw$Z{u=OL>23d6`NVJQJYuFX=Z1?f5XyyKZ647g7!hYp)X$*=)nvVSUM8MYA0(@ ztJygLrrWf^Fn)Jt{<7;U4`!JKGhsFCKx5z0uyh7B+ZYZxT*>DfUBz@}BA@z)^J;vk z7I%?(f(e!a8D1JCfEjw1F~7`Tb_|6d=+mc|py~dO^ffO!1sb1R>49(p0WaJRW(o60 zk6~!d<;n}tLOj5LXb{tY#_EybHsLDcVSb88Z`F|5BuEBw9&~iThCd0)&Tl-3Do^4o z9WM|t6vtNa>1V^ihg)S1d|7#Px*UVFDBoT=LeFLQGJp64jOUJ>>cD_NemYif$*|s% zjUbg43CmcU*Ez&%XkZ``)t=SHF!SQ~Qn;9g@`0C_de8i()`- z&Xe5svGIfQBYJB}l+9QOFmv5O+>L;B6ba%5)zS~|=!?#pW8yQ^g4e#li~%ynxKi-e z?;+`~-D<}{h*6pDJ)l4I{u$LjY>PA$;E| zT^llJ_6}fdnt~GLx|z6eOg#S!u%bL(ASREyvJWl>XUYm-h~9VOX2T%uKK=HLEGp=T z8=2tcG`#!-)B`)F_|@mYq8Gp_K>#ymMbs*0RtczM+riGG-YO~?dIY0a2-4u2-2mPA zHv5F$7HusQo<9Zh&SxFx@1=l8mVyZyd#fzDuFXPW!wh2z0(q)w3{4za8X6r0oQnX@ zW$;goKV_fP8}`;6tL#hyb{c!o1k)Z^Wo+g|2WQ5xJ~Nn0jVks~13|!^2=G+VEGv#w z_BAY6wpODaL$F34LVlpk{AK61RdMZs>H=IYd9pU9o;R-xus(#CVgIAk`r^7=y&(nv z{JWnGy!R9vy@o#Ly-*vrTp)CZ-Go~d)J#Pg-{#|k#{9(%Fduhh^$;DrX$zK>zFi(a zF(A_#XF9iOBTcFG=G}Q(zmgE_7!jbZ)}itI#v0|ZJmw+LYyAFk#%vO##jRLrJunp6 z{_^MLv`$NPV_e*cnfEIfiQKW$Zzjj9O?}e^U2Sk)P>vLKvsFg4vZ^ z`wXL8xbDr}r#q&p9CUFo*fDRg^L}z&V zYP+c6hpdrl8KkDsmsOzpU>orD?v@>u0tQV0 zIAQ!%m_4$gtBaQ`vJuYPCx8pMcY%s@97ahss#&PWnqK9}sv!u*T*EjtgLV9=v-yj4 z7`8pWEbC|MMfyUF6^Sm~C86jr7OJZZ54LMZ^oOA@f}Vd&CRN_l7?w1$`2wdPbti2F z4AN)%ve`gLyX7%$SsJvq2{2zKN;bo42^R*yUWqdw8S}lY#EDwVqeTw$=0GTj;eGjY zU@94*F@XfU1`x?lm+38A(OcGt6?8;%n5+g@5o1)7nTNp942_^Sy0YfZdSnuu+wv;f z3g^kxv*~yC*i{ga<-)a1^D+Y8C=GBln6s)kN43sgIU%c`Db1$0%+LYpxwdToXDkGu za~AAqcidt;#$9y5u1eGZM%A892U^CGz%SGB|LZgN@xfuRWle7j4$rGcFjQdZL?n1y zI#^7ygG_L~^pfZ+3>updP*e+6u&3_6dhHh&mbgYY1Tk)Gq~*(%;O9qRfBL+^mUX=? z491os2p|LG%ucYuOE8QAnlYSJcJpaS_3{K7OMJvCF@=vB!3cz( zsHz5;5~{oK2{Fd+74+%MAElbV?3ivNRuwtCpC0TgKt>{1Gbj>N8M6xRwd48cKmLC6 zkfBo54b9iNebXHh7^6(O@m26r??YxeH_I%f=@^{)kkyT+N)^!=xx1I&N634p<}KL8s@WtypHQnb3P!Jh5Ew}%y6 z^T|Wtrf(fN0(FD(99UAL!(f0XsOQMCiBy#ua@3yY+9#+^3VkWh2At6mxF0d>%*oDZ zFoRt?db{FqJbumeOY0fa$r$W|DnNlX@6k>{S#^4Ij6L+@6}N+sLnt|*Z2ABwrPD%~ zHId2qgKZx3H4upTwIs{8-b{pN32 zOH6-1VuF!#`#(Sa;~yXwL22P~PQRDP*euBIUa&zBC)pCXIn}w?nx;)}k{S%!*Bi8r zRo3Unoe(i}E5IAEd<3=IOy^O%w{BHq`-2#hmGWAqM?Xa&}i zkmE#`U1DxC%d0_v!J0#ZHNIF}t1dZx0i4+;7*30Y!XIVn19q&pOBP0mn1vvf$S|su z7cR_G_Q@pp=5aRDF1Xc$9;=Aa4xITY7h8)my`+5&ZV|!2?|V8d@MnE-B~B`Rx#A(O^?OzK-;ae-~KsB-pA|lGhSs5J(U^ zA+m9A8VchDBr*VbAcGxedOMi?0!x{OVM1+24ta++*F($fQndq}#qL34_&nnc`?Kdq zApkxH1pVA46B#%P-V#Mw9k*DM%#VrdJ#?bAjo@iBLyC8fY>T7&vee$s*fltuN5XyaBLn|NSbOWH3c$%=Ylfm=Uw2uEOeI z-U%Y&MGlWb(%?$=zcjw$_=lMBD9GpY7AOSqj8IT(WH`8BCYnz;z_OpHTiVB`q=u{_ zQ61tud9O@odb6B)|K=CjtLYmC=Y*MO`t9Or22zkk4*}8k9oDh0{$i>%J~1Gf5AIi= zYvRw6^dZBn*-4P}lOPIWdIRh-$gb`L+!q8)&|hoyZM!i}89q#KU{r)XMDfc{)uj|L z=x_f{W|^W)_jev>u;UGC-}x5!#ddgMg+M(QMw&59x%RC@J}Z=~Y-L4(%1{+uOfJ%T zfY}Aq)Urq0yn1I~0c6lgx%o$P>Djywvu6zi@Fm#A-l=2GwX5tIg>IXu+8Z~2^~cHV zOV*eAKD`H$@hYzXGyT+O^}WYap)X8;g)+zD*sfAQ0DJpie)c%H3!j}A8_^!>G~MX7 zo)G5D;REjn$3f*EU!yJ`*49)xZ zw8@gSagl6He3Y;lJ!Fc_^vr_hX~4wh&W$H5TgIGv)zf3c;~>B%dQ4Rh29aG{!Jo}s+zi-S{~nDp#YFqdBe#RQ z%ES=FNsZ`CpEVFOi-$*}=?=geM3=LGT|m3dJ9%y8P_jV4Ea<~KFShK>htIHT3)BZ< zDcOU78=q;2AIxL~v*?eWak|OmcSu1bn>>)N%>+Yp$^&x)t+EW1qoH+!EV;>F7rWSD zzR|Tf!`t)_x7%gs zL%?7Nm=CCrLE4B>(QL)wFZX;NTwUvy)?g_MwVkZ1HTT?o7m6TMgz8XZEMaby7KD_8 zU3p}DsA@KuSv(CgeJU@NF737EGZT3JX)qoK`dqW@ZfVT|ulp~*d4j_9ib8Fdx#xbK z11@0D230$U>JM6BT*p1Ua#kUMy*@UqS0O2BpFV*!!x&AYI@MY~lQ%r{A{vL)^om=23>LmlzrM2dz8tyRt^+#`M zONdIm&>GW++5&y|gZrIuF3_nmP)6YY`t1iqPvm`pt-N|0zAi`{sBL1$dHr@q6Hslc zWGxbd7~>}*FbBKLUv@zlGq3otDnHF-CFZIrrZ5jLXUu}%xc`OUbwM71IzWQlcfMP> z#wlPn&&@tzqDVUiWqcq&8>VX-Zhmn&RkKn6o;>5Ex-0Y}(^EUzt7kvUXCC815a7bB zRw-Ha`m?FbB!+g9$3XLqtmFLcA+}b4&tVPBp|FcBI>(aZx9-fP8|ZPMho`AftsahJ zFeC@S%g&lTAd+Q*^RDjnoCcM>7<+^0ePDtQ=1)Ew2+llY3SDd!qw6=z46@w1By8W$ z^tx>i(?I#`W$;sPwi1?BJhNWlGSSGcc>Etfc;db9vk6A2B7-_6OL%-ORdnGOTSR}j zFcq`3bNrySHh{GRzxrGzWZw4%Jnh&_{wvV3b^Wlp%iv{}u*}gT$ml6vW&Se#O}y}m1+O>1ivs}rOn#r};69?&pXRSutDLbleU8rOwcF)T zF^yuzO!MKj4Qguw0~i$cr6SM0+11yclS$n8f^0s-q9Gh=H#pB22PHwWa=d~aC@lvX`q4lnYFG5&yNfySx_H`%YkDhSE>>WruXP#56Y)YvO z$B6E+2lo5Z8Z@o;Rl* zQJ%e}VTZojDNuMrR;q^OFz%auvS9*j`rw2v+Ia6v;6Na6%yzJ!J{`nV1gv_O!LQ%e z$cV;+7*(DnXg7YY7SsCpX$ztBfI5$a-wv;l2YT8$*hW9nVA>e{hCbz4!7k?mGwT$PG*PDTl&f2wWj(ISrbg8Nbr83|b83!5yN{9u{c3`>BLo0Buv#GEtzL?Qx;ZJF-^ zM2X5RsD-9C+@WkUpg?h$@mC=*srQL2J7y^en0c%iPuH%>fl+Q6$je|$&9*-U4*^Ak z*cO!4+cU>Cthk%coYrLZg*s)@sm+XhDU-N2>tcVXs7BfJV=>UO!hEBf`G6V(sRPjT z2u#C>DMCMm@*K9a>eV&yghsF=dSNV%hj&0gkX3rPd@~=14W3~=0g2hW?dAJ6 zroU|4$4I}<%r0T%)MdF#UIS)qr0h&si1-A%T34P1< zv(B=i4OXBI5EClc84T$4E#x8Q%`)iPGhl*jh`(v_7;hfiF?=iUeued@++z>*5VQeu zxy858kyz6UifS}lhr!VTSO{+qT=EW~oou!OKD(MSz#KI@laoEe(0 zjiBtT4uMC5F3zs%T_4r$SXls*B5x;z1_0`s*Pmdx#$`@;p~}lr(>`Qw>+J_wg7hmp zKyI4pSE%I}c&ny~a(c08?%MJi(?4?9KyLMQgQ>a%G&>-}oc= z9=BlC)WKLbgTfgS;D`y}MZj|Y>&)q?CegH&#Us;q(mf3R4SU%X;UVc4~IWy=`uB zlD8KWrWHeB0*CzR*^>0(81_d!Zt-MM`9k*tjv%#3-c~uBGYl19=FoOldya!AxLa2g zxFCP7si&eKl|haJv12xY%0aA}_REaB9=CXt0!!%@mUzhJJ>Dm(h8eEHpI19G^zwsm z{c(?vJg4k1KQ;kik-pdhG0c%~J_ddm4hFpQ>(Ja>QCS~A)CkyrF>1<1b?rFikmU_* zRxK?wh$`IWpCA4Sv`MC>U`*3k;O{*NR;Nud3j%7vTHW6GHpHd}Er0QDu#2tQeDgc! zShPGil(SQ=Y7ApGHFnwNn-72k383vcuuae*PniY@m?^z&d?{7I&IB;XXA_;^yd?We z7QJc@y4V~nU{`TuI`bxg${lEd>?(N&W#JGf`Md{11XvwMyX5*FFO5QH#jDu#L(O7T z=~-1E&{QAGpt}H@Rp(pUS1vMoZ*LY(t5MHd^k_52S9C&KD_hSW9!d5=BQzmt&* z?Rob(w6irhfY?k0|NQIwU6>v_>;$Buw8gg{l4JhW{>qVQ%sigVKQVT}`${SpOuALM z#(66HhoC1DG6mF7V+T$ndO=|zAS!TL6mZ^3Jz(h+a^QgMioX@*eDoVe1Uo0c*YS9q=XIi|(uk^|70I zwQ+p`h-KdjS^&+nqIqcz7u%AJb+6qy%H#=%;67NwEzG|+ZUdVFvBm@m*0jJ`2D&h3 zVaC^SM&^~TTQg*s$KELL;6q@KolbDEWmwY#x>Uq&*a#Yp2jlj`-gy)pa6Ay%=&tgR z&pIF-G{cng0flb2zx8acJ+w)BS`XD;l*QcFupGXnW&USaXeEogxkGx)YUcDZ;{e3- zm`%^d>kpcLHE?V-8B=?57@VOU&D&rM`(%=>Dq@hk1=vOXM78_yw-?*P{9M`Xa8w@0 z$RQVu@yJOGXoCRQd79}MdJr)Ei#^^Ywf&OJ%rPwi+Ud@@;5BM-5WMLnoBe3B3=k! za_4fvF{l>g0b-~>_#Bu3_r9P%VU6k6czF3(Ie|IS@~^-DdAJPO3mw*WU%%Tu=d#SO z0svOiIt>p1F==~2g6)dYL+0j-k4Lfd0W2d%j?TW=qEoDx?CS1pn>~5?=jp15__B?A zO9k=5!)|=~{pp!3aNAezvz>+HiGpm_(NIg;zklXlDC{?Y6VCwnq~;d++i4d#W~QKm zokE}jk3kK{zFcNi`e9IB&MTI;&rYsGzWzt5b#e1btyAP&H`MF5fq9iWc(J7?f`FAy zFz@_XRp(u-f=dTM;1`=SlRSYn4j>H^)!dr_%`ve|&TtSj7T~`1NHqV1V4Yb7Bpt_f z#toew%ZM3PzbQI6_pxI9)mqHKTJx9P6dj|X9NM)XXhW6AYd!Xi7r;IEoJKe1u*aQF zdNMXZGl*{F4FT3BaIT(;P$OmLq+Dd9s~Z&9a6w{iM-^jD6e!He^uY>faUfs`#9IQB zAojbhkx%bWsPB+TaJFd;Of&jRxje%2QU*qaSD)P&Gre(wLALQP)??1>BSR6VWEhut96%Ta!OgRAB0m}#&=4r<{V9!4QHf{Q8J6%7+rr!lB%`fW- zD=~en`oH>}qz_KJJhISJ)=5t%vTxjY46M?H7X`{erH3#7s_<0C?3A=`y?Ssmu~AIAChO~ua)OZ#zc@lz!4p_wKz0gyqo8yYl2118%gf*?yq92-A*7)ZTZ{_8 zqF41_bI!;DE1(0@ADf0^BXemG|M%|a?&YR0wkw%g=?@C^-z$Ouny!2aoLvzx{f#zA zdc#WP=5E8Lp_7cjUH>}3EA0GbcM=$&0|W1VqL54zZ(qev!Zm^WLUz~}8R zHSa@pr+wz%M}x||1kORGf8N0?Q>isrz=P%I+2HHPZQz2T3IexBT(pn?|8k~tKD*++6;y>I;ZQt*j8v?S2@0GQyl=a@H@e82;$>$4Q| zNosttA#$q5JD4J8BU9jw+N3CNJf;E=)68!0-c$bGL2_jA1hN;T(p_c`M3{cx)^eaB z$_n%I@%^Uv#V@vvyEwR%RkO)wf=6!(IGZY)82g~|z4seWj8&InteWo_OPy`zawixi zh|vP7Ky2;2U|b8BpiLdVZ2UVGI1CfbUv?OJ(=}BueqT-$KE+x9Ui*f~1`&)63u(G) zhi497j+=nE`U^1LFCIi+07oLGUVc=R9JW%P3Y<(cH(|mBJsJz>6b+`&tN-acGEQ*} z8b0@C7tqku)LG6Zsv5ClJw0{(Ys?%CmXOKRzx;uv+scXqVnwiF@b8{oU|Z!J)^H1~ zx|Jvnq2i6#^Op^}5lsfTc-Q`9!dN1doQk_@yQ}2%b7U9cSgV(oAcIx>xD@ z;9JCvFSi6)b}VIYuU7E6NcDQ+qyi&8Hz#su>Qr;WsKJLJ$cyD#uX->Vn8QZ3P`y70 zu`@S957K!I7-0MhKbSHn52PLU$+8A=c49;UPjwl}rzhY2CRi>gq7Tf~Sb)5 zDquOQX;?J6nNQqm8M47R4PW^}LFO%f3W#+yP0+4sP->TDw8)O!68OPWY(8)O4lI7e zM%^ESMY^Xv!fA_BmNd%2NWfYM5VfAKS@gKY4+D>|_8^ztJ{n|Kk?OsuoxK6=WEU(c zh%N()xg2QS2a9F^U-&xM2p1ivzyC9czXzRfx1!D8`oo8pMqmHsI@Z%Wu1p03LbY*_ zCHFAL;ADbW_m@lHK*6cx+n&%qLP{AzSB_N5NR5^r#K9+59(3p#m41Re}|3um1!*_?!)a zIZ@NyR_U3y8q*iLa&G$mnTGd9fdLV0rY)d2C)IOg{y+qH;$>b`kYajU1v<~>wJ){? z3z#MuuBKldgJwGYPxnJ(6%4B|I%N8)m${3yS!J~sAG=i`mIlDA3}5T3DUcy}uxQyu zvu)7WIce6#CjGCczlJsRukJ4_bYYm4kO3YD>SVFyL=G|IS!-oOqwGw407s~f#$ca- zGz6w<>Pz2Bfj$o69D4*{{0kqLf}Q3syQ{y(1RpUqlO2~Jm>9}ATf7f*VVIQ{yO#$J zn7%=(3y0PZ+O15a=YVyZ_Ts}}(=p+uUnQ|+ZvcwxL>m8$HfGIsK=RIk=V07`z;O=p z%CGyD7mn5B`*-EUF75PvbfduH;154Qq*S+-nQB1{wY(W5R1yboBpil%j^IzZ= z57`{?&aeJvc5Gc+5FLN9UH-NQ*}M<0qhXkVtRM3M_s}M-QXTkWjo!)h>!^0@hLU{T z;*+V8K~UV8Aq*mU-~^o;~P$^YN_1!dv`EyBKSW&e9vggPmNj6k9;5>D`Y=I*#^gaAINppPxMOm^K6DV*g-44T!g# z12H4$^zBb>+lK)7OtrJwkO6o~I@bZ-+SHBjB@B12B15QyRh?MLmV^owWwf1X=rYV>D`R z6s$nyoMWdYz89N@lK^`Vn=m7&GG;Aj3W6wlXawhgO;>_dS6r2tXFA$maT%%DEd z$ctYD2Q05I5(7p&RDZqk%h1VN_^N>ZtT@>Tr2heChkz-^Fz^X>uw9Vi3~4C~9s$-w zsNh=Bq-<_vZX%+^J@8dVbH6^^I-0@bUuL`@YFGh;sSBS&Pmrle(~AJ;F(8Nh^e~wo z&3WF{G27Xh(1l40&HCfE1xPURLz%325>gfn9DsnnjaUZ8Ft?<5l zgHd?xdpUN&rXRj>xAO^Qo;_}iQ#c5qseLcr4&M6SeKO_p`a_~H&itDlw{(vz*Ep}a zI`G%Ko~;;?xj;TH1fE%@pDztyblOtO$R(whM?+jbn6|1}%S?`AiFh@#IkHOvs%hqp zL%-OX;E%sH<5P=ehfF*berU=u&{FE{F3~)}3dAS(uulQym2Kb~Cm}~Go6N5G6#M`E z%P;;6S_Vr?748518y^tPEFA3wMFnFy;XI(nM>WTU+P6)<3)ed6Z*1ANL&F;oX2 zCTGbGnAh76HbbZ=oH{^H3gPD1XT3(#u74I1NadIoE`zGlFZR%^)jC#nee?rx2M;g} z!O(brfRQwyf2~pZWk!y0R0U$g5De6dWbQ4_*(smNoUMpFhU-8nDn4l?)E%5v=huX_7HYy{d zik=4sw@Stu-Mz)jqa&;Vn5-E=xkpu({H;{ z7gJuK#W`;ZfGwy4#2PNSWbF$fh)bwgm||+t!_lBy|2FbvHVFR=Cvf2X?|{8=rwoMC zUm8-2)KEDS2g2oGuG1)#iiL>6va@~vE7M*rXN=-h$ZD2MG(gZh%;c6;zHGUrK|@%? zot}UM)DA&mCrhg1^zeS6yI}bsXJ?zXHM_`y{r%&pt(r*8=)vo?+Jn{4Qx(juuW94Mz_6x)hDX7&=D{?mCc4iGw{Zje~3s0D%8OR(1D9BlQpctQ&4z!G($Knv%+aEpI(A|J_|TyfVFld}j zPXCvl$YmV<{OuoY%#F42_{E0xbz=#0oX-kRdW+Q(1ai3YGw``pFo2!C&@ZC~qI#1N zYe}|!{<9W?89XjEeX1~+4-LSF0bcy*o&c5a7n{O%H~#4p)(ze^D3c7>7+C{3QlJOgNJi}x$ScdoWUZz zq|(0ZO#hVzYrJ3kHMpwTiK(H!w;sXx;Ao_tRsaq3f2b;MsC1MD)oVMwRBM$3PBzt0 zRNS<+Yut?~RSkAo>+Qmtm%a|h{=>Zn_B6FY0HK~DSu-O%%v62hUN8sHDF_G$={llJ zhIK-!7YO!sGBOAmk*sSL7hV#kS>Bgdg{{bT_uy>-kTY|6Zw2ym77G!w8XHW+26H>#E4 zGW}ohGAM^O83C{VlpSXU1epGM6t9;N83$g>Mfr0)XCyuboY~V2^5;`$1hfa@VNMDd z|Fluj9U%#$%9UrjyGpy>{0&C_b780YqwEtFzZq3oY zM^*DasAU2H3Fn2as%!>7dpiB4`JO z=(*_48m+?$Rh{cldqF9dhLAN|UtGAFo{3r0=OuihB!K|#0cZ^t$!IYto3m?W0=#1z z%su$6$G7+UjK4kTs<%SUXt~Y{hJh@X$hV$PcV>EroYII-|9I@bbJ7k?1A9%ZF~3<$ z&Ly6*$oo8&YZ4q}NUx8d7(d47_V@P4a*bDfc;8qjMy)c_1EIPtMY+s^GhnSuE_R!A zkf0JGAhD6B^$j(H_se`%1th}{?1Huu4e@d}Sk}JO8?)9>%cKO}zpHurg?lQyT3uw! zrU(4Z>j0Tz>{OPkHH?>lX3{U5@i=8pc=$KlLI@%ZCV3c4il2~mOgDjgb~c&6wZ?33 zxE%6j$DqqLTpj=N$L9{A?XEU3#)7)J)Jf5HnAJ?qQyFJ9_`mU+P@ZbA$5U@lhw{W_ zW)h$pj|{-`Ri}i?qE@d{j$5j=6`De4lG3!9zo{;nttootb}mp24O$b3nF1IL_0k*4 zmr$eAOqW zePPV_o{P8MoMBeL$LrtZy6N+n zOPE!Q)YFAAw*xUOncO0~==|Dvd_Ua=7%cKNSX6lPt19%9vcAxtiCF-O2m-q-vxBVp zWZsijvj_^*k&IKucqQX#A3}9{_5y$_`j40mZ$Dn0;$*PIPjATw-zk@K7@z}H>+CEy zp5;t^qiiCQra_+{dzxTL;Te%>?fPwJ=m=4x4A8L8{t&*j$}mOjiEw3tWG_ zA+O!*a^p^{JYqVox8*qR@{)l6F_@+6d2){*J__as3J1|!g4q)Wfo1^qpbEZh1(tcO z)Yj>Do`Pg+@3u8KB|vWr7L*h-y#_(d5Dkf}2B3tsSp*8pnU)#wwu=Aw4qsIOOUpd{ zgP(&jX3d~&8gBYd^1X)+p_YMKvcZ5kGnwoFf(nRHcWo%jnCXu@ocsUFXYRm6UQSG;2V_2|$oOYlgY-{zn=M zn~&n`Eiiyxe)MdRv0rqQsb()ozTN;>)^#+oUdG_%bSobqV-C!vy}&n~+I0@5U*jUvD&RuWYQ7@{Gy>2#K$BZQA--W2dr zVyjiPWQ^%kAV1t+6mZku8A!FB36Pmii21Q0{;v+bNuhd^WaZ&spSZthp4T1#si>4i zRH?03(F|Tq-4hybdgH56@hy-5ZQW22{OiMC92%^}L<{@g=iqPA{wA-Gai-MqUyFixcVgOieM6xOYn#LZ&#z5a@ZdbN$ zu~?^9z@q!Xc#%<7y5}gE>9<26hd@A#2ylZ*k$RJ4(Re!BFmMU<-q%GRuE;+vZhiY( zRt#!9sHhK&J?WiixNemW6y!ss@hI@lBiz?n<%_?7$db80Pm$op56wjBtvMdCXFum7 zn^&6-@mhW5*E7&me%C<-GS8KdWOzJW4kc9v;EVJP5DJ4Qq+r1aLoZXS>bdaX~U;#gY^FK&bON4OYeJt$P0+o>OV19Gv=sdKS1g zov-4+xrba1+!quKVm>f5fuInTwoqx<7|0^7egXP|Oj)Y8ZHWKgK_9<(y*-60{p2)O z4|AMPhZnvY;o$4c>nZ<1OZW$|VuWw}E(&~Lx(s}9A51VXz{~`~^G^;%n`hn|3`)=& zgu{-YWLciaM$0O_4lSHhAV6h4 zivZv$0)tVB2BWaZ=gkK)A?nWMgpMk|s&}7u&UMSjnDK0F<^D(b>IQJH6e*k!q?W(_ z{%gBTqwbnqHtw|!OE@ts1p%-B++azP-V)~j;KUn0fKdB^X8QjwyfAg2(ZW}rg2ITX zGI5^%;A!5_Yv#S%RX4K2FgiV*i6uA^vBxyiVEii?$$C??RZgR-Nk?PKCkU)`DkG51 zxrGgmTNjiurxOkuyXH*4RKG2=d=4_Q!@pA@}OO%atAr^e6l zp#XG(dPD`!D`AESa@in&Hdf!dTW7fp!PUzN8dC27rmCA6Pz3_$L%Qpd-&^0}@Ndg3 zRc}_?2^MGwXB2_%z?`6x%PL4R70g{S*L`H{VgKS|4Gd-Pq)b>0Olob#)N-gbI5()r z$KN+tlcu-EZJGTUC|wC+bZkLG?kh}O7gqT34w!~QXrrJd)he2yH+g}*@SGDkjYx0Y z2M2;dFa4$*T-DwlX8`{HIDHdJ*V}WrjulJ;KFr_wD%ef-GGI!?Kw-6)BQ4wN58A)_ zGnv$LmDMV1xI6P7Lsl6O>%ht4g1YRqHf5T@q71!7d5zqb2J>H^!^GRS$!sq7KHo@- z0j8xMDp@vtTbV0N^meY-kdy*7Q5&{E3uF-$xipy?kKR?8dc)=|i8LgqAIFts&q59T zvnkGjib3?l)=2y4mD^tUHq=ok_6f$k?r0PoI5z#&T1Jw-x5_^rU}KG1 z26IRT(_jc(w%#T>Ks~dy^-%u5XTC5jF=>XqftO8XsFR(N{-$XRuwN4Q{a*C{KK8llnKyIV~X5(*(nzPc>ov? zXj>C>3^~pUqt8tL4v5LabYd9-ohfm2Crwh7>y zppq+J0B`IE^Irf1Xe~Pf6T|`ZAGduG+`6h1T#s>Dr^nt1^ZcN@-(F@7R^=J2s&>y< zSiJHepTZHH%*}c3{jGb#se*h#fX9d5+F-{4q6$sF8*14H=9or;?fJ5DdXCOwUj&kB zT*0SK4VL8VEwPVy_YX`4bs?`h)>bw>2KcH%lM#4+Dj2;2#Di!u;24kwuI>trO>_xl z>F-gg4Q-gHRpoX79WWSHpf_x68Vi^cK)48v_d-+Gjy!@s{@1%6XUu$cw*kc5xj0=wq zYEw|?oo$)|9C7i@2T#D+rlLS>e@t7|27|k=f0jN91pzF(F_7Chn8B`My3Hk>GS28w0=^H2nf5OFqxKA1E3v~2{qse>`nuw_Z^^&f{N+*YK94*m4Zb2tu|@z z=53If+H@Q=gJq?9%O>MInG>sw2h)ih_@YwyM1V%k*rkQ;A5 zKAHeYb4oh`!GScdpaEJk>0Dzlrc7^)EKY4xY4iNUewGAsfBo|~+~+^VL>>Wk%WC0c zjN#@k*f!b3zD)Nix2qPH>tM`Iwn1jZAVsiS*tocv6 zs*Sf7VtOk?j)4b_`ha&2(?d7E3C4b%T*#8mI^Jd2nGkg#gH06%o3O&Bq==;)=?4Y` z*4qBlm%h;Ib2*B)(BR#hb7`B6(21rrrm&tm`py52(~{P)+8I!|Ue!U3@n0KM>MeQU zXT19=n~-hh)h}!o4?q(X5A#s8HZ~|eDh&JF^lA^7#}L@)k*r&q6d88qNe|Hma!@iz z5BI~|9gLYzjR8gA#y7pI^_JkcEhq(K`V2jyDW`rq7$MY|Am>3_al5%*UYyL)O&jjk3Y2L~Ug~G}b70pXe&n)@QL>&^$pMGQ(m5 zuHOwtf2Oio0K*et`ylR2nG(S{4VM|nz#{wMe~`?zdb6-hbv*~=kwp3qh_3fu7Y*D6 z_nf(X{tJm98g%eV{FRRm-yDgxGZvYp%o4ty(l9DoK0B)EA4kcUZO8O45(8sA_&^u< zo{0=&yq;H+IZZuuY!aw&11zW`ierO8je3K)w;^?BMk2g~Rid5^Md`k5(ZCw}P?70> zZ3d_enP$1aaTi!Z?>dt-iM`7XlxC-lgYFH=V>0!D42Cr64Pia?o(=GPAU7p8rN)&N z$3m(A^|F0*m_FsS0*wlMAL62Lzc=sIE#k43Dh$&vp}kDM%(!M38)Mdsp7Oc zWsmVnGVc-0Kuyp#KEMnXwdyS@#&KYTNgP+mL=xDrpE{rJ5*2R4ta95EaNvE2P@!9KpP(80wD3Nv97L}we!Y1f-`Fp3309Lt_2h38Fq z$dtw>nZ?iF2DaBjn8^A0nLI@V4%!pWN=S%HRMQ2O<+i zfFHJiF@b@ig^+pC7`1X{lEI=by+t^Dn8y68VxdHVcxQknm9`wqfSa64WE-SyeQZp? zLTIljJWYeLV^O^t#JuUPJnMlE9ViQ~m(Rg0KKjq6zJC`cE`xxXmR*+fTfgdmN2Ol5wRH*O$4=P~s#$3T2a-U1{$xdb za4$sM_CC15nqIv%Z+*kxVFPPs{^xhU9ed?xwk(-x^+E+IFAk)N(0D&@u95{BA3qIr zs(|h0&p-V&xFe{%@>Hg4^B}orgFStEd#*jgXDYLzE)(q4r!%S`O#fU4GO@yuwY>w{ z0@-_j3HBgp_7sR-0WQ&fBR+XIKMz?TbJL~|=;aT~=)>O_OzGE~l7dB5^;U(kuCh9d z_5=QW=4hZ7y4PiR6vX84(~d!@43Lrgx@!b&1By+*s3AHZX|bZd`#7ZCAR}n7YCvxl z@8_Trh@~`Fyvqc#1|2h(t1}pgu|j71%iptQGR)SR-sdT}@`n(NfD928t@aGZek$1Y zM{4Ik_y!c#nZRJhpx%nLlsbE?8t*-0;hb^bAJ{=-nW(*>zDqQ<;p%U|fwcsYfBJPC6oXO22BR8f zt$iGCX0kyhoaP{lU;cV2L>|)$umY8f3eMOj(4ZN$m2l`+e;?x04Cw=EJ5w38(1elS zZ0sZiV6bS!V390JWSDtj24JjqWRouq0G29E6R_WFh@|kVN;0~(Z+(GCk_ zjfu>spB~&mG1%brJOU9UGKe5R9D8QYc*b*Q&b{Xk z-1n_-b?vQ!XKQ%gFRWFos=oTtD%9P3(_?_22$gFF_l%ocg@yGXcFyT8uszWAZ@P2G z@XKO15-^I)VZa(h_eJqM9XrrY!`Os?=3spuN@AKar`~T+=F1@p_|OK+CJdJK#Ktp~ zGA@#RbQ`!sq_XKhe)_A(R7`Y_ah3~ov_i|~1MrZYV}IL!{^+sdIhB(!Ceuo8Jc$L& zM}rxY1~Z)7u?EN;Ed#&MmtQJlaC>Hets~e6-_a*8Kx16FOOb%f_lRWqG}4i=AO6{n zNu2eMJD;_IOzs1VG8i&tFhsfcKW={*i`8J^s9gIBwQfvhI<>v=)%s&-I^39U%o4#7 zM0tnk&;PpDpT*C_dFvN4$1q;M7c2%;0y0=MZEjK7)`$xeM^y_n0lQ-xbM};-O|aO? zy%Atu18r^nn-Iq#U@S4|t4^-olLN7y%YKtR0+wV&qXt2O@JSa{$NCgEBpp4_Uic$euS^|q zGXY$V7DFMTx!nK;bLPy=VbQYPx|GUV@KHX(u?&?hCp}@b7*Lg>{RL_dYbhJF5vT%q z<#vor_Gf+cOBNwhMti$+j5~C5Hdr%nZq4c3T1lOH7@QOw5Vv^a%iORsoi6_f0^keW zKB%}adek{=S0y}tiExD#6l2SWX#^4=31Gmsv$|f9jM;(7 zP3@1USv6;gESIPdaRf1~eKdZZOyuAA5-V14KEMVFqtJLT0G>i$=olC6V#wLYTQRSr zWzt~OlDSc`V)^aI{FANO@tJ6JLw{-&IPYe~Hy-W(EbTMam?JSxV1hZiF?*m{J$-;O ziK%#^oZIK*&BrTeComYYY;MTwcU@TI?J`!u(m}x0KP1xIDvHpoeRt)^JVeyW1iD>jW0dESDpxk{U2Ca2eSn^SIPwVi7y!EflZq#p6(S;zT{YJFk$V} zCa9}kdI0Az)Hw_R%cb2N?8T?SUV2b9*%=I2Z$OlYqhOKXWqoJA(bR)cWRO+8+AHXu zc+e(DU<}y0xmhfdyx_%lPgz?d;vbLyz0Onm81pj98_?(?h6bq5`0Ljm zW>V1tp!=pB3=`@54BD_970#*z`ayhJRT{2PSB-z+x@m4-rS=Dwp(_2bT#&WDcM6RG zj0MHWEQ=|euMw9YZ)G2$eN%JY;Gf2bYkpgjT?O+1U>Z+5gZUerwPkJ$j<>2LioJFR zMp1l@{8g6z3aG%NkPql{_NiH%S_A|50K9(W1+Z}tV?PV(TV@LPsp5a@`%F9o3?^+G zOv35{kmq7}I7G$fOoV>^{+kc0b~f?h&oGKOZgkR$x45ffPK4* z+Mhn);MM!N;^k+rJ_TuxWf{1$$^he+80?x`gyXwhZ!^duNl!B6xpfuWn(B#rPyzZ- zho5NEIqlWZSmgrM3mDXeBCq1~rko8{7=5|OoKN2~xM)iw2UZ9Q0;Pgjb~;Q^rqSj4yeO;#5^(CnS2F>u zG2cV>%{}MBYLBhk2CrcCTzwLZh0PLjQ}OB1J`xZU9_+*ReJ5P$6+O)+s?2kyW$YN{ zpnVrX72JcE>-HdnH3#O_;P88_57jH#=sH1yT(*E7#uDgMJC$uN21|!&GP_B+ed(9r ziJ;k_lNZ0ia+t5+D-63B!;#Jwp?#n}q%p4!4fbG3DG0CzoqY&^%v^m4l8yr65B|7^GV>g`aN%l<0IO)(6hJ4g9M?XAv{Ly*Q#f^gtCT$enqo(ia+w18^@{o?NE^Ywtb=u5uIFtB-nuo5K*YV{@Za z{F$jM5fyayxg`DEK3&VTFB`c0GYn1JU~Fy{Pmas>kyWZsgki)zkU4X_dF8hdLG)#Z z)9Q%7@vj9>%uR8@Dj$|Va85+9qi@F9pVG-pAg^nVH4NNj!gs7o6uuHLQ_j(UEp(*7 zi~Wu#*KFmG<#z?GlM%Gl?>TE|z#7T9?Fn%xp)a$-IBo4@f+)qYH8*$%7(-us?N;nux1 zind5?N3cG)-j`8p3~nTb3MkFBTSpS zMpiM@Kx1MQ_{5Zqgx9Ms9&J9k$lBgi@3Z;PhmsbO${`t)VQatt=W~yRjY0)HMwLl2 z49GY&{+Tik7%VzCiICO8JFFn1rrQ4Fq2IppJ(di>B8q$a&O&B%SrA>+W#>BsG0BNg z?ej;WX}>yTYDAa;*3&LM2ocDBcgui<`_KW`zX=u;!!}}$Oz+~VS00j?qLRZ_x4?aN z<~R^528aw)U1FaBaY>FyQybSgm-x&Cu5+z4{>%Wg<_@XESdgJ>^vG=SK}4&%`muh5 z2b{p@2Y~)*78Tr!L17N_{Gp)>C2v0sr2-V@as2^qLCJ|K(8hn1!ZCBB*na#$fK5ii zk~Jd$@achqX{M^xiLLv^9bPrOdnm(C4ypeg>|Dv3l?m`Nkb0N$aEJc!GY8-!F6yGj zU-H8-b5k%BxQa*|RIM*GyZl6^F6wJUVaft*R|}vKQ0G`|3dG<9nD(=SJSfZ%V5xXx z6Jp+dhRvZ}nJULDCy@0qRz3G^SqiRRXoG!hWs0w8z+8Qw_Wv6)0v`u$v%k=xYkz-6 zZMPVBsV>d;0opB~yMZKTo{IcueEhY+Ydk40P|gG|WTGGCGTpYjkGU0<)W?Er|E|{v z1)x6}o9eUuN2Y5S)$*w0^&`k@cd_9+F++4Dv%6Y$6&A4ZaiPG=ubX#er4KAEs2(YY zm>4Cdj&zb__8T86t-P^hI>e6;z;bX)3IGqtrD^KKoGIx0#y_gVoVlAa)_hvSSusZe ztmt>{2CFS>`{*>kdp`Zh6uy9be3cK3#m}lOglbdEc^Lww>kM1sjPO!Qii;KGTO_8|}JQ%vCiwv)GhtRIEa zH~_}YppcjQtZyzb_YIZ=@&rEq76{-Io1>^q7(O*QK7Xe;&Q^B&d09R%4L=^_i)$R;BOTemg z8mW$9)dMyngqOLi6n*E%S!^H;T^w`6vTU8JRZDHPmt4ayoY}}65wwY*Nw3^l4nFB* zFH`*xg?w*f_BAX&_a&Jw5utNmXl%5=ER%$VW7!<-1HF0CbNv(98O4$QP=OSekqYIm zQJHa62Oy5MBrDs4>bw^pw{s54C%1W*$%yvip}^C>&Zj#ZrIFrw?ddA|t|u-mOd2Hgd8{f-G%gpQS%5$Jp*%icL! zu8q}CTH6qHO2ll&3Y09G93Ezs4H4rF76k%wM1YskfO=3(Q}#PwkZIOO9Vm|h+Eb2h zq|*eJt@4cSz%t*8k8gue4S0zy0Ig0Lvy|As@7UQqEXseFGUqVey;oqW7y}y{YQt(Ag^^Mukma zqgEqtKLvRT;@QJ?whU%}Kx69;WCG}x=9oGOYYJd7xr)jn^UYq4$%tcqQzy{O+4f);DP8r5XkJy-_N z4d+4UBH8Y^r)^tVGXOvir+_t3w5V<(K9e&jOL9cH`aI3{<~bKWy4NO|by440%I;y= zG?fR|y;#{(dF**|8qx+;nKJ?v*h-FOT-I!TyeXptM%nQC`7nID%;Rl0m^3 zIQjjb74KL!q)g6jq}RhSAN(AeqpDn} ztO@~*3luf;#+RU6{|VTzWs@q?ShhOYoX^Q91)^R*Aj;JTV$5f_b5^Ix%-S(z5);RR z?WFkQyTAuQ!0F}tvqD7eT=Xazfoj>RTsG4PmNVcSe{`Y}g&{WwYlj;dV9SaD7_6)k zZbPiE;2S@>{#D2_5Rj~j7^?3~JblX`s${fm64qS=d4PaizQ8#a^v1_R&K`F5up0r- zKhxmB4$vdRItUI`%PP&`{afT1v#}Dyqz(sZAA+fLcKVcC+7pLWfbuNgN}N=ttV3^= zqYLvQ!PlHcO}_FlQ>~oOpAto$bs$GnF7Q7}!sp((O_cE1JSZ+Q;2A4)SvM%X}~w|Nf`1vf_e3t{|#M_M)60 z+1(P28<5&uESuF@qu$K4zv|%TlJoK-F??ddexJy}0LaYqJxST@&fM?^K)f6KM|539 z1%$wbX+Gnzp6Ps$T9m;=2nX3%w!>>LI|{2hL8cam!FxX`O15(T@K;cQ-HP|`optt8 zZ@GMp0}9xVa|VvV`#J}~Rqh?<^S)DW`~n$W*=?>CSlCS-Jojzv37?qSp6(kjD<~xwOw+gNvfSx?>40eluRIIJ<{si{5|iDBo+J&n-w}No!hVjVOGnqoH9 zsGh@+SA)6+wa*5DcJ?=BjBAPtE>z!J+JZ$u&8T}MU+Dqfryb-q??Y!>t6M?^c(Cx5 zr$+txu(XmPEExhj;M>)tUk-SILnL^M6BrOB!n?}&9R!#+PiYL92L_Cd$b^SJKMbvj zapYYAdv%|^Ej9)<3C$s*j%k?Y1y)rQ!VF3VEtWICf$I-~m5$ufL44#QUS!0zi!x!(4+~W{#pIEGK>OXcEeu(ZIxJgvh;_9~ z3vAN9pau{_w!*Yjt=8`K-;MsiU;pN#m{Ggbn)d0R+Ha;`WDd>oQ~~qMR5i(gFFmXu z>VZ~g*_uxtU;qLg{q>WqMvpT3WVArf>;$C;K!iu^9jmO6gBkN_A3ar2gu#Uyw_E$U zH2NQ(!+_5MG>Q<;Y`jHpobP?{k5!=~Sa>vY?Y8HB3Z=4y4ZC*(j6MSreVMORxS6)A zB)2JR+2z}sj^dnV)d(D8Fj%c?7aU^z;j-P#8F?p?&h3e{TgdhRVl` zG6PQV-kO^%0aA1}$N^n|`4$)hin`wwU0FS+@?g&zs(- zx^25BdKfp7)xUlBw-BBxy)FBu3M<1w0(D_}d4rA_;=}8h>C9Hytxv6#mqAyq9Y2PC zJbyPHVAAc8_cqCMYYfWQG3(DN`PkZBpoWtLov~%`Vr&7t1~OM zlfmdTyMMmz0SJJHxP^9QvS4YD4%S?Fp$vO%`z%|AWq~h00p5LVFQ+8g?~1a_wA}&q zH+tnmxH&b07lX<{0IeEy&#!f50msQ)nRojEZ3C|Vp3ei&AVB-s*)6S^K9JSS8f(XM zaegx7BFQn~&LUJU<#`rdz=X0u4lyZ;K&D-VyVYcL2_I5$OY=r&u<#~# zV_aUSb!~sSM!-kkx-bOQ?Z!`Kf@KJJC9SxWFuDx?v@h6NFqohkVs;>;n|Z&O)ZaSP zVEpnVr11s!?QngiuIxB%n3iIe1zlhVrh-)x z&&G5J+H)ymESjenR?Gfj`K$0jWB-5q_h3L6b1Fy0=F*QaXlF9TvO7il_<-*-eoU;F zzURqVfF&~J3N|9+{iJT%;Cc*}${<>{W+47=PkbG#cy(Z^y*nZRl7$6ytICGT3gRv2 zO2GD*>f=^f;740vIzoCmr+Pm$W}&AXWrw+Rujnh5jmlTKQ}fC99OZ<;0!Vts%{GMZ z1u>wALN-htVTTL`aQ1)c>ZRcNT{6wYOSR==tOhfxuRht&nUf@N%jWpnM{udY;q-+^ z&iRtWHDJcw1b)<s=<19umzgjt(n_K3hEECRXrN4NG3>-vELo|5$RJzj4DG)mW>+LhK%|x_p z7#1*WtPz$7P+{f3k`vIN!T{dD+T_d)Ii|7=gNl}w$W};R1=#5VvrS>S47-*zLAa_0 zoT46ssb<+O)@mF(8sMOU0M!MwxEk2G$8-mZ7rnt}ZNQe4BRvCEvvP`wPoU+sePA~p z?gejNaAs};fg)b|1@jWHYz-Ft#~&Y>cQp9`Guo%loARi!@;oN_pel8Ei{Rvn?Zu|< z558T%mf<$i!fcCX1@NCo*u_-QG(ZKKg83AdjbQ^8Pqt(oSpmB3a+Yc~Y@OUGcc%+YvY%-44#L{xBJRzm*!e+fB(jF@0Aps7qe z!LF|TPi*q7)_#xmcsbBBy8~x-_Z-Rjmme1yEF$8p#;2JpI_Mrg2`~bR_hE|1C&|ot zukZ`dHrgj-Jba7ZgjIA+x~x7p*9@g9R7Uh$0w}a5e>wkH`y$(E43D=M8bMGHWTrms zv3E&o#Hdzg)MF)VV@Ma}RDk)qS@uzyoXaQlW1#$>|2+5(Xsa>;mIiC ztpIjyXHk91Agx3PSD}LT_pjfl{q7gd;A|VHuvj&1hT}6~**I%uUG?sv`PmB@l^D{Y zhdna?!cW)__CPVQDwX+mRyY>-kFVYH&cm{(qc_t}y@&a9l&ZAjg>8(Vv57fDYZ~&l zcGbQiZ&t2#?Yof7C*`4CnFi0dT@c+qtyq+k<`=%b?E?L;-~Ivk2>TbiMo~s{eOUw) z?UM`D=7OPRpI`x99F{c>&b*Ff3dMpLr7|XuiXfxF+X~J@JohZvSOOqwOLv|q*Hu2HXsvwFgEL($9LO|CZ)2~poIFQ`bS$Z0D zQJ;bmc|6deeIm0y8PTuW%RzxX)(Slv;D(0DIFW7M6lH>pA zckAusd~j8|&{&q)?0g?TqcRnG6)&qpy}an-k5!q=MD}ub7Bp8-1&E$ZaA%e>;3J^W zpzICHzQQ7I78gK*cnEKO1mz?gjHMTs=aST;3<^}ev`$v8iV*(#<9t{?=84C+J;Vfv zg`C99jyzJ`1^O*bV^UST_$au*cmLIU91=QxnX)-&pW-Nos*3eh+!*-sp@X^Z02*cs z5HO1XmOm?y)^e5q3Yd;t+BX!2wflvI$p?@L+q;c+N&Ry6OEkL8#eVwbCyr$XJYpah zoC(c_P|AD(bJV zt!R95B4LyL6L1n?qq+rO`7)cBGYpDPGuXm}eImD8AW8&yY!z5pjb9gpgJpYE*}2k? zxi@~{TpHf4{VQcf8YW6X?|x_EmETWaD0VAi-#FWh!+oq(%5P(qc~0-X^F6RgI$?Gs zVg@1~1Xwl!3sOhNBCbC!i^C!4=u>|%(kpj?0n7__o^dB;GO#OxNdvSsH#RRqKL0JS zo+Ccko3}IWts`!pMH#IgZc(?i!)L6jbCu7j9u8UpQvjfMSu6nm?{HaE@KJ6w%#L0b zbpeP`tOKo#sVyjV zg!Yv5oP8m=A8*Ef25^7bB!z&jmVs&Cxz!gQ(8=@#@={{lP9Ygt=9&)Xd+u?UWn&yh zKDdJ|!2l+QXU}*?L&XqZ1lmV3ymJ|%9Byi(DKp7|EF+o?IGn221V0QIy9JpCulG{J z?ocR}P2ok{8s^5frvjh_Zb#SeR&d)nngbIIoNEoz2Ue_>Yu`O$-2eS6_k!m$5MFD^ z;FTbN?gK)(9RkWuXqHW>&;984BdYtQ(iL{n7RDqOI>k z=77>i86lwV>}_+3M$z=(W;t^07c@Uh4Za;!O~+&cQ~6U$W5GcA*~jklO-3aB)+rk6u#6yOHhs*00=+7#(( zz_Q0=jX9@H$NEI`yMKT_cy5<&+H=ZIExh(T%HDd?>?bpB{Ywr(nP>ezuDh^k>7B+hqCs&oU<#car+kdp~|!=FIs~L*}(_ zlxn}l6lR43XFv9W`ucsn|CD3=HfhY7J4jCR9)hH=+CcfSGRfrf z8sZiN@S%aNMc&V~b_QH+Kwk5ED|AoI5txoh7Vp&`oM+qW@g3v#>tm3T}9nxx}8}LWT~7SR^?Nw@>Y)aKtzW4vB@o4%T!z=`3N5QuSq*(&HDpo zXZ*dr!2rHH>0sL*2U)ghK-Pyq%sS6U@FZWBE90aZ`A2uE^1k{s-wk}mnkNSwo#SJ* zx8G@cg>j@U0{U67=>r)Ly2-FP%NAuf-~=~!zJf4}3H{5y^&RB_F$uMU7y|jtlNAsp z)&Ag�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

YIgODmD9G7|tuBmJrJ|Vybr}?s?zj(8g~u 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%0DZdy40o%;`3o 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

EI|p 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 VwmX+< zS-6Yg?Kr##?((Hv^DmgjonXSwiOZg}5MjZtd4XY+uhCd!G(>ZBxTJH&ar;IjIpBPV4(O}t3> zn`qbRC7qx)=X!6NuC%m&oTiqh`W;0ZZS_u*9wqIhuOgCRUk(27-Fd*4Bf0f7G9xPS zUdKsN9^R`9dxDA*Im71y$y$3yJ}JHEp_mB}`Z82xNId{lkBN|m#Oe)Xv0GhSeX?T> zwZ`ipuRQsQw!){YGV(2nLQ->NZ-+D4yUlUEym`3)HY6W@`*bD0PR2hS_m9O7z)vKX z*eo&ZU4AeI7f<__)qr9@XnLY+BTV}mh0SwV_2hAjuI^K?pp~b*rI0apCa6_ss0V}0 z3tdhs2Z%^`S@88gy?&Hvcr{ zXB%LNKzf+Nn!`MiNB3u93n9;z>thLgB#np&6#)^>ulQSYf2H#~H=1Cm`|z%o)0A?% z8gj|^0{0i~SM9G=5^ndQ=5327;bh^{_OV~l)#LK6y0tR^Jn-B}i|b$Uz{-7HQw*UD zI0^FlSIPu0C?LnfF^y2+$;VpTm1#lrTylB%chfdgtI{R=p*B6(SD~J`a!(+msHJwI zY+$7OAg^Z!K0>&U5zY|@eCmng_N8>EEZhg7T*y;WQiXww5KdaC(jW>UvZS?KVFZjJ zVg?^_^`(k#3TdGk+13BKirE4aF=j?l*rwvtCO}wd4i`rrP8V%GEd)1BynJH=&a@mEa5joJu_Jxi=38A)G*1fyIkEt}a!L zrZwak^U}DMI3Q<{349AoT!se>`R>cADfgnIjq-;q3weZq_%c(WZ)GO47k=>jN{xc9_ev$i6ZuSX!N;0supk@iQQAx2qf6 zIt|@6gl9mk9(F4pyLVnJ)R$dFg^XXZ=pDY1%}V3cB|BDZOsWD|+(qB_5yj=Ebx!+0 zFT}49D?P!)+d>q2G0;cQ(!1O^!${%;sy*F0l*tga4(_*RZ*=09K3JbgWz`Q0g7j5g z_=kwT!WtA;8tU~(dd2YF2k`Qb+_O@s<>uxnC#F0?AMk5U#v!-7Ike#EB_1L53F*Wy z+UFEi6rvF!tsb|>+q#|6ARW@QFdDLnU{kLB>A|X}gC6)j=WhHCR(crk2}+IgyrB31 zH1)qq@&Z_>i;8k2rRq+YX4Qw09A|wZ(fo;$M1{EKLi-r3=ui_M2GLnBB zDXw(eYJAt4KUa~+Aze;v4E9031$G8`b3q_e)RTf7St0HgH@odC8j}lObt^S@G7nX8 z@;922y}R}&(y+%_9UyzVe!IX_sY2|UqaY9Y39w}{BK9rE0e4uYI^_7Npy#i7+HAL9 zynK`srABe(00PQ?{Hu?LAq!-NZ?5$G&>^1Y&2N#srNgBZvIyeX=rbGR)~Z&LESwzumrWl=D2QQGf{!jo65BwuHWDjDE@@j&h1|4=#4nue4W|4#HWu zYZE%A4a_)Frx;yf&D7@xZDM=98Fy;iW6g?@hQ-~SOw0a-bAquJ-Ae2%H#DD<>Tx?nmky#%+gn?d706A!vC-SAECoBYzAiH?65RYZe#G zjpDR+wOs1F*);_!eQ4Z1JqFb&I3-DgT|3=a^t>Jh>yZk_;bKncy6*%X(OT+CzNuLY Yj9~^#F8WY_Tf98*VB7wW|LK4K0g}xFga7~l diff --git a/local-tests/build.mjs b/local-tests/build.mjs index 02e3008a3b..773624bb10 100644 --- a/local-tests/build.mjs +++ b/local-tests/build.mjs @@ -10,8 +10,8 @@ const TEST_DIR = 'local-tests'; */ export const build = async () => { await esbuild.build({ - entryPoints: [`${TEST_DIR}/test.ts`], // Use template literals to inject the variable - outfile: `./${TEST_DIR}/build/test.mjs`, // Modify paths to use the TEST_DIR variable + entryPoints: [`${TEST_DIR}/test.ts`], + outfile: `./${TEST_DIR}/build/test.mjs`, bundle: true, plugins: [ nodeExternalsPlugin({ @@ -21,7 +21,7 @@ export const build = async () => { platform: 'node', target: 'esnext', format: 'esm', - inject: [`./${TEST_DIR}/shim.mjs`], // Update inject path to use TEST_DIR + inject: [`./${TEST_DIR}/shim.mjs`], mainFields: ['module', 'main'], }); }; @@ -32,7 +32,7 @@ export const build = async () => { * @returns {void} */ export const postBuildPolyfill = () => { - const file = fs.readFileSync(`./${TEST_DIR}/build/test.mjs`, 'utf8'); // Use the TEST_DIR variable in the file path + const file = fs.readFileSync(`./${TEST_DIR}/build/test.mjs`, 'utf8'); const content = `import fetch from 'cross-fetch'; try { if (!globalThis.fetch) { @@ -43,7 +43,7 @@ try { } `; const newFile = content + file; - fs.writeFileSync(`./${TEST_DIR}/build/test.mjs`, newFile); // Use the TEST_DIR variable in the file path + fs.writeFileSync(`./${TEST_DIR}/build/test.mjs`, newFile); }; // Go! From 1247704df391c36edb5da321145921ddda2ca100 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 22:50:08 +0100 Subject: [PATCH 011/263] feat(types): adding types for auth unification --- packages/types/src/lib/interfaces.ts | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 258333c7cd..0d54cab457 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -37,6 +37,7 @@ export interface AuthSig { derivedVia: string; signedMessage: string; address: string; + algo?: string; } export type CosmosWalletType = 'keplr' | 'leap'; @@ -255,6 +256,14 @@ export interface WithSessionSigs extends BaseJsonExecutionRequest { export type JsonExecutionRequest = WithAuthSig | WithSessionSigs; +export interface JsExecutionRequestBody { + authSig?: AuthSig; + code?: string; + ipfsId?: string; + authMethods?: AuthMethod[]; + jsParams?: any; +} + export interface BaseJsonPkpSignRequest { toSign: ArrayLike; pubKey: string; @@ -300,6 +309,31 @@ export interface JsonSignChainDataRequest { exp: number; } +export interface JsonSignSessionKeyRequestV1 { + sessionKey: string; + authMethods: AuthMethod[]; + pkpPublicKey?: string; + authSig?: AuthSig; + siweMessage: string; + curveType: 'BLS' | 'ECDSA'; + code?: string; + litActionIpfsId?: string; + jsParams?: any; + epoch?: number; +} + +export interface BlsResponseData { + result: boolean; + signatureShare: { + ProofOfPossession: string; + }; + shareIndex: number; + curveType: string; + siweMessage: string; + dataSigned: string; + blsRootPubkey: string; +} + /** * Struct in rust * ----- @@ -878,6 +912,17 @@ export interface SignSessionKeyProp { domain?: string; resourceAbilityRequests?: LitResourceAbilityRequest[]; + + // -- as part of auth unification + sessionKeyUri?: string; + + litActionCode?: string; + + jsParams?: { + [key: string]: any; + publicKey: string; + sigName: string; + }; } export interface SignSessionKeyResponse { @@ -1573,6 +1618,19 @@ export interface CapacityDelegationRequest { uses: string; // Always present, default to '1' if undefined } +export interface CapacityCreditsReq { + dAppOwnerWallet: SignerLike; + capacityTokenId?: string; + delegateeAddresses?: string[]; + uses?: string; + domain?: string; + expiration?: string; + statement?: string; +} +export interface CapacityCreditsRes { + capacityDelegationAuthSig: AuthSig; +} + export interface LitCustomAuth { litActionCode?: string; ipfsId?: string; From 14be1211b53b1527791d388062f88e61bf0123bc Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 22:51:47 +0100 Subject: [PATCH 012/263] feat: refactor siwe message creation, (Breaking) renaming SIG_TYPE to LIT_CURVE, and a util for sanitise // --- packages/constants/src/lib/enums.ts | 2 +- packages/core/src/lib/lit-core.ts | 6 +- packages/crypto/src/lib/crypto.ts | 14 +- .../src/lib/lit-node-client-nodejs.ts | 503 ++++++++++-------- packages/misc/src/lib/misc.ts | 38 ++ 5 files changed, 337 insertions(+), 226 deletions(-) diff --git a/packages/constants/src/lib/enums.ts b/packages/constants/src/lib/enums.ts index 6312ea041f..e6b7b0aeb4 100644 --- a/packages/constants/src/lib/enums.ts +++ b/packages/constants/src/lib/enums.ts @@ -5,7 +5,7 @@ export enum VMTYPE { CVM = 'CVM', } -export enum SIGTYPE { +export enum LIT_CURVE { BLS = 'BLS', EcdsaK256 = 'K256', EcdsaCaitSith = 'ECDSA_CAIT_SITH', // Legacy alias of K256 diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 358eefeed9..766c612be9 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -19,7 +19,7 @@ import { LIT_ERROR_CODE, LIT_NETWORKS, LitNetwork, - SIGTYPE, + LIT_CURVE, StakingStates, version, } from '@lit-protocol/constants'; @@ -1327,12 +1327,12 @@ export class LitCore { * Calculates an HD public key from a given keyId * The curve type or signature type is assumed to be k256 unless provided * @param keyId - * @param {SIGTYPE} sigType + * @param {LIT_CURVE} sigType * @returns {string} public key */ computeHDPubKey = ( keyId: string, - sigType: SIGTYPE = SIGTYPE.EcdsaCaitSith + sigType: LIT_CURVE = LIT_CURVE.EcdsaCaitSith ): string => { if (!this.hdRootPubkeys) { logError('root public keys not found, have you connected to the nodes?'); diff --git a/packages/crypto/src/lib/crypto.ts b/packages/crypto/src/lib/crypto.ts index ea242f6451..d4e5a8210a 100644 --- a/packages/crypto/src/lib/crypto.ts +++ b/packages/crypto/src/lib/crypto.ts @@ -17,7 +17,7 @@ import { } from '@lit-protocol/uint8arrays'; import { nacl } from '@lit-protocol/nacl'; -import { SIGTYPE } from '@lit-protocol/constants'; +import { LIT_CURVE } from '@lit-protocol/constants'; import { CombinedECDSASignature } from '@lit-protocol/types'; const LIT_CORS_PROXY = `https://cors.litgateway.com`; @@ -242,8 +242,8 @@ export const combineEcdsaShares = ( try { let res: string = ''; switch (type) { - case SIGTYPE.EcdsaCaitSith: - case SIGTYPE.EcdsaK256: + case LIT_CURVE.EcdsaCaitSith: + case LIT_CURVE.EcdsaK256: res = ecdsaSdk.combine_signature(validShares, 2); try { @@ -272,7 +272,7 @@ export const combineEcdsaShares = ( } } break; - case SIGTYPE.ECDSCAITSITHP256: + case LIT_CURVE.ECDSCAITSITHP256: res = ecdsaSdk.combine_signature(validShares, 3); log('response from combine_signature', res); sig = JSON.parse(res); @@ -295,13 +295,13 @@ export const combineEcdsaShares = ( export const computeHDPubKey = ( pubkeys: string[], keyId: string, - sigType: SIGTYPE + sigType: LIT_CURVE ): string => { // TODO: hardcoded for now, need to be replaced on each DKG as the last dkg id will be the active root key set. try { switch (sigType) { - case SIGTYPE.EcdsaCaitSith: - case SIGTYPE.EcdsaK256: + case LIT_CURVE.EcdsaCaitSith: + case LIT_CURVE.EcdsaK256: // a bit of pre processing to remove characters which will cause our wasm module to reject the values. pubkeys = pubkeys.map((value: string) => { return value.replace('0x', ''); diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index cde9abac88..2a1de0b29f 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -11,8 +11,11 @@ import { LitResourceAbilityRequest, decode, RecapSessionCapabilityObject, + craftAuthSig, + createSiweMessageWithCapacityDelegation, + createSiweMessageWithRecaps, + createSiweMessage, LitRLIResource, - LitAbility, } from '@lit-protocol/auth-helpers'; import { AUTH_METHOD_TYPE_IDS, @@ -23,7 +26,7 @@ import { LIT_SESSION_KEY_URI, LOCAL_STORAGE_KEYS, LitNetwork, - SIGTYPE, + LIT_CURVE, SIWE_DELEGATION_URI, } from '@lit-protocol/constants'; import { LitCore } from '@lit-protocol/core'; @@ -46,6 +49,7 @@ import { logErrorWithRequestId, logWithRequestId, mostCommonString, + normalizeAndStringify, throwError, } from '@lit-protocol/misc'; import { @@ -107,24 +111,13 @@ import type { WebAuthnAuthenticationVerificationParams, ILitNodeClient, GetPkpSessionSigs, + CapacityCreditsReq, + CapacityCreditsRes, + JsExecutionRequestBody, + JsonSignSessionKeyRequestV1, + BlsResponseData, } from '@lit-protocol/types'; - -// TODO: move this to auth-helper for next patch -interface CapacityCreditsReq { - dAppOwnerWallet: ethers.Wallet; - capacityTokenId?: string; - delegateeAddresses?: string[]; - uses?: string; - domain?: string; - expiration?: string; - statement?: string; -} - -// TODO: move this to auth-helper for next patch -interface CapacityCreditsRes { - litResource: LitRLIResource; - capacityDelegationAuthSig: AuthSig; -} +import * as blsSdk from '@lit-protocol/bls-sdk'; export class LitNodeClientNodeJs extends LitCore @@ -179,115 +172,57 @@ export class LitNodeClientNodeJs createCapacityDelegationAuthSig = async ( params: CapacityCreditsReq ): Promise => { - const { - dAppOwnerWallet, - capacityTokenId, - delegateeAddresses, - uses, - domain, - expiration, - statement, - } = params; + // Useful log for debugging + if (!params.delegateeAddresses || params.delegateeAddresses.length === 0) { + log( + `[createCapacityDelegationAuthSig] No delegatee addresses provided. It means that the capability will not restrict access based on delegatee list, but it may still enforce other restrictions such as usage limits (uses) and specific NFT IDs (nft_id).` + ); + } // -- This is the owner address who holds the Capacity Credits NFT token and wants to delegate its // usage to a list of delegatee addresses const dAppOwnerWalletAddress = ethers.utils.getAddress( - await dAppOwnerWallet.getAddress() + await params.dAppOwnerWallet.getAddress() ); - // -- default configuration for siwe message unless there are arguments - const _domain = domain ?? 'example.com'; - const _expiration = - expiration ?? new Date(Date.now() + 1000 * 60 * 7).toISOString(); - const _statement = '' ?? statement; - - // -- default configuration for recap object capability - const _uses = uses ?? '1'; - // -- if it's not ready yet, then connect if (!this.ready) { await this.connect(); } // -- validate - if (!dAppOwnerWallet) { + if (!params.dAppOwnerWallet) { throw new Error('dAppOwnerWallet must exist'); } - // -- validate dAppOwnerWallet is an ethers wallet - // if (!(dAppOwnerWallet instanceof ethers.Wallet || ethers.Signer)) { - // throw new Error('dAppOwnerWallet must be an ethers wallet'); - // } - - // -- create LitRLIResource - // Note: we have other resources such as LitAccessControlConditionResource, LitPKPResource and LitActionResource) - // lit-ratelimitincrease://{tokenId} - const litResource = new LitRLIResource(capacityTokenId ?? '*'); - - const recapObject = await this.generateSessionCapabilityObjectWithWildcards( - [litResource] - ); - - const capabilities = { - ...(capacityTokenId ? { nft_id: [capacityTokenId] } : {}), // Conditionally include nft_id - ...(delegateeAddresses - ? { - delegate_to: delegateeAddresses.map((address) => - address.startsWith('0x') ? address.slice(2) : address - ), - } - : {}), - uses: _uses.toString(), - }; - - recapObject.addCapabilityForResource( - litResource, - LitAbility.RateLimitIncreaseAuth, - capabilities - ); - - // make sure that the resource is added to the recapObject - const verified = recapObject.verifyCapabilitiesForResource( - litResource, - LitAbility.RateLimitIncreaseAuth - ); - - // -- validate - if (!verified) { - throw new Error('Failed to verify capabilities for resource'); - } - const nonce = await this.getLatestBlockhash(); - // -- get auth sig - let siweMessage = new siwe.SiweMessage({ - domain: _domain, - address: dAppOwnerWalletAddress, - statement: _statement, - uri: SIWE_DELEGATION_URI, - version: '1', - chainId: 1, - nonce: nonce?.toString(), - expirationTime: _expiration, + const siweMessage = await createSiweMessageWithCapacityDelegation({ + uri: 'lit:capability:delegation', + litNodeClient: this, + walletAddress: dAppOwnerWalletAddress, + nonce: nonce, + + // -- default configuration for recap object capability + expiration: + params.expiration ?? new Date(Date.now() + 1000 * 60 * 7).toISOString(), + domain: params.domain ?? 'example.com', + statement: + params.statement ?? + 'This is a test statement. You can put anything you want here.', + + // -- capacity delegation specific configuration + uses: params.uses ?? '1', + delegateeAddresses: params.delegateeAddresses, + capacityTokenId: params.capacityTokenId, }); - siweMessage = recapObject.addToSiweMessage(siweMessage); - - const messageToSign = siweMessage.prepareMessage(); - - let signature = await dAppOwnerWallet.signMessage(messageToSign); - // replacing 0x to match the tested working authSig from node - signature = signature.replace('0x', ''); - - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: dAppOwnerWalletAddress.replace('0x', '').toLowerCase(), - algo: null, // This is added to match the tested working authSig from node - }; + const authSig = await craftAuthSig({ + signer: params.dAppOwnerWallet, + toSign: siweMessage, + }); - return { litResource, capacityDelegationAuthSig: authSig }; + return { capacityDelegationAuthSig: authSig }; }; // ========== Scoped Class Helpers ========== @@ -738,12 +673,12 @@ export class LitNodeClientNodeJs if (!authSig) { throw new Error('authSig or sessionSig is required'); } - const data: JsonExecutionRequest = { - authSig, - code, - ipfsId, - jsParams, - authMethods, + const data: JsExecutionRequestBody = { + ...(authSig ? { authSig } : {}), + ...(code ? { code } : {}), + ...(ipfsId ? { ipfsId } : {}), + ...(authMethods ? { authMethods } : {}), + ...(jsParams ? { jsParams } : {}), }; const res = await this.sendCommandToNode({ @@ -1276,9 +1211,9 @@ export class LitNodeClientNodeJs // -- validate if signature type is ECDSA if ( - sigType !== SIGTYPE.EcdsaCaitSith && - sigType !== SIGTYPE.EcdsaK256 && - sigType !== SIGTYPE.EcdsaCAITSITHP256 + sigType !== LIT_CURVE.EcdsaCaitSith && + sigType !== LIT_CURVE.EcdsaK256 && + sigType !== LIT_CURVE.EcdsaCAITSITHP256 ) { throwError({ message: `signature type is ${sigType} which is invalid`, @@ -1440,9 +1375,9 @@ export class LitNodeClientNodeJs // -- validate if signature type is ECDSA if ( - sigType !== SIGTYPE.EcdsaCaitSith && - sigType !== SIGTYPE.EcdsaK256 && - sigType !== SIGTYPE.EcdsaCAITSITHP256 + sigType !== LIT_CURVE.EcdsaCaitSith && + sigType !== LIT_CURVE.EcdsaK256 && + sigType !== LIT_CURVE.EcdsaCAITSITHP256 ) { throwError({ message: `signature type is ${sigType} which is invalid`, @@ -2449,11 +2384,13 @@ export class LitNodeClientNodeJs signSessionKey = async ( params: SignSessionKeyProp ): Promise => { + log(`[signSessionKey] params:`, params); + // ========== Validate Params ========== // -- validate: If it's NOT ready if (!this.ready) { const message = - '8 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; + '[signSessionKey] ]LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; throwError({ message, @@ -2467,18 +2404,36 @@ export class LitNodeClientNodeJs params.expiration || new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(); - // Try to get it from local storage, if not generates one~ - const sessionKey = params.sessionKey ?? this.getSessionKey(); - const sessionKeyUri = LIT_SESSION_KEY_URI + sessionKey.publicKey; + let sessionKeyUri: string; + + // This allow the user to provide a sessionKeyUri directly without using the session key pair + if (params?.sessionKeyUri) { + sessionKeyUri = params.sessionKeyUri; + log(`[signSessionKey] sessionKeyUri found in params:`, sessionKeyUri); + } else { + // Try to get it from local storage, if not generates one~ + let sessionKey: SessionKeyPair = + params.sessionKey ?? this.getSessionKey(); + sessionKeyUri = LIT_SESSION_KEY_URI + sessionKey.publicKey; + + log( + `[signSessionKey] sessionKeyUri is not found in params, generating a new one`, + sessionKeyUri + ); + } + + if (!sessionKeyUri) { + throw new Error( + '[signSessionKey] sessionKeyUri is not defined. Please provide a sessionKeyUri or a sessionKey.' + ); + } // Compute the address from the public key if it's provided. Otherwise, the node will compute it. const pkpEthAddress = (function () { - if (params.pkpPublicKey) { - // prefix '0x' if it's not already prefixed - const hexedPkpPublicKey = hexPrefixed(params.pkpPublicKey); + // prefix '0x' if it's not already prefixed + params.pkpPublicKey = hexPrefixed(params.pkpPublicKey!); - if (hexedPkpPublicKey) return computeAddress(hexedPkpPublicKey); - } + if (params.pkpPublicKey) return computeAddress(params.pkpPublicKey); // This will be populated by the node, using dummy value for now. return '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; @@ -2487,75 +2442,50 @@ export class LitNodeClientNodeJs let siwe_statement = 'Lit Protocol PKP session signature'; if (params.statement) { siwe_statement += ' ' + params.statement; + log(`[signSessionKey] statement found in params: "${params.statement}"`); } let siweMessage; - if (params?.resourceAbilityRequests) { - const resources = params.resourceAbilityRequests.map((r) => r.resource); - - const recapObject = - await this.generateSessionCapabilityObjectWithWildcards(resources); - - params.resourceAbilityRequests.forEach((r) => { - recapObject.addCapabilityForResource(r.resource, r.ability); - - const verified = recapObject.verifyCapabilitiesForResource( - r.resource, - r.ability - ); - - if (!verified) { - throw new Error('Failed to verify capabilities for resource'); - } - }); + const siweParams = { + domain: params?.domain || globalThis.location?.host || 'litprotocol.com', + walletAddress: pkpEthAddress, + statement: siwe_statement, + uri: sessionKeyUri, + version: '1', + chainId: params.chainId ?? 1, + expiration: _expiration, + nonce: this.latestBlockhash!, + }; - // regular siwe - siweMessage = new siwe.SiweMessage({ - domain: - params?.domain || globalThis.location?.host || 'litprotocol.com', - address: pkpEthAddress, - statement: siwe_statement, - uri: sessionKeyUri, - version: '1', - chainId: params.chainId ?? 1, - expirationTime: _expiration, - resources: params.resources, - nonce: this.latestBlockhash!, + if (params.resourceAbilityRequests) { + siweMessage = await createSiweMessageWithRecaps({ + ...siweParams, + resources: params.resourceAbilityRequests, + litNodeClient: this, }); - - siweMessage = recapObject.addToSiweMessage(siweMessage); } else { - // lit-siwe (NOT regular siwe) - siweMessage = new siwe.SiweMessage({ - domain: - params?.domain || globalThis.location?.host || 'litprotocol.com', - address: pkpEthAddress, - statement: siwe_statement, - uri: sessionKeyUri, - version: '1', - chainId: params.chainId ?? 1, - expirationTime: _expiration, - resources: params.resources, - nonce: this.latestBlockhash!, - }); + siweMessage = await createSiweMessage(siweParams); } - const siweMessageStr: string = ( - siweMessage as siwe.SiweMessage - ).prepareMessage(); - // ========== Get Node Promises ========== // -- fetch shares from nodes - const body = { + const body: JsonSignSessionKeyRequestV1 = { sessionKey: sessionKeyUri, authMethods: params.authMethods, - pkpPublicKey: params.pkpPublicKey, + ...(params?.pkpPublicKey && { pkpPublicKey: params.pkpPublicKey }), ...(params?.authSig && { authSig: params.authSig }), - // authSig: params.authSig, - siweMessage: siweMessageStr, + siweMessage: siweMessage, + curveType: LIT_CURVE.BLS, + + // -- custom auths + ...(params?.litActionCode && { code: params.litActionCode }), + ...(params?.jsParams && { jsParams: params.jsParams }), + ...(this.currentEpochNumber && { epoch: this.currentEpochNumber }), }; + log(`[signSessionKey] body:`, body); + const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { @@ -2609,74 +2539,215 @@ export class LitNodeClientNodeJs const responseData = res.values; logWithRequestId( requestId, - 'responseData', + '[signSessionKey] responseData', JSON.stringify(responseData, null, 2) ); // ========== Extract shares from response data ========== // -- 1. combine signed data as a list, and get the signatures from it - const signedDataList = responseData.map( - (r: any) => (r as SignedData).signedData - ); + let curveType = responseData[0]?.curveType; + + if (!curveType) { + log(`[signSessionKey] curveType not found. Defaulting to ECDSA.`); + curveType = 'ECDSA'; + } - logWithRequestId(requestId, 'signedDataList', signedDataList); + log(`[signSessionKey] curveType is "${curveType}"`); + + let signedDataList: any[] = []; + + if (curveType === LIT_CURVE.BLS) { + let _responseData: BlsResponseData[] = responseData; + + const signatureShares = _responseData.map((s) => ({ + ProofOfPossession: s.signatureShare.ProofOfPossession, + })); + + log(`[signSessionKey] signatureShares:`, signatureShares); + + signedDataList = _responseData.map((s) => { + return s.dataSigned; + }); + + signedDataList = _responseData; + } else { + signedDataList = responseData.map( + (r: any) => (r as SignedData).signedData + ); + } + + if (signedDataList.length <= 0) { + const err = `[signSessionKey] signedDataList is empty.`; + log(err); + throw new Error(err); + } + + logWithRequestId( + requestId, + '[signSessionKey] signedDataList', + signedDataList + ); // -- checking if we have enough shares const validatedSignedDataList = signedDataList .map((signedData: any) => { - const sessionSig = signedData['sessionSig']; + const sessionSig = signedData['sessionSig'] ?? signedData; + + // add backwards compatibility for `sigType` field + // For more context: Previously, the field was called `sigType` but it was changed to `curveType` because we are now using BLS instead of ECDSA. + if (sessionSig['curveType'] && !sessionSig['sigType']) { + sessionSig['sigType'] = sessionSig['curveType']; + } // each of this field cannot be empty - const requiredFields = [ - 'sigType', - 'dataSigned', - 'signatureShare', - 'bigr', - 'publicKey', - 'sigName', - 'siweMessage', - ]; + let requiredFields = + curveType === LIT_CURVE.BLS + ? [ + 'signatureShare', + 'curveType', + 'shareIndex', + 'siweMessage', + 'dataSigned', + 'blsRootPubkey', + 'result', + ] + : [ + 'sigType', + 'dataSigned', + 'signatureShare', + 'bigr', + 'publicKey', + 'sigName', + 'siweMessage', + ]; // check if all required fields are present for (const field of requiredFields) { if (!sessionSig[field] || sessionSig[field] === '') { log( - `Invalid signed data. ${field} is missing. Not a problem, we only need ${this.config.minNodeCount} nodes to sign the session key.` + `[signSessionKey] Invalid signed data. "${field}" is missing. Not a problem, we only need ${this.config.minNodeCount} nodes to sign the session key.` ); return null; } } + if (curveType === LIT_CURVE.BLS) { + if (!sessionSig.signatureShare.ProofOfPossession) { + const err = `[signSessionKey] Invalid signed data. "ProofOfPossession" is missing.`; + log(err); + throw new Error(err); + } + } + return signedData; }) .filter((item) => item !== null); - logWithRequestId(requestId, 'requested length:', signedDataList.length); logWithRequestId( requestId, - 'validated length:', + '[signSessionKey] requested length:', + signedDataList.length + ); + logWithRequestId( + requestId, + '[signSessionKey] validated length:', validatedSignedDataList.length ); logWithRequestId( requestId, - 'minimum required length:', + '[signSessionKey] minimum required length:', this.config.minNodeCount ); if (validatedSignedDataList.length < this.config.minNodeCount) { throw new Error( - `not enough nodes signed the session key. Expected ${this.config.minNodeCount}, got ${validatedSignedDataList.length}` + `[signSessionKey] not enough nodes signed the session key. Expected ${this.config.minNodeCount}, got ${validatedSignedDataList.length}` ); } - const signatures = this.getSessionSignatures(validatedSignedDataList); + let signatures: any; + + if (curveType === LIT_CURVE.BLS) { + const blsSignedData: BlsResponseData[] = + validatedSignedDataList as BlsResponseData[]; + + const sigType = mostCommonString( + blsSignedData.map((s: any) => s.sigType) + ); + log(`[signSessionKey] sigType:`, sigType); + + const signatureShares = blsSignedData.map((s) => ({ + ProofOfPossession: s.signatureShare.ProofOfPossession, + })); + + log(`[signSessionKey] signatureShares:`, signatureShares); + + const blsCombinedSignature = blsSdk.combine_signature_shares( + signatureShares.map((s) => JSON.stringify(s)) + ); + + log(`[signSessionKey] blsCombinedSignature:`, blsCombinedSignature); + + const publicKey = params.pkpPublicKey.startsWith('0x') + ? params.pkpPublicKey.slice(2) + : params.pkpPublicKey; + + const dataSigned = mostCommonString( + blsSignedData.map((s: any) => s.dataSigned) + ); + const siweMessage = mostCommonString( + blsSignedData.map((s: any) => s.siweMessage) + ); + signatures = { + sessionSig: { + signature: blsCombinedSignature, + publicKey, + dataSigned, + siweMessage, + }, + }; + } else { + // Shape: [signSessionKey] signatures: { + // sessionSig: { + // r: "xx", + // s: "yy", + // recid: 1, + // signature: "0x...", + // publicKey: "04e...", + // dataSigned: "7c1...", + // siweMessage: "litprotocol.com wants you to sign in with your Ethereum account:\n0xd69969c6a2E56C928d63F12325fe1d9D47115C91\n\nLit Protocol PKP session signature Some custom statement. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Signing' for 'lit-pkp://*'.\n\nURI: lit:session:95ff87b5d2210c382ccfcba6bdb16ceb217da9726c91d0fdda5eb888f087488f\nVersion: 1\nChain ID: 1\nNonce: 0x337906a8c2a6da52d438495fc1b0145ed5632ec32ffa1dda1064f43775b3a802\nIssued At: 2024-04-09T17:58:47Z\nExpiration Time: 2024-04-10T17:59:13.420Z\nResources:\n- urn:recap:eyJhdHQiOnt9LCJwcmYiOltdfQ\n- urn:recap:eyJhdHQiOnsibGl0LXBrcDovLyoiOnsiVGhyZXNob2xkL1NpZ25pbmciOlt7fV19fSwicHJmIjpbXX0", + // }, + // } + signatures = this.getSessionSignatures(validatedSignedDataList); + } + + log('[signSessionKey] signatures:', signatures); const { sessionSig } = signatures; + const signedMessage = normalizeAndStringify(sessionSig.siweMessage); + + log(`[signSessionKey] signedMessage:`, signedMessage); + + if (curveType === LIT_CURVE.BLS) { + return { + authSig: { + sig: JSON.stringify({ + ProofOfPossession: sessionSig.signature, + }), + algo: 'LIT_BLS', + derivedVia: 'lit.bls', + signedMessage, + address: computeAddress('0x' + sessionSig.publicKey), + }, + pkpPublicKey: sessionSig.publicKey, + }; + } + return { authSig: { sig: sessionSig.signature, derivedVia: 'web3.eth.personal.sign via Lit PKP', - signedMessage: sessionSig.siweMessage, + signedMessage, address: computeAddress('0x' + sessionSig.publicKey), }, pkpPublicKey: sessionSig.publicKey, @@ -2829,11 +2900,12 @@ export class LitNodeClientNodeJs const sessionExpiration = new Date(Date.now() + 1000 * 60 * 5); const capabilities = params.capacityDelegationAuthSig - ? [params.capacityDelegationAuthSig, authSig] - : [authSig]; - // const capabilities = params.capacityDelegationAuthSig ? [authSig, params.capacityDelegationAuthSig] : [authSig]; - - // console.log('capabilities:', capabilities); + ? [ + ...(params.capabilityAuthSigs ?? []), + params.capacityDelegationAuthSig, + authSig, + ] + : [...(params.capabilityAuthSigs ?? []), authSig]; const signingTemplate = { sessionKey: sessionKey.publicKey, @@ -2853,11 +2925,6 @@ export class LitNodeClientNodeJs const signedMessage = JSON.stringify(toSign); - // sanitise signedMessage, replace //n with /n - // signedMessage = signedMessage.replaceAll(/\/\/n/g, '/n'); - - // console.log('XX signedMessage:', signedMessage); - const uint8arrayKey = uint8arrayFromString( sessionKey.secretKey, 'base16' @@ -2866,7 +2933,6 @@ export class LitNodeClientNodeJs const uint8arrayMessage = uint8arrayFromString(signedMessage, 'utf8'); const signature = nacl.sign.detached(uint8arrayMessage, uint8arrayKey); - // log("signature", signature); signatures[nodeAddress] = { sig: uint8arrayToString(signature, 'base16'), derivedVia: 'litSessionSignViaNacl', @@ -2881,6 +2947,13 @@ export class LitNodeClientNodeJs return signatures; }; + /** + * Retrieves the PKP sessionSigs. + * + * @param params - The parameters for retrieving the PKP sessionSigs. + * @returns A promise that resolves to the PKP sessionSigs. + * @throws An error if any of the required parameters are missing or if `litActionCode` and `ipfsId` exist at the same time. + */ getPkpSessionSigs = async (params: GetPkpSessionSigs) => { const chain = params?.chain || 'ethereum'; diff --git a/packages/misc/src/lib/misc.ts b/packages/misc/src/lib/misc.ts index 0489aec0b0..8852753d41 100644 --- a/packages/misc/src/lib/misc.ts +++ b/packages/misc/src/lib/misc.ts @@ -859,3 +859,41 @@ export async function executeWithRetry( requestId, }; } + +/** + * Attempts to normalize a string by unescaping it until it can be parsed as a JSON object, + * then stringifies it exactly once. If the input is a regular string that does not represent + * a JSON object or array, the function will return it as is without modification. + * This function is designed to handle cases where strings might be excessively escaped due + * to multiple layers of encoding, ensuring that JSON data is stored in a consistent and + * predictable format, and regular strings are left unchanged. + * + * @param input The potentially excessively escaped string. + * @return A string that is either the JSON.stringify version of the original JSON object + * or the original string if it does not represent a JSON object or array. + */ +export function normalizeAndStringify(input: string): string { + try { + // Directly return the string if it's not in a JSON format + if (!input.startsWith('{') && !input.startsWith('[')) { + return input; + } + + // Attempt to parse the input as JSON + const parsed = JSON.parse(input); + + // If parsing succeeds, return the stringified version of the parsed JSON + return JSON.stringify(parsed); + } catch (error) { + // If parsing fails, it might be due to extra escaping + const unescaped = input.replace(/\\(.)/g, '$1'); + + // If unescaping doesn't change the string, return it as is + if (input === unescaped) { + return input; + } + + // Otherwise, recursively call the function with the unescaped string + return normalizeAndStringify(unescaped); + } +} From 63a3ffc1dc63f0e15fbe72bb09cf111e1b0bcd74 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Tue, 23 Apr 2024 23:10:54 +0100 Subject: [PATCH 013/263] docs: update comments --- .../src/lib/siwe/create-siwe-message.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts index 2f82343767..0600ec98f9 100644 --- a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts +++ b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts @@ -12,6 +12,12 @@ import { addRecapToSiweMessage, } from './siwe-helper'; +/** + * Creates a SIWE + * @param params - The parameters for creating the SIWE message. + * @returns A promise that resolves to the created SIWE message as a string. + * @throws An error if the walletAddress parameter is missing. + */ export const createSiweMessage = async ( params: T ): Promise => { @@ -69,6 +75,13 @@ export const createSiweMessage = async ( return siweMessage.prepareMessage(); }; + +/** + * Creates a SIWE message with recaps added to it. + * + * @param params - The parameters for creating the SIWE message with recaps. + * @returns A Promise that resolves to a string representing the SIWE message. + */ export const createSiweMessageWithRecaps = async ( params: WithRecap ): Promise => { @@ -76,6 +89,13 @@ export const createSiweMessageWithRecaps = async ( ...params, }); }; + +/** + * Creates a SIWE message with capacity delegation. + * @param params - The parameters for creating the SIWE message. + * @returns A Promise that resolves to the created SIWE message. + * @throws An error if litNodeClient is not provided. + */ export const createSiweMessageWithCapacityDelegation = async ( params: WithCapacityDelegation ) => { From d90d7b1fcda8c4f6ea41fd0f020968fc43ed30e6 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:48:56 +0100 Subject: [PATCH 014/263] fix(siwe): dAppOwnerWallet is actually the only required param to create the delegation auth sig --- packages/auth-helpers/src/lib/siwe/create-siwe-message.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts index 2f82343767..ac6e8d7e50 100644 --- a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts +++ b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts @@ -41,9 +41,10 @@ export const createSiweMessage = async ( // -- create a message with capacity credits if ( - 'uses' in params || - 'delegateeAddresses' in params || - 'capacityTokenId' in params + 'dAppOwnerWallet' in params || // required param + 'uses' in params || // optional + 'delegateeAddresses' in params || // optional + 'capacityTokenId' in params // optional ) { const ccParams = params as CapacityDelegationFields; From a4b149c644ebef18cf5cf54fc99c7e583fb05ad5 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:50:08 +0100 Subject: [PATCH 015/263] fix(lint): let to const --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 068672bf7e..dc3b4c56dc 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -582,7 +582,7 @@ export class LitContracts { } if (!context) { - let contractData = await LitContracts._resolveContractContext( + const contractData = await LitContracts._resolveContractContext( network, context ); @@ -602,7 +602,7 @@ export class LitContracts { // if we have contract context then we determine if there exists a `resolverAddres` // if there is a resolver address we assume we are using a contract resolver for bootstrapping of contracts if (!context.resolverAddress) { - let stakingContract = (context as LitContractContext).Staking; + const stakingContract = (context as LitContractContext).Staking; if (!stakingContract.address) { throw new Error( @@ -615,7 +615,7 @@ export class LitContracts { provider ); } else { - let contractContext = await LitContracts._getContractsFromResolver( + const contractContext = await LitContracts._getContractsFromResolver( context as LitContractResolverContext, provider, ['Staking'] From 6d872cf18f337b68486e40c3a210c0681106187a Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:50:50 +0100 Subject: [PATCH 016/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/435#discussion_r1576978843 --- .../src/lib/lit-node-client-nodejs.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index cde9abac88..06919ef3bd 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2881,6 +2881,13 @@ export class LitNodeClientNodeJs return signatures; }; + /** + * Retrieves the PKP session signatures. + * + * @param params - The parameters for retrieving the PKP session signatures. + * @returns A promise that resolves to the PKP session signatures. + * @throws An error if any required parameter is missing or if both `litActionCode` and `ipfsId` are provided. + */ getPkpSessionSigs = async (params: GetPkpSessionSigs) => { const chain = params?.chain || 'ethereum'; From a2f6308839757bee4bf5a14f64c7c124362f32a2 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:52:55 +0100 Subject: [PATCH 017/263] fix(pkpSessionSigs): add getPkpSessionSigs to LitClientSessionManager --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 4 +++- packages/types/src/lib/interfaces.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 06919ef3bd..be9431ae2b 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2888,7 +2888,9 @@ export class LitNodeClientNodeJs * @returns A promise that resolves to the PKP session signatures. * @throws An error if any required parameter is missing or if both `litActionCode` and `ipfsId` are provided. */ - getPkpSessionSigs = async (params: GetPkpSessionSigs) => { + getPkpSessionSigs = async ( + params: GetPkpSessionSigs + ): Promise => { const chain = params?.chain || 'ethereum'; const pkpSessionSigs = this.getSessionSigs({ diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 258333c7cd..db1a91474b 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1014,6 +1014,7 @@ export interface LitClientSessionManager { // authCallbackParams: AuthCallbackParams; // authCallback?: AuthCallback; // }) => Promise; + getPkpSessionSigs: (params: GetPkpSessionSigs) => Promise; checkNeedToResignSessionKey: (params: { authSig: AuthSig; sessionKeyUri: any; From fbe4005510111cbdc4c0873de30b8388d0960bcf Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:53:51 +0100 Subject: [PATCH 018/263] docs: fix jsDocs https://github.com/LIT-Protocol/js-sdk/pull/435#discussion_r1576989384 --- packages/types/src/lib/interfaces.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index db1a91474b..1454ba293b 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -916,17 +916,19 @@ export interface GetSessionSigsProps extends LitCustomAuth { */ sessionCapabilityObject?: ISessionCapabilityObject; - // If you want to ask Metamask to try and switch the user's chain, you may pass true here. This will only work if the user is using Metamask. If the user is not using Metamask, then this will be ignored. + /** + * If you want to ask Metamask to try and switch the user's chain, you may pass true here. This will only work if the user is using Metamask. If the user is not using Metamask, then this will be ignored. + */ switchChain?: boolean; - // This is a callback that will be called if the user needs to authenticate using a PKP. For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. This callback should use the LitNodeClient.signSessionKey function to get a session signature for the user from their PKP. If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. + /** + * This is a callback that will be called if the user needs to authenticate using a PKP. For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. This callback should use the LitNodeClient.signSessionKey function to get a session signature for the user from their PKP. If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. + */ authNeededCallback?: AuthCallback; // The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. sessionKey?: any; - // rateLimitAuthSig: AuthSig; - /** * @deprecated - use capabilityAuthSigs instead * Used for delegation of Capacity Credit. This signature will be checked for proof of capacity credit. From 5e3e3bd9d802eaf9263ddd381c0f85be7e1893c5 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:57:59 +0100 Subject: [PATCH 019/263] fix(test): try/catch on polyfill https://github.com/LIT-Protocol/js-sdk/pull/435#discussion_r1576914291 --- local-tests/build.mjs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/local-tests/build.mjs b/local-tests/build.mjs index 773624bb10..0ea3586e8e 100644 --- a/local-tests/build.mjs +++ b/local-tests/build.mjs @@ -32,8 +32,9 @@ export const build = async () => { * @returns {void} */ export const postBuildPolyfill = () => { - const file = fs.readFileSync(`./${TEST_DIR}/build/test.mjs`, 'utf8'); - const content = `import fetch from 'cross-fetch'; + try { + const file = fs.readFileSync(`./${TEST_DIR}/build/test.mjs`, 'utf8'); + const content = `import fetch from 'cross-fetch'; try { if (!globalThis.fetch) { globalThis.fetch = fetch; @@ -42,8 +43,11 @@ try { console.error('❌ Error in polyfill', error); } `; - const newFile = content + file; - fs.writeFileSync(`./${TEST_DIR}/build/test.mjs`, newFile); + const newFile = content + file; + fs.writeFileSync(`./${TEST_DIR}/build/test.mjs`, newFile); + } catch (e) { + throw new Error(`Error in postBuildPolyfill: ${e}`); + } }; // Go! From c27b92d63a8ca0d6fc9e3de73d50dcc6bed4a1b0 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 02:58:55 +0100 Subject: [PATCH 020/263] feat: change craft to generate https://github.com/LIT-Protocol/js-sdk/pull/435#discussion_r1576915101 --- local-tests/setup/session-sigs/get-eoa-session-sigs.ts | 6 +++--- local-tests/setup/tinny-person.ts | 4 ++-- packages/auth-helpers/src/lib/craft-auth-sig.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/local-tests/setup/session-sigs/get-eoa-session-sigs.ts b/local-tests/setup/session-sigs/get-eoa-session-sigs.ts index 057eed415b..e6afeaef70 100644 --- a/local-tests/setup/session-sigs/get-eoa-session-sigs.ts +++ b/local-tests/setup/session-sigs/get-eoa-session-sigs.ts @@ -1,7 +1,7 @@ import { LitActionResource, LitPKPResource, - craftAuthSig, + generateAuthSig, createSiweMessageWithRecaps, } from '@lit-protocol/auth-helpers'; import { @@ -78,7 +78,7 @@ export const getEoaSessionSigs = async ( litNodeClient: devEnv.litNodeClient, }); - const authSig = await craftAuthSig({ + const authSig = await generateAuthSig({ signer: person.wallet, toSign, }); @@ -140,7 +140,7 @@ export const getEoaSessionSigsWithCapacityDelegations = async ( litNodeClient: devEnv.litNodeClient, }); - const authSig = await craftAuthSig({ + const authSig = await generateAuthSig({ signer: fromWallet, toSign, }); diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index 210a2943f1..bd5057ac42 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -1,6 +1,6 @@ import { AuthSig, - craftAuthSig, + generateAuthSig, createSiweMessage, } from '@lit-protocol/auth-helpers'; import { LitContracts } from '@lit-protocol/contracts-sdk'; @@ -62,7 +62,7 @@ export class TinnyPerson { walletAddress: this.wallet.address, }); - this.authSig = await craftAuthSig({ + this.authSig = await generateAuthSig({ signer: this.wallet, toSign: this.siweMessage, }); diff --git a/packages/auth-helpers/src/lib/craft-auth-sig.ts b/packages/auth-helpers/src/lib/craft-auth-sig.ts index 42bc8fdb18..e1fee7fe27 100644 --- a/packages/auth-helpers/src/lib/craft-auth-sig.ts +++ b/packages/auth-helpers/src/lib/craft-auth-sig.ts @@ -2,7 +2,7 @@ import { AuthSig, SignerLike } from '@lit-protocol/types'; import { ethers } from 'ethers'; /** - * Crafts an AuthSig object using the signer. + * Generate an AuthSig object using the signer. * * For more context: * We are only using authSig to generate session sigs. In a newer version, we will stop accepting @@ -13,7 +13,7 @@ import { ethers } from 'ethers'; * @param address - (optional) the address of the signer * @returns */ -export const craftAuthSig = async ({ +export const generateAuthSig = async ({ signer, toSign, address, From 2c37483a9aa4f3625350bae6df42c31534cf52e8 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:04:56 +0100 Subject: [PATCH 021/263] feat(endpoints): centralised all endpoints with types --- local-tests/setup/tinny-config.ts | 53 +------------------ local-tests/setup/tinny-environment.ts | 9 +--- packages/constants/src/index.ts | 1 + .../constants/src/lib/constants/constants.ts | 1 + .../constants/src/lib/constants/endpoints.ts | 52 ++++++++++++++++++ packages/core/src/index.ts | 1 + packages/core/src/lib/endpoint-version.ts | 32 +++++++++++ packages/core/src/lib/lit-core.ts | 7 ++- .../src/lib/lit-node-client-nodejs.ts | 42 +++++++++++---- 9 files changed, 129 insertions(+), 69 deletions(-) create mode 100644 packages/constants/src/lib/constants/endpoints.ts create mode 100644 packages/core/src/lib/endpoint-version.ts diff --git a/local-tests/setup/tinny-config.ts b/local-tests/setup/tinny-config.ts index a4d53754dd..1b1dc893d6 100644 --- a/local-tests/setup/tinny-config.ts +++ b/local-tests/setup/tinny-config.ts @@ -91,55 +91,4 @@ export interface TinnyEnvConfig { litNodeClient: LitNodeClient; network: LIT_TESTNET; processEnvs: ProcessEnvs; -} - -export enum LIT_ENDPOINT_VERSION { - LEGACY = '/', - V1 = '/v1', -} - -export const LIT_ENDPOINT = { - HANDSHAKE: { - path: '/web/handshake', - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'HANDSHAKE', - }, - SIGN_SESSION_KEY: { - path: '/web/sign_session_key', - // version: LIT_ENDPOINT_VERSION.V1, - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'SIGN_SESSION_KEY', - }, - EXECUTE_JS: { - path: '/web/execute', - // version: LIT_ENDPOINT_VERSION.V1, - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'EXECUTE_JS', - }, - PKP_SIGN: { - path: '/web/pkp/sign', - // version: LIT_ENDPOINT_VERSION.V1, - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'PKP_SIGN', - }, - PKP_CLAIM: { - path: '/web/pkp/claim', - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'PKP_CLAIM', - }, - SIGN_ACCS: { - path: '/web/signing/access_control_condition', - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'SIGN_ACCS', - }, - ENCRYPTION_SIGN: { - path: '/web/encryption/sign', - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'ENCRYPTION_SIGN', - }, - SIGN_ECDSA: { - path: '/web/signing/signConditionEcdsa', - version: LIT_ENDPOINT_VERSION.LEGACY, - envName: 'SIGN_ECDSA', - }, -}; +} \ No newline at end of file diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index c33c098667..0bc59fbe51 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -1,16 +1,11 @@ -import { - LIT_ENDPOINT, - LIT_ENDPOINT_VERSION, - LIT_TESTNET, - ProcessEnvs, - TinnyEnvConfig, -} from './tinny-config'; +import { LIT_TESTNET, ProcessEnvs, TinnyEnvConfig } from './tinny-config'; import { LitNodeClient } from '@lit-protocol/lit-node-client'; import { LitContracts } from '@lit-protocol/contracts-sdk'; import { AuthSig, LitContractContext } from '@lit-protocol/types'; import { TinnyPerson } from './tinny-person'; import networkContext from './networkContext.json'; import { ethers } from 'ethers'; +import { LIT_ENDPOINT, LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; export class TinnyEnvironment { public network: LIT_TESTNET; diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts index e0bd1d0faf..d6f7e6862e 100644 --- a/packages/constants/src/index.ts +++ b/packages/constants/src/index.ts @@ -3,6 +3,7 @@ export * from './lib/version'; // ----------- Constants ----------- export * from './lib/constants/constants'; +export * from './lib/constants/endpoints'; export * from './lib/constants/autogen_internal'; // ----------- Interfaces ----------- diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 042d6d8c8d..6577787e7b 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -789,3 +789,4 @@ export const RELAY_URL_MANZANO = 'https://manzano-relayer.getlit.dev'; // ========== Lit Actions ========== export const LIT_ACTION_IPFS_HASH = 'QmUjX8MW6StQ7NKNdaS6g4RMkvN5hcgtKmEi8Mca6oX4t3'; + diff --git a/packages/constants/src/lib/constants/endpoints.ts b/packages/constants/src/lib/constants/endpoints.ts new file mode 100644 index 0000000000..e123184685 --- /dev/null +++ b/packages/constants/src/lib/constants/endpoints.ts @@ -0,0 +1,52 @@ +export enum LIT_ENDPOINT_VERSION { + LEGACY = '/', + V1 = '/v1', +} + +export const LIT_ENDPOINT = { + HANDSHAKE: { + path: '/web/handshake', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'HANDSHAKE', + }, + SIGN_SESSION_KEY: { + path: '/web/sign_session_key', + // version: LIT_ENDPOINT_VERSION.V1, + + // FIXME: Change this to V1 once the new version is deployed to all public networks + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'SIGN_SESSION_KEY', + }, + EXECUTE_JS: { + path: '/web/execute', + // FIXME: Change this to V1 once the new version is deployed to all public networks + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'EXECUTE_JS', + }, + PKP_SIGN: { + path: '/web/pkp/sign', + // version: LIT_ENDPOINT_VERSION.V1, + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'PKP_SIGN', + }, + PKP_CLAIM: { + path: '/web/pkp/claim', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'PKP_CLAIM', + }, + SIGN_ACCS: { + path: '/web/signing/access_control_condition', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'SIGN_ACCS', + }, + ENCRYPTION_SIGN: { + path: '/web/encryption/sign', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'ENCRYPTION_SIGN', + }, + SIGN_ECDSA: { + path: '/web/signing/signConditionEcdsa', + version: LIT_ENDPOINT_VERSION.LEGACY, + envName: 'SIGN_ECDSA', + }, +}; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 395f767467..63e9e0e404 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1 +1,2 @@ export * from './lib/lit-core'; +export * from './lib/endpoint-version'; \ No newline at end of file diff --git a/packages/core/src/lib/endpoint-version.ts b/packages/core/src/lib/endpoint-version.ts new file mode 100644 index 0000000000..2fad4b296f --- /dev/null +++ b/packages/core/src/lib/endpoint-version.ts @@ -0,0 +1,32 @@ +import { isNode } from '@lit-protocol/misc'; +import { LitEndpoint } from '@lit-protocol/types'; + +/** + * Compose the Lit URL + * @param params + * @returns the composed URL + */ +export const composeLitUrl = (params: { + url: string; + endpoint: LitEndpoint; +}) => { + // check if params.url is a valid URL + try { + new URL(params.url); + } catch (error) { + throw new Error(`[composeLitUrl] Invalid URL: "${params.url}"`); + } + + let versionOverride: string | null = null; + + // Get the version override for a particular endpoint + // FIXME: We will remove this completly once v0.1 is deployed to all public networks + if (isNode()) { + versionOverride = process.env[`${params.endpoint.envName}`] || null; + } + + // Use the overridden version if it exists, otherwise use the default + const version = versionOverride || params.endpoint.version; + + return `${params.url}${params.endpoint.path}${version}`; +}; diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 358eefeed9..e529dd4e67 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -22,6 +22,7 @@ import { SIGTYPE, StakingStates, version, + LIT_ENDPOINT, } from '@lit-protocol/constants'; import { LitContracts } from '@lit-protocol/contracts-sdk'; import { checkSevSnpAttestation, computeHDPubKey } from '@lit-protocol/crypto'; @@ -58,6 +59,7 @@ import type { SuccessNodePromises, SupportedJsonRequests, } from '@lit-protocol/types'; +import { composeLitUrl } from './endpoint-version'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type Listener = (...args: any[]) => void; @@ -891,7 +893,10 @@ export class LitCore { const { url } = params; // -- create url with path - const urlWithPath = `${url}/web/handshake`; + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.HANDSHAKE, + }); log(`handshakeWithNode ${urlWithPath}`); diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index be9431ae2b..4cbae9ee85 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -19,6 +19,7 @@ import { AuthMethodType, EITHER_TYPE, LIT_ACTION_IPFS_HASH, + LIT_ENDPOINT, LIT_ERROR, LIT_SESSION_KEY_URI, LOCAL_STORAGE_KEYS, @@ -26,7 +27,7 @@ import { SIGTYPE, SIWE_DELEGATION_URI, } from '@lit-protocol/constants'; -import { LitCore } from '@lit-protocol/core'; +import { LitCore, composeLitUrl } from '@lit-protocol/core'; import { checkSevSnpAttestation, combineEcdsaShares, @@ -732,8 +733,10 @@ export class LitNodeClientNodeJs logWithRequestId(requestId, 'getJsExecutionShares'); // -- execute - - let urlWithPath = `${url}/web/execute`; + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.EXECUTE_JS, + }); if (!authSig) { throw new Error('authSig or sessionSig is required'); @@ -765,7 +768,10 @@ export class LitNodeClientNodeJs requestId: string ) => { logWithRequestId(requestId, 'getPkpSigningShares'); - const urlWithPath = `${url}/web/pkp/sign`; + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.PKP_SIGN, + }); if (!params.authSig) { throw new Error('authSig is required'); } @@ -783,7 +789,10 @@ export class LitNodeClientNodeJs requestId: string ) => { logWithRequestId(requestId, 'getPkpSigningShares'); - const urlWithPath = `${url}/web/pkp/claim`; + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.PKP_CLAIM, + }); if (!params.authMethod) { throw new Error('authMethod is required'); } @@ -810,7 +819,11 @@ export class LitNodeClientNodeJs requestId: string ): Promise => { logWithRequestId(requestId, 'getSigningShareForToken'); - const urlWithPath = `${url}/web/signing/access_control_condition`; + + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.SIGN_ACCS, + }); return this.sendCommandToNode({ url: urlWithPath, @@ -834,7 +847,11 @@ export class LitNodeClientNodeJs requestId: string ): Promise => { log('getSigningShareForDecryption'); - const urlWithPath = `${url}/web/encryption/sign`; + + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.ENCRYPTION_SIGN, + }); return await this.sendCommandToNode({ url: urlWithPath, @@ -862,7 +879,11 @@ export class LitNodeClientNodeJs id: string ): Promise | RejectedNodePromises> => { log('signConditionEcdsa'); - const urlWithPath = `${url}/web/signing/signConditionEcdsa`; + + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.SIGN_ECDSA, + }); const data = { access_control_conditions: params.accessControlConditions, @@ -2693,7 +2714,10 @@ export class LitNodeClientNodeJs requestId: string ) => { log('getSignSessionKeyShares'); - const urlWithPath = `${url}/web/sign_session_key`; + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, + }); return await this.sendCommandToNode({ url: urlWithPath, data: params.body, From f0bcbbf1ba9a336f37989c92f76e45ab005ed10e Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:13:40 +0100 Subject: [PATCH 022/263] chore: pretty pretty pretty lint --- local-tests/setup/tinny-config.ts | 2 +- packages/constants/src/lib/constants/constants.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/local-tests/setup/tinny-config.ts b/local-tests/setup/tinny-config.ts index 1b1dc893d6..c9227ab8ac 100644 --- a/local-tests/setup/tinny-config.ts +++ b/local-tests/setup/tinny-config.ts @@ -91,4 +91,4 @@ export interface TinnyEnvConfig { litNodeClient: LitNodeClient; network: LIT_TESTNET; processEnvs: ProcessEnvs; -} \ No newline at end of file +} diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 6577787e7b..042d6d8c8d 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -789,4 +789,3 @@ export const RELAY_URL_MANZANO = 'https://manzano-relayer.getlit.dev'; // ========== Lit Actions ========== export const LIT_ACTION_IPFS_HASH = 'QmUjX8MW6StQ7NKNdaS6g4RMkvN5hcgtKmEi8Mca6oX4t3'; - From 74d0d67fe8d6bc318c086fc312e91706ed6fd77c Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:13:57 +0100 Subject: [PATCH 023/263] chore: pretty pretty lint --- packages/core/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 63e9e0e404..96715e1682 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,2 +1,2 @@ export * from './lib/lit-core'; -export * from './lib/endpoint-version'; \ No newline at end of file +export * from './lib/endpoint-version'; From 5b7e311397cfaef3732822016c38f75659de4a9c Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:28:03 +0100 Subject: [PATCH 024/263] fix(sessionKey): signed session key mismatch with the one being signed due to storage provider not found --- .../src/lib/lit-node-client-nodejs.ts | 27 ++++++++++++++++++- packages/types/src/lib/interfaces.ts | 5 ++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index be9431ae2b..6d967eaf85 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -107,6 +107,7 @@ import type { WebAuthnAuthenticationVerificationParams, ILitNodeClient, GetPkpSessionSigs, + SessionKeyCache, } from '@lit-protocol/types'; // TODO: move this to auth-helper for next patch @@ -126,6 +127,11 @@ interface CapacityCreditsRes { capacityDelegationAuthSig: AuthSig; } +const TEMP_CACHE_PERIOD = 30000; // 30 seconds + +// Global cache variable +let sessionKeyCache: SessionKeyCache | null = null; + export class LitNodeClientNodeJs extends LitCore implements LitClientSessionManager, ILitNodeClient @@ -385,6 +391,15 @@ export class LitNodeClientNodeJs `Storage key "${storageKey}" is missing. Not a problem. Contiune...` ); + // Check if a valid session key exists in cache + if ( + sessionKeyCache && + Date.now() - sessionKeyCache.timestamp < TEMP_CACHE_PERIOD + ) { + log(`[getSessionKey] Returning session key from cache.`); + return sessionKeyCache.value; + } + // Generate new one const newSessionKey = generateSessionKeyPair(); @@ -392,7 +407,17 @@ export class LitNodeClientNodeJs try { localStorage.setItem(storageKey, JSON.stringify(newSessionKey)); } catch (e) { - console.warn(`Localstorage not available. Not a problem. Contiune...`); + log( + `[getSessionKey] Localstorage not available.Not a problem.Contiune...` + ); + + // Store in cache + sessionKeyCache = { + value: newSessionKey, + timestamp: Date.now(), + }; + + log(`[getSessionKey] newSessionKey set to cache: `, sessionKeyCache); } return newSessionKey; diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 1454ba293b..8f04c5df42 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1612,3 +1612,8 @@ export interface GetPkpSessionSigs extends GetSessionSigsProps { sigName?: string; }; } + +export type SessionKeyCache = { + value: SessionKeyPair; + timestamp: number; +}; \ No newline at end of file From 0813bec20c371ac89b125904b8b56752d28d92a5 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:42:08 +0100 Subject: [PATCH 025/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/438#discussion_r1577978272 --- packages/core/src/lib/endpoint-version.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core/src/lib/endpoint-version.ts b/packages/core/src/lib/endpoint-version.ts index 2fad4b296f..bdf5c87757 100644 --- a/packages/core/src/lib/endpoint-version.ts +++ b/packages/core/src/lib/endpoint-version.ts @@ -3,6 +3,10 @@ import { LitEndpoint } from '@lit-protocol/types'; /** * Compose the Lit URL + * + * The schema of the routing can be found in the `constants` package in the `endpoints.ts` file, where you would be able to add new endpoint to the enum, + * and use that enum in the LIT_ENDPOINT map. + * * @param params * @returns the composed URL */ From 3ccaf38dcbe9a73861435f966f8c02ce17c3b02f Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:43:30 +0100 Subject: [PATCH 026/263] fix: `LEGACY` to `V0` https://github.com/LIT-Protocol/js-sdk/pull/438#discussion_r1577983072 --- .../constants/src/lib/constants/endpoints.ts | 18 +++++++++--------- tools/scripts/tools.mjs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/constants/src/lib/constants/endpoints.ts b/packages/constants/src/lib/constants/endpoints.ts index e123184685..7dd1e36911 100644 --- a/packages/constants/src/lib/constants/endpoints.ts +++ b/packages/constants/src/lib/constants/endpoints.ts @@ -1,12 +1,12 @@ export enum LIT_ENDPOINT_VERSION { - LEGACY = '/', + V0 = '/', V1 = '/v1', } export const LIT_ENDPOINT = { HANDSHAKE: { path: '/web/handshake', - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'HANDSHAKE', }, SIGN_SESSION_KEY: { @@ -14,39 +14,39 @@ export const LIT_ENDPOINT = { // version: LIT_ENDPOINT_VERSION.V1, // FIXME: Change this to V1 once the new version is deployed to all public networks - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'SIGN_SESSION_KEY', }, EXECUTE_JS: { path: '/web/execute', // FIXME: Change this to V1 once the new version is deployed to all public networks - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'EXECUTE_JS', }, PKP_SIGN: { path: '/web/pkp/sign', // version: LIT_ENDPOINT_VERSION.V1, - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'PKP_SIGN', }, PKP_CLAIM: { path: '/web/pkp/claim', - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'PKP_CLAIM', }, SIGN_ACCS: { path: '/web/signing/access_control_condition', - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'SIGN_ACCS', }, ENCRYPTION_SIGN: { path: '/web/encryption/sign', - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'ENCRYPTION_SIGN', }, SIGN_ECDSA: { path: '/web/signing/signConditionEcdsa', - version: LIT_ENDPOINT_VERSION.LEGACY, + version: LIT_ENDPOINT_VERSION.V0, envName: 'SIGN_ECDSA', }, }; diff --git a/tools/scripts/tools.mjs b/tools/scripts/tools.mjs index 40b889ed7f..00e02643a7 100644 --- a/tools/scripts/tools.mjs +++ b/tools/scripts/tools.mjs @@ -1329,7 +1329,7 @@ async function validateDependencyVersions() { ` ❗️ Before publishing, make sure you have tested the build! - yarn test:unit | run unit tests - - yarn test:e2e:node | run e2e tests on nodejs (legacy) + - yarn test:e2e:node | run e2e tests on nodejs (v0) - yarn test:local | run e2e tests on nodejs `, true From 1ff14502c398bb0878a06a77aefc471ae27ad516 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:44:07 +0100 Subject: [PATCH 027/263] fix: change `null` to `undefined` https://github.com/LIT-Protocol/js-sdk/pull/438#discussion_r1577985746 --- packages/core/src/lib/endpoint-version.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/lib/endpoint-version.ts b/packages/core/src/lib/endpoint-version.ts index bdf5c87757..f2d1381b79 100644 --- a/packages/core/src/lib/endpoint-version.ts +++ b/packages/core/src/lib/endpoint-version.ts @@ -21,12 +21,12 @@ export const composeLitUrl = (params: { throw new Error(`[composeLitUrl] Invalid URL: "${params.url}"`); } - let versionOverride: string | null = null; + let versionOverride: string | undefined = undefined; // Get the version override for a particular endpoint // FIXME: We will remove this completly once v0.1 is deployed to all public networks if (isNode()) { - versionOverride = process.env[`${params.endpoint.envName}`] || null; + versionOverride = process.env[`${params.endpoint.envName}`] || undefined; } // Use the overridden version if it exists, otherwise use the default From 4344d6af189b9b4fd53a84b2365b24ccc8cc74b0 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 15:45:21 +0100 Subject: [PATCH 028/263] chore: pretty pretty lint --- packages/types/src/lib/interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 8f04c5df42..5e178beed5 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1616,4 +1616,4 @@ export interface GetPkpSessionSigs extends GetSessionSigsProps { export type SessionKeyCache = { value: SessionKeyPair; timestamp: number; -}; \ No newline at end of file +}; From 72bcd8d6485bf7a9dfe12c1a4e9e1a177841d9e4 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 16:00:08 +0100 Subject: [PATCH 029/263] feat(accs): added compose lit action resource string helper function --- packages/auth-helpers/src/lib/resources.ts | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/auth-helpers/src/lib/resources.ts b/packages/auth-helpers/src/lib/resources.ts index dee4c794fa..cda889d7ee 100644 --- a/packages/auth-helpers/src/lib/resources.ts +++ b/packages/auth-helpers/src/lib/resources.ts @@ -1,8 +1,11 @@ import { + AccessControlConditions, ILitResource, LitAbility, LitResourcePrefix, } from '@lit-protocol/types'; +import { hashAccessControlConditions } from '@lit-protocol/access-control-conditions'; +import { uint8arrayToString } from '@lit-protocol/uint8arrays'; abstract class LitResourceBase { abstract resourcePrefix: LitResourcePrefix; @@ -42,6 +45,34 @@ export class LitAccessControlConditionResource litAbility === LitAbility.AccessControlConditionSigning ); } + + /** + * Composes a resource string by hashing access control conditions and appending a data hash. + * + * @param {AccessControlConditions} accs - The access control conditions to hash. + * @param {string} dataToEncryptHash - The hash of the data to encrypt. + * @returns {Promise} The composed resource string in the format 'hashedAccs/dataToEncryptHash'. + */ + public static async composeLitActionResourceString( + accs: AccessControlConditions, + dataToEncryptHash: string + ): Promise { + if (!accs || !dataToEncryptHash) { + throw new Error( + 'Invalid input: Access control conditions and data hash are required.' + ); + } + + const hashedAccs = await hashAccessControlConditions(accs); + const hashedAccsStr = uint8arrayToString( + new Uint8Array(hashedAccs), + 'base16' + ); + + const resourceString = `${hashedAccsStr}/${dataToEncryptHash}`; + + return resourceString; + } } export class LitPKPResource extends LitResourceBase implements ILitResource { From fe71ddfba4c9701c513bb649a4e53af45ea66bd8 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 16:00:28 +0100 Subject: [PATCH 030/263] feat(types): better interfaces --- packages/types/src/lib/interfaces.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 1eb5295bce..8ffafc8abd 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -226,7 +226,7 @@ export interface BaseJsonExecutionRequest { // authSig?: AuthSig; // An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. - jsParams: any; + jsParams?: any; // JS code to run on the nodes code?: string; @@ -530,7 +530,19 @@ export interface SignConditionECDSA { * */ export interface ExecuteJsResponse { - signatures: any; + success?: boolean; + signatures: + | { + sig: { + r: string; + s: string; + recid: number; + signature: string; // 0x... + publicKey: string; // pkp public key + dataSigned: string; + }; + } + | any; decryptions: any[]; response: string; logs: string; From 430abb7f8b841a21823d1248ebd52cf0dfed3660 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 16:00:58 +0100 Subject: [PATCH 031/263] feat(test): add new e2e tests --- local-tests/test.ts | 103 +++++++++- ...pacityCreditsNFTToAnotherPkpToExecuteJs.ts | 128 +++++++++++++ ...ityCreditsNFTToAnotherWalletToExecuteJs.ts | 116 +++++++++++ ...acityCreditsNFTToAnotherWalletToPkpSign.ts | 98 ++++++++++ ...thUnspecifiedCapacityTokenIdToExecuteJs.ts | 120 ++++++++++++ ...WithUnspecifiedCapacityTokenIdToPkpSign.ts | 100 ++++++++++ ...SigWithUnspecifiedDelegateesToExecuteJs.ts | 118 ++++++++++++ ...thSigWithUnspecifiedDelegateesToPkpSign.ts | 94 +++++++++ ...stUseEoaSessionSigsToEncryptDecryptFile.ts | 96 ++++++++++ ...UseEoaSessionSigsToEncryptDecryptString.ts | 89 +++++++++ ...estUseEoaSessionSigsToEncryptDecryptZip.ts | 91 +++++++++ ...stUseEoaSessionSigsToExecuteJsClaimKeys.ts | 181 ++++++++++++++++++ ...SessionSigsToExecuteJsClaimMultipleKeys.ts | 105 ++++++++++ ...tUseEoaSessionSigsToExecuteJsConsoleLog.ts | 54 ++++++ ...seEoaSessionSigsToExecuteJsJsonResponse.ts | 69 +++++++ ...testUseEoaSessionSigsToExecuteJsSigning.ts | 66 +++++++ ...SessionSigsToExecuteJsSigningInParallel.ts | 121 ++++++++++++ .../tests/testUseEoaSessionSigsToPkpSign.ts | 62 ++++++ ...validLitActionCodeToGenerateSessionSigs.ts | 32 ++++ ...stUsePkpSessionSigsToEncryptDecryptFile.ts | 97 ++++++++++ ...UsePkpSessionSigsToEncryptDecryptString.ts | 83 ++++++++ ...estUsePkpSessionSigsToEncryptDecryptZip.ts | 92 +++++++++ ...stUsePkpSessionSigsToExecuteJsClaimKeys.ts | 170 ++++++++++++++++ ...SessionSigsToExecuteJsClaimMultipleKeys.ts | 104 ++++++++++ ...tUsePkpSessionSigsToExecuteJsConsoleLog.ts | 52 +++++ ...sePkpSessionSigsToExecuteJsJsonResponse.ts | 69 +++++++ ...testUsePkpSessionSigsToExecuteJsSigning.ts | 80 ++++++++ ...SessionSigsToExecuteJsSigningInParallel.ts | 121 ++++++++++++ .../tests/testUsePkpSessionSigsToPkpSign.ts | 60 ++++++ ...eneratedSessionSigsToEncryptDecryptFile.ts | 99 ++++++++++ ...eratedSessionSigsToEncryptDecryptString.ts | 87 +++++++++ ...GeneratedSessionSigsToEncryptDecryptZip.ts | 94 +++++++++ ...eneratedSessionSigsToExecuteJsClaimKeys.ts | 116 +++++++++++ ...SessionSigsToExecuteJsClaimMultipleKeys.ts | 106 ++++++++++ ...neratedSessionSigsToExecuteJsConsoleLog.ts | 67 +++++++ ...ratedSessionSigsToExecuteJsJsonResponse.ts | 70 +++++++ ...eGeneratedSessionSigsToExecuteJsSigning.ts | 82 ++++++++ ...SessionSigsToExecuteJsSigningInParallel.ts | 123 ++++++++++++ ...ActionCodeGeneratedSessionSigsToPkpSign.ts | 67 +++++++ 39 files changed, 3677 insertions(+), 5 deletions(-) create mode 100644 local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts create mode 100644 local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts create mode 100644 local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts create mode 100644 local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts create mode 100644 local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts create mode 100644 local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts create mode 100644 local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToExecuteJsConsoleLog.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToExecuteJsSigning.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts create mode 100644 local-tests/tests/testUseEoaSessionSigsToPkpSign.ts create mode 100644 local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts create mode 100644 local-tests/tests/testUsePkpSessionSigsToPkpSign.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts create mode 100644 local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts diff --git a/local-tests/test.ts b/local-tests/test.ts index bfc0bcf724..24afa4b0f2 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -1,8 +1,47 @@ -import { LIT_ENDPOINT_VERSION, LIT_TESTNET } from './setup/tinny-config'; +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from './setup/tinny-config'; import { TinnyEnvironment } from './setup/tinny-environment'; import { runInBand, runTestsParallel } from './setup/tinny-operations'; -import { testBundleSpeed } from './tests/test-bundle-speed'; -import { testExample } from './tests/test-example'; +// import { testBundleSpeed } from './tests/test-bundle-speed'; +// import { testExample } from './tests/test-example'; +import { testUseEoaSessionSigsToExecuteJsSigning } from './tests/testUseEoaSessionSigsToExecuteJsSigning'; +import { testUseEoaSessionSigsToPkpSign } from './tests/testUseEoaSessionSigsToPkpSign'; +import { testUsePkpSessionSigsToExecuteJsSigning } from './tests/testUsePkpSessionSigsToExecuteJsSigning'; +import { testUsePkpSessionSigsToPkpSign } from './tests/testUsePkpSessionSigsToPkpSign'; +import { testUseValidLitActionCodeGeneratedSessionSigsToPkpSign } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign'; +import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning'; +import { testUseEoaSessionSigsToExecuteJsSigningInParallel } from './tests/testUseEoaSessionSigsToExecuteJsSigningInParallel'; +import { testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs } from './tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs'; +import { testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign } from './tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign'; +import { testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign } from './tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign'; +import { testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs } from './tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs'; +import { testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign } from './tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign'; +import { testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs } from './tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs'; +import { testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs } from './tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs'; +import { testUseEoaSessionSigsToExecuteJsClaimKeys } from './tests/testUseEoaSessionSigsToExecuteJsClaimKeys'; +import { testUseEoaSessionSigsToExecuteJsClaimMultipleKeys } from './tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys'; +import { testUseEoaSessionSigsToExecuteJsJsonResponse } from './tests/testUseEoaSessionSigsToExecuteJsJsonResponse'; +import { testUseEoaSessionSigsToExecuteJsConsoleLog } from './tests/testUseEoaSessionSigsToExecuteJsConsoleLog'; +import { testUseEoaSessionSigsToEncryptDecryptString } from './tests/testUseEoaSessionSigsToEncryptDecryptString'; +import { testUsePkpSessionSigsToEncryptDecryptString } from './tests/testUsePkpSessionSigsToEncryptDecryptString'; +import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString'; +import { testUseInvalidLitActionCodeToGenerateSessionSigs } from './tests/testUseInvalidLitActionCodeToGenerateSessionSigs'; +import { testUseEoaSessionSigsToEncryptDecryptFile } from './tests/testUseEoaSessionSigsToEncryptDecryptFile'; +import { testUseEoaSessionSigsToEncryptDecryptZip } from './tests/testUseEoaSessionSigsToEncryptDecryptZip'; +import { testUsePkpSessionSigsToExecuteJsSigningInParallel } from './tests/testUsePkpSessionSigsToExecuteJsSigningInParallel'; +import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel'; +import { testUsePkpSessionSigsToExecuteJsClaimKeys } from './tests/testUsePkpSessionSigsToExecuteJsClaimKeys'; +import { testUsePkpSessionSigsToExecuteJsClaimMultipleKeys } from './tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys'; +import { testUsePkpSessionSigsToExecuteJsJsonResponse } from './tests/testUsePkpSessionSigsToExecuteJsJsonResponse'; +import { testUsePkpSessionSigsToExecuteJsConsoleLog } from './tests/testUsePkpSessionSigsToExecuteJsConsoleLog'; +import { testUsePkpSessionSigsToEncryptDecryptFile } from './tests/testUsePkpSessionSigsToEncryptDecryptFile'; +import { testUsePkpSessionSigsToEncryptDecryptZip } from './tests/testUsePkpSessionSigsToEncryptDecryptZip'; +import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys'; +import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys'; +import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse'; +import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog'; +import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile'; +import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -23,10 +62,64 @@ import { testExample } from './tests/test-example'; ); } + const eoaSessionSigsTests = { + testUseEoaSessionSigsToExecuteJsSigning, + testUseEoaSessionSigsToPkpSign, + testUseEoaSessionSigsToExecuteJsSigningInParallel, + testUseEoaSessionSigsToExecuteJsClaimKeys, + testUseEoaSessionSigsToExecuteJsClaimMultipleKeys, + testUseEoaSessionSigsToExecuteJsJsonResponse, + testUseEoaSessionSigsToExecuteJsConsoleLog, + testUseEoaSessionSigsToEncryptDecryptString, + testUseEoaSessionSigsToEncryptDecryptFile, + testUseEoaSessionSigsToEncryptDecryptZip, + }; + + const pkpSessionSigsTests = { + testUsePkpSessionSigsToExecuteJsSigning, + testUsePkpSessionSigsToPkpSign, + testUsePkpSessionSigsToExecuteJsSigningInParallel, + testUsePkpSessionSigsToExecuteJsClaimKeys, + testUsePkpSessionSigsToExecuteJsClaimMultipleKeys, + testUsePkpSessionSigsToExecuteJsJsonResponse, + testUsePkpSessionSigsToExecuteJsConsoleLog, + testUsePkpSessionSigsToEncryptDecryptString, + testUsePkpSessionSigsToEncryptDecryptFile, + testUsePkpSessionSigsToEncryptDecryptZip, + }; + + const litActionSessionSigsTests = { + testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning, + testUseValidLitActionCodeGeneratedSessionSigsToPkpSign, + testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel, + testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys, + testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys, + testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse, + testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog, + testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString, + testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile, + testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip, + testUseInvalidLitActionCodeToGenerateSessionSigs, + }; + + const capacityDelegationTests = { + testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs, + testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign, + testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs, + testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs, + testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign, + testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs, + testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign, + }; + const testConfig = { tests: { - testExample, - testBundleSpeed, + // testExample, + // testBundleSpeed, + ...eoaSessionSigsTests, + ...pkpSessionSigsTests, + ...litActionSessionSigsTests, + ...capacityDelegationTests, }, devEnv, }; diff --git a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts new file mode 100644 index 0000000000..f8de798aa5 --- /dev/null +++ b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts @@ -0,0 +1,128 @@ +import { + AuthMethodScope, + AuthMethodType, + LIT_ENDPOINT_VERSION, +} from '@lit-protocol/constants'; +import { LitAuthClient } from '@lit-protocol/lit-auth-client'; +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LitAbility } from '@lit-protocol/types'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; + +/** + * ## Scenario: + * Delegating capacity credits NFT to Bob (delegatee) for him to execute JS code to sign with his PKP + * - Given: The capacity credits NFT is minted by the dApp owner + * - When: The dApp owner creates a capacity delegation authSig + * - And: The dApp owner delegates the capacity credits NFT to Bob + * - Then: The delegated (Bob's) wallet can execute JS code to sign with his PKP using the capacity from the capacity credits NFT + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne + * - ✅ NETWORK=manzano yarn test:local --filter=testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs + * - ✅ NETWORK=localchain yarn test:local --filter=testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs + */ +export const testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs = async ( + devEnv: TinnyEnvironment +) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + // Checking the scopes of the PKP owned by Bob + const bobsAuthMethodAuthId = await LitAuthClient.getAuthIdByAuthMethod( + bob.authMethod + ); + + const scopes = + await bob.contractsClient.pkpPermissionsContract.read.getPermittedAuthMethodScopes( + bob.authMethodOwnedPkp.tokenId, + AuthMethodType.EthWallet, + bobsAuthMethodAuthId, + 3 + ); + + if (!scopes[AuthMethodScope.SignAnything]) { + throw new Error('Bob does not have the "SignAnything" scope on his PKP'); + } + + // As a dApp owner, create a capacity delegation authSig for Bob's PKP wallet + const capacityDelegationAuthSig = await alice.createCapacityDelegationAuthSig( + [bob.pkp.ethAddress] + ); + + // As a dApp owner, delegate the capacity credits NFT to Bob + const bobPkpSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: bob.authMethodOwnedPkp.publicKey, + authMethods: [bob.authMethod], + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ], + capabilityAuthSigs: [capacityDelegationAuthSig], + }); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: bobPkpSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: bob.authMethodOwnedPkp.publicKey, + }, + }); + + console.log('✅ res:', res); + + // -- Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "00fdf6f2fc3f13410393939bb678c8ec26c0eb46bfc39dbecdcf58540b7f9237", + // s: "480b578c78137150db2420669c47b220001b42a0bb4e92194ce7b76f6fd78ddc", + // recid: 0, + // signature: "0x00fdf6f2fc3f13410393939bb678c8ec26c0eb46bfc39dbecdcf58540b7f9237480b578c78137150db2420669c47b220001b42a0bb4e92194ce7b76f6fd78ddc1b", + // publicKey: "0465BFEE5CCFF60C0AF1D9B9481B680C2E34894A88F68F44CC094BA27501FD062A3C4AC61FA850BFA22D81D41AF72CBF983909501440FE51187F5FB3D1BC55C44E", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!res.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } +}; diff --git a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts new file mode 100644 index 0000000000..b3b7bc0a15 --- /dev/null +++ b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts @@ -0,0 +1,116 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigsWithCapacityDelegations } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Delegating capacity credits NFT to Bob (delegatee) for him to execute JS code to sign with his PKP + * - Given: The capacity credits NFT is minted by the dApp owner + * - When: The dApp owner creates a capacity delegation authSig + * - And: The dApp owner delegates the capacity credits NFT to Bob + * - Then: The delegated (Bob's) wallet can execute JS code to sign with his PKP using the capacity from the capacity credits NFT + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne, but session sigs would still work + * - ✅ NETWORK=manzano yarn test:local --filter=testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs + * - ✅ NETWORK=localchain yarn test:local --filter=testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs + */ +export const testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + const appOwnersCapacityDelegationAuthSig = + await alice.createCapacityDelegationAuthSig([bob.wallet.address]); + + // 4. Bob receives the capacity delegation authSig use it to generate session sigs + const bobsSessionSigs = await getEoaSessionSigsWithCapacityDelegations( + devEnv, + bob.wallet, + appOwnersCapacityDelegationAuthSig + ); + + // -- printing out the recaps from the session sigs + const bobsSingleSessionSig = + bobsSessionSigs[devEnv.litNodeClient.config.bootstrapUrls[0]]; + + console.log('bobsSingleSessionSig:', bobsSingleSessionSig); + + const regex = /urn:recap:[\w+\/=]+/g; + + const recaps = bobsSingleSessionSig.signedMessage.match(regex) || []; + + recaps.forEach((r) => { + const encodedRecap = r.split(':')[2]; + const decodedRecap = Buffer.from(encodedRecap, 'base64').toString(); + console.log(decodedRecap); + }); + + // 5. Bob can now execute JS code using the capacity credits NFT + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: bobsSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: bob.pkp.publicKey, + }, + }); + + // Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "0f4b8b20369a8a021aae7c2083076715820e32d2b18826ea7ccea525a9adadc2", + // s: "43aa338fa2c90e13c88d9b432d7ee6c8e3df006b8ef94ad5b4ab32d64b507f17", + // recid: 1, + // signature: "0x0f4b8b20369a8a021aae7c2083076715820e32d2b18826ea7ccea525a9adadc243aa338fa2c90e13c88d9b432d7ee6c8e3df006b8ef94ad5b4ab32d64b507f171c", + // publicKey: "0406A76D2A6E3E729A537640C8C41592BBC2675799CCBBF310CD410691C028C529C5A8DE8016933CEC0B06EC7AA0FFAFBA2791158A11D382C558376DF392F436AD", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!res.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(res.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + console.log( + '✅ testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs' + ); + }; diff --git a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts new file mode 100644 index 0000000000..00b0f4984b --- /dev/null +++ b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts @@ -0,0 +1,98 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigsWithCapacityDelegations } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Delegating capacity credits NFT to Bob (delegatee) for him to execute JS code to sign with his PKP + * - Given: The capacity credits NFT is minted by the dApp owner + * - When: The dApp owner creates a capacity delegation authSig + * - And: The dApp owner delegates the capacity credits NFT to Bob + * - Then: The delegated (Bob's) wallet can execute JS code to sign with his PKP using the capacity from the capacity credits NFT + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne, but session sigs would still work + * - ✅ NETWORK=manzano yarn test:local --filter=testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign + * - ✅ NETWORK=localchain yarn test:local --filter=testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign + */ +export const testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign = async ( + devEnv: TinnyEnvironment +) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + const appOwnersCapacityDelegationAuthSig = + await alice.createCapacityDelegationAuthSig([bob.wallet.address]); + + // 4. Bob receives the capacity delegation authSig use it to generate session sigs + const bobsSessionSigs = await getEoaSessionSigsWithCapacityDelegations( + devEnv, + bob.wallet, + appOwnersCapacityDelegationAuthSig + ); + + // -- printing out the recaps from the session sigs + const bobsSingleSessionSig = + bobsSessionSigs[devEnv.litNodeClient.config.bootstrapUrls[0]]; + + console.log('bobsSingleSessionSig:', bobsSingleSessionSig); + + const regex = /urn:recap:[\w+\/=]+/g; + + const recaps = bobsSingleSessionSig.signedMessage.match(regex) || []; + + recaps.forEach((r) => { + const encodedRecap = r.split(':')[2]; + const decodedRecap = Buffer.from(encodedRecap, 'base64').toString(); + console.log(decodedRecap); + }); + + // 5. Bob can now execute JS code using the capacity credits NFT + const res = await devEnv.litNodeClient.pkpSign({ + sessionSigs: bobsSessionSigs, + toSign: alice.loveLetter, + pubKey: bob.pkp.publicKey, + }); + + // -- Expected output: + // { + // r: "25e04b2abdf220b1374b19228bc292bab71a3224a635726a46d4cbe3a62bb636", + // s: "1e5d96ffa6ec7cca961ec7bfa90e524a08b1c4fc9a833b69d8727eff1453064c", + // recid: 0, + // signature: "0x25e04b2abdf220b1374b19228bc292bab71a3224a635726a46d4cbe3a62bb6361e5d96ffa6ec7cca961ec7bfa90e524a08b1c4fc9a833b69d8727eff1453064c1b", + // publicKey: "041FF0DC7B69D2B3C3E452AF9E0D30C7FDA6729A1B394059BDC8C4530D7F584FFCAEEEC19B1F22EFB054A22E5EF13AA0B5804994469570929066F5474D490B8A1F", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + if (!res.r) { + throw new Error(`Expected "r" in res`); + } + if (!res.s) { + throw new Error(`Expected "s" in res`); + } + + if (!res.dataSigned) { + throw new Error(`Expected "dataSigned" in res`); + } + + if (!res.publicKey) { + throw new Error(`Expected "publicKey" in res`); + } + + // -- signature must start with 0x + if (!res.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- recid must be parseable as a number + if (isNaN(res.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + console.log('✅ res:', res); +}; diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts new file mode 100644 index 0000000000..16c45d1590 --- /dev/null +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts @@ -0,0 +1,120 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigsWithCapacityDelegations } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing unrestricted access to execute js code using a capacity delegation authSig without specific delegatee restrictions + * - Given: A capacity delegation authSig is created by the dApp owner + * - When: The authSig does not specifically restrict delegatees + * - And: Any user attempts to execute js code using the capacity from the capacity credits NFT + * - Then: The user should be able to sign with his/her PKP using the capacity without restrictions due to the absence of delegatee limits + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne, but session sigs would still work + * - ✅ NETWORK=manzano yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs + * - ✅ NETWORK=localchain yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs + */ +export const testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + const appOwnersCapacityDelegationAuthSig = ( + await devEnv.litNodeClient.createCapacityDelegationAuthSig({ + dAppOwnerWallet: alice.wallet, + }) + ).capacityDelegationAuthSig; + + // 3. Bob gets the capacity delegation authSig from somewhere and uses it to get session sigs + const bobsSessionSigs = await getEoaSessionSigsWithCapacityDelegations( + devEnv, + bob.wallet, + appOwnersCapacityDelegationAuthSig + ); + + // -- printing out the recaps from the session sigs + const bobsSingleSessionSig = + bobsSessionSigs[devEnv.litNodeClient.config.bootstrapUrls[0]]; + + console.log('bobsSingleSessionSig:', bobsSingleSessionSig); + + const regex = /urn:recap:[\w+\/=]+/g; + + const recaps = bobsSingleSessionSig.signedMessage.match(regex) || []; + + recaps.forEach((r) => { + const encodedRecap = r.split(':')[2]; + const decodedRecap = Buffer.from(encodedRecap, 'base64').toString(); + console.log(decodedRecap); + }); + + // 4. Bob can now execute JS code using the capacity credits NFT + // 5. Bob can now execute JS code using the capacity credits NFT + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: bobsSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: bob.pkp.publicKey, + }, + }); + + // Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "0f4b8b20369a8a021aae7c2083076715820e32d2b18826ea7ccea525a9adadc2", + // s: "43aa338fa2c90e13c88d9b432d7ee6c8e3df006b8ef94ad5b4ab32d64b507f17", + // recid: 1, + // signature: "0x0f4b8b20369a8a021aae7c2083076715820e32d2b18826ea7ccea525a9adadc243aa338fa2c90e13c88d9b432d7ee6c8e3df006b8ef94ad5b4ab32d64b507f171c", + // publicKey: "0406A76D2A6E3E729A537640C8C41592BBC2675799CCBBF310CD410691C028C529C5A8DE8016933CEC0B06EC7AA0FFAFBA2791158A11D382C558376DF392F436AD", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!res.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(res.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + console.log( + '✅ testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs' + ); + }; diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts new file mode 100644 index 0000000000..4abccce37e --- /dev/null +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts @@ -0,0 +1,100 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigsWithCapacityDelegations } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing unrestricted access to pkp sign using a capacity delegation authSig without specific delegatee restrictions + * - Given: A capacity delegation authSig is created by the dApp owner + * - When: The authSig does not specifically restrict delegatees + * - And: Any user attempts to pkp sign using the capacity from the capacity credits NFT + * - Then: The user should be able to sign with his/her PKP using the capacity without restrictions due to the absence of delegatee limits + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne, but session sigs would still work + * - ✅ NETWORK=manzano yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign + * - ✅ NETWORK=localchain yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign + */ +export const testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + const appOwnersCapacityDelegationAuthSig = ( + await devEnv.litNodeClient.createCapacityDelegationAuthSig({ + dAppOwnerWallet: alice.wallet, + }) + ).capacityDelegationAuthSig; + + // 3. Bob gets the capacity delegation authSig from somewhere and uses it to get session sigs + const bobsSessionSigs = await getEoaSessionSigsWithCapacityDelegations( + devEnv, + bob.wallet, + appOwnersCapacityDelegationAuthSig + ); + + // -- printing out the recaps from the session sigs + const bobsSingleSessionSig = + bobsSessionSigs[devEnv.litNodeClient.config.bootstrapUrls[0]]; + + console.log('bobsSingleSessionSig:', bobsSingleSessionSig); + + const regex = /urn:recap:[\w+\/=]+/g; + + const recaps = bobsSingleSessionSig.signedMessage.match(regex) || []; + + recaps.forEach((r) => { + const encodedRecap = r.split(':')[2]; + const decodedRecap = Buffer.from(encodedRecap, 'base64').toString(); + console.log(decodedRecap); + }); + + // 4. Bob can now execute JS code using the capacity credits NFT + const res = await devEnv.litNodeClient.pkpSign({ + sessionSigs: bobsSessionSigs, + toSign: alice.loveLetter, + pubKey: bob.pkp.publicKey, + }); + + // -- Expected output: + // { + // r: "25e04b2abdf220b1374b19228bc292bab71a3224a635726a46d4cbe3a62bb636", + // s: "1e5d96ffa6ec7cca961ec7bfa90e524a08b1c4fc9a833b69d8727eff1453064c", + // recid: 0, + // signature: "0x25e04b2abdf220b1374b19228bc292bab71a3224a635726a46d4cbe3a62bb6361e5d96ffa6ec7cca961ec7bfa90e524a08b1c4fc9a833b69d8727eff1453064c1b", + // publicKey: "041FF0DC7B69D2B3C3E452AF9E0D30C7FDA6729A1B394059BDC8C4530D7F584FFCAEEEC19B1F22EFB054A22E5EF13AA0B5804994469570929066F5474D490B8A1F", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + if (!res.r) { + throw new Error(`Expected "r" in res`); + } + if (!res.s) { + throw new Error(`Expected "s" in res`); + } + + if (!res.dataSigned) { + throw new Error(`Expected "dataSigned" in res`); + } + + if (!res.publicKey) { + throw new Error(`Expected "publicKey" in res`); + } + + // -- signature must start with 0x + if (!res.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- recid must be parseable as a number + if (isNaN(res.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + console.log('✅ res:', res); + }; diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts new file mode 100644 index 0000000000..f98f9e7592 --- /dev/null +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts @@ -0,0 +1,118 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigsWithCapacityDelegations } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing unrestricted access to execute JS code using a capacity delegation authSig without specific delegatee restrictions + * - Given: A capacity delegation authSig is created by the dApp owner + * - When: The authSig does not specifically restrict delegatees + * - And: Any user attempts to execute JS code using the capacity from the capacity credits NFT + * - Then: The user should be able to execute the JS code using the capacity without restrictions due to the absence of delegatee limits + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne, but session sigs would still work + * - ✅ NETWORK=manzano yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs + * - ✅ NETWORK=localchain yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs + */ + +export const testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + // No delegatee addresses provided. It means that the capability will not restrict access based on delegatee list, but it may still enforce other restrictions such as usage limits and specific NFT IDs. + const appOwnersCapacityDelegationAuthSig = + await alice.createCapacityDelegationAuthSig(); + + // 4. Bob gets the capacity delegation authSig from somewhere and uses it to get session sigs + const bobsSessionSigs = await getEoaSessionSigsWithCapacityDelegations( + devEnv, + bob.wallet, + appOwnersCapacityDelegationAuthSig + ); + + // -- printing out the recaps from the session sigs + const bobsSingleSessionSig = + bobsSessionSigs[devEnv.litNodeClient.config.bootstrapUrls[0]]; + + console.log('bobsSingleSessionSig:', bobsSingleSessionSig); + + const regex = /urn:recap:[\w+\/=]+/g; + + const recaps = bobsSingleSessionSig.signedMessage.match(regex) || []; + + recaps.forEach((r) => { + const encodedRecap = r.split(':')[2]; + const decodedRecap = Buffer.from(encodedRecap, 'base64').toString(); + console.log(decodedRecap); + }); + + // 5. Bob can now execute JS code using the capacity credits NFT + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: bobsSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: bob.pkp.publicKey, + }, + }); + + // Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "0f4b8b20369a8a021aae7c2083076715820e32d2b18826ea7ccea525a9adadc2", + // s: "43aa338fa2c90e13c88d9b432d7ee6c8e3df006b8ef94ad5b4ab32d64b507f17", + // recid: 1, + // signature: "0x0f4b8b20369a8a021aae7c2083076715820e32d2b18826ea7ccea525a9adadc243aa338fa2c90e13c88d9b432d7ee6c8e3df006b8ef94ad5b4ab32d64b507f171c", + // publicKey: "0406A76D2A6E3E729A537640C8C41592BBC2675799CCBBF310CD410691C028C529C5A8DE8016933CEC0B06EC7AA0FFAFBA2791158A11D382C558376DF392F436AD", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!res.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(res.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + console.log( + '✅ testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs' + ); + }; diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts new file mode 100644 index 0000000000..77f3700308 --- /dev/null +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts @@ -0,0 +1,94 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigsWithCapacityDelegations } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing unrestricted access to pkp sign code using a capacity delegation authSig without specific delegatee restrictions + * - Given: A capacity delegation authSig is created by the dApp owner + * - When: The authSig does not specifically restrict delegatees + * - And: Any user attempts to pkp sign code using the capacity from the capacity credits NFT + * - Then: The user should be able to execute the JS code using the capacity without restrictions due to the absence of delegatee limits + * + * + * ## Test Commands: + * - ❌ Not supported in Cayenne, but session sigs would still work + * - ✅ NETWORK=manzano yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign + * - ✅ NETWORK=localchain yarn test:local --filter=testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign + */ + +export const testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + const alice = await devEnv.createRandomPerson(); + const bob = await devEnv.createRandomPerson(); + + const appOwnersCapacityDelegationAuthSig = + await alice.createCapacityDelegationAuthSig(); + + // 4. Bob gets the capacity delegation authSig from somewhere and uses it to get session sigs + const bobsSessionSigs = await getEoaSessionSigsWithCapacityDelegations( + devEnv, + bob.wallet, + appOwnersCapacityDelegationAuthSig + ); + + // -- printing out the recaps from the session sigs + const bobsSingleSessionSig = + bobsSessionSigs[devEnv.litNodeClient.config.bootstrapUrls[0]]; + + console.log('bobsSingleSessionSig:', bobsSingleSessionSig); + + const regex = /urn:recap:[\w+\/=]+/g; + + const recaps = bobsSingleSessionSig.signedMessage.match(regex) || []; + + recaps.forEach((r) => { + const encodedRecap = r.split(':')[2]; + const decodedRecap = Buffer.from(encodedRecap, 'base64').toString(); + console.log(decodedRecap); + }); + + // 5. Bob can now pkp sign using the capacity credits NFT + const runWithSessionSigs = await devEnv.litNodeClient.pkpSign({ + toSign: alice.loveLetter, + pubKey: bob.pkp.publicKey, + sessionSigs: bobsSessionSigs, + }); + + // -- Expected output: + // { + // r: "36bd0039b4e4d1dae488a63437318790df86b8023ac4ffa842c8983245b7f629", + // s: "29135af930c40ee0901a9ea3ca5621d06a6b932aee2f2256cf2a99a65cb36d05", + // recid: 1, + // signature: "0x36bd0039b4e4d1dae488a63437318790df86b8023ac4ffa842c8983245b7f62929135af930c40ee0901a9ea3ca5621d06a6b932aee2f2256cf2a99a65cb36d051c", + // publicKey: "04837486BD4DCF221D463D976E6A392E12BC2DFEFB124E189AB0A8EA406DFB1C73F4DCD268CC2B8F854C202256BD08E22D688121061EA9CFB1317142DBD2EAB4C4", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + // r, s, dataSigned, and public key should be present + if (!runWithSessionSigs.r) { + throw new Error(`Expected "r" in runWithSessionSigs`); + } + if (!runWithSessionSigs.s) { + throw new Error(`Expected "s" in runWithSessionSigs`); + } + if (!runWithSessionSigs.dataSigned) { + throw new Error(`Expected "dataSigned" in runWithSessionSigs`); + } + if (!runWithSessionSigs.publicKey) { + throw new Error(`Expected "publicKey" in runWithSessionSigs`); + } + + // signature must start with 0x + if (!runWithSessionSigs.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // recid must be parseable as a number + if (isNaN(runWithSessionSigs.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + }; diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts new file mode 100644 index 0000000000..57af5ec840 --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts @@ -0,0 +1,96 @@ +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptFile + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptFile + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptFile + */ +export const testUseEoaSessionSigsToEncryptDecryptFile = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const message = 'Hello world'; + const blob = new Blob([message], { type: 'text/plain' }); + const blobArray = new Uint8Array(await blob.arrayBuffer()); + + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.wallet.address, + }); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: eoaSessionSigs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const eoaSessionSigs2 = await getEoaSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decriptedFile = await LitJsSdk.decryptToFile( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: eoaSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (blobArray.length !== decriptedFile.length) { + throw new Error( + `decrypted file should match the original file but received ${decriptedFile}` + ); + } + for (let i = 0; i < blobArray.length; i++) { + if (blobArray[i] !== decriptedFile[i]) { + throw new Error(`decrypted file should match the original file`); + } + } + + console.log('decriptedFile:', decriptedFile); +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts new file mode 100644 index 0000000000..a79276ac4a --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts @@ -0,0 +1,89 @@ +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptString + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptString + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptString + */ +export const testUseEoaSessionSigsToEncryptDecryptString = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.wallet.address, + }); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: eoaSessionSigs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const eoaSessionSigs2 = await getEoaSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decryptRes = await LitJsSdk.decryptToString( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: eoaSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (decryptRes !== 'Hello world') { + + throw new Error( + `Expected decryptRes to be 'Hello world' but got ${decryptRes}` + ); + } + +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts new file mode 100644 index 0000000000..de5dff56c7 --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts @@ -0,0 +1,91 @@ +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptZip + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptZip + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToEncryptDecryptZip + */ +export const testUseEoaSessionSigsToEncryptDecryptZip = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const message = 'Hello world'; + + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.wallet.address, + }); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.zipAndEncryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: eoaSessionSigs, + dataToEncrypt: message, + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const eoaSessionSigs2 = await getEoaSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decryptedZip = await LitJsSdk.decryptToZip( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: eoaSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + const decryptedMessage = await decryptedZip['string.txt'].async('string'); + + if (message !== decryptedMessage) { + throw new Error( + `decryptedMessage should be ${message} but received ${decryptedMessage}` + ); + } + + console.log('decryptedMessage:', decryptedMessage); +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts new file mode 100644 index 0000000000..78cdb6b6f2 --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts @@ -0,0 +1,181 @@ +// import { LitContracts } from '@lit-protocol/contracts-sdk'; +// import { log } from '@lit-protocol/misc'; +// import { +// ClaimRequest, +// ClaimResult, +// ClientClaimProcessor, +// } from '@lit-protocol/types'; +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * ## Scenario: + * Testing the capability to claim keys using EOA (Externally Owned Account) session sigs. This test ensures that keys can be claimed correctly. + * + * - Given: EOA sessionSigs are properly generated for the environment. + * - When: These sessionSigs are used to execute JS code within Lit Action. + * - And: The Lit Action JS code attempts to claim a key using the provided sessionSigs. + * - Then: The claim operation should successfully return signatures, derived key IDs, and validate the existence and structure of claimed results. + * + * - Note: The key claiming process involves multiple nodes within the Lit network verifying the sessionSigs and collaboratively signing the claim, which results in the generation of a new key pair if successful. + * + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToExecuteJsClaimKeys + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToExecuteJsClaimKeys + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToExecuteJsClaimKeys + */ +export const testUseEoaSessionSigsToExecuteJsClaimKeys = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: eoaSessionSigs, + code: `(async () => { + Lit.Actions.claimKey({keyId: "foo"}); + })();`, + }); + + console.log('res:', res); + + // Expected output: + // { + // claims: { + // foo: { + // signatures: [ + // { + // r: "0x31e5dcf6eed3619aa6ff68d0c8f7a4bcf082acc2f12c3d5bcae9b8bbaf883c07", + // s: "0x405f671d1c659022105775b18afe805e01eaa1d0799c6b92887baef77dc023f5", + // v: 27, + // }, { + // r: "0xf2e9fe653d9155bd93feb7fe122c07a81769076fe44567c3ea93bb828f87146e", + // s: "0x01adf2b2780511f70b0b037360ff4b0c2b8d04657a689af780180bed9e6ea3c5", + // v: 27, + // }, { + // r: "0xfe1dcacd79f53b42b24dae75521f01315f34bbc492233e26083995c82218a3ff", + // s: "0x0b708b11704d986b50bce9f648bb5d40e8b9ad87f3a337a213999c7751dc1c0c", + // v: 27, + // } + // ], + // derivedKeyId: "22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0", + // }, + // }, + // signatures: {}, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // assertions + if (!res.claims.foo) { + throw new Error(`Expected "foo" in res.claims`); + } + if (!res.claims.foo.derivedKeyId) { + throw new Error(`Expected "derivedKeyId" in res.claims.foo`); + } + + if (!res.claims.foo.signatures) { + throw new Error(`Expected "signatures" in res.claims.foo`); + } + + res.claims.foo.signatures.forEach((sig: any) => { + if (!sig.r) { + throw new Error(`Expected "r" in sig`); + } + if (!sig.s) { + throw new Error(`Expected "s" in sig`); + } + if (!sig.v) { + throw new Error(`Expected "v" in sig`); + } + }); + + // const claimRequest: ClaimRequest = { + // authMethod: devEnv.bobsWalletAuthMethod, + // signer: devEnv.hotWallet, + // mintCallback: async (claimRes: ClaimResult) => { + // console.log('claimRes:', claimRes); + + // const litContracts = await devEnv.getContractsClient(claimRes.signer); + // const pkpInfo = await litContracts.pkpNftContractUtils.write.claimAndMint( + // `0x${claimRes.derivedKeyId}`, + // claimRes.signatures + // ); + + // return pkpInfo.tokenId; + // }, + // }; + + // const claimRes = await devEnv.litNodeClient.claimKeyId(claimRequest); + + // console.log('claimRes:', claimRes); + + // Expected output: + // { + // signatures: [ + // { + // r: "0xf73ec73f2dd7858d9b463598420169cf153f8cd409c82af606b3832ff82f8774", + // s: "0x0de6ab4437749fdf1e6239a8d13af516ac9a0744fc0725f9897a880151799fde", + // v: 28, + // }, { + // r: "0x65ec2ac206c4d18aaf12d6d1f17826543c1f329657214cea66c509fcdec8d633", + // s: "0x710e2efb2c61f9ae504721d7bea0b8d1d3c519167e48e4d67c77bf61dfeca735", + // v: 28, + // }, { + // r: "0xe51bd0670463cb5b5e9994870362b3eaa747cb5732e5c666ccf25495fe9aaa54", + // s: "0x1b49aed6d46833c9b9ee0fa13a4009c533309dafdfd51dd30165f2556b6cdcf1", + // v: 27, + // }, { + // r: "0x4278d3f7f2eb38801da5940858be54527e42ee11b25d7b239cb491139c00765d", + // s: "0x13dac60eaa90a548a4c99f1e09ac24e07cb1ef7447e55d3c82cf2ea6d69ec190", + // v: 27, + // }, { + // r: "0xb18158eccd4b099d0cfae4c2f987843cbaf039ce50164410fe4f529e6dc2bb6a", + // s: "0x284d9d5326deeb3d10e2c1d81ed1a7d6fca584c46ad9606a4dad9f12d81874ab", + // v: 27, + // }, { + // r: "0x28ad76574d39d646948642d05f599a982a1dd0776e2e36138315f5fb2c03666e", + // s: "0x2a125a028df39b9230f5d866383fcda0107cc7ee2f42fa1f323d41b34f67273a", + // v: 27, + // }, { + // r: "0xb7ab5120aeffeaee6e8d6ab1456d6823a15fae7e5a70b88d2556dc85450486cf", + // s: "0x6e1e9ac479066d95d62a6cd86f0cb3db92e07367acf43873fb5a7b8ad558a09d", + // v: 28, + // } + // ], + // claimedKeyId: "4825e3caf11a273792ad0405524820410cd15d6323ae4621537f0a89c1322a74", + // pubkey: "049528b98ac4829b5eaf8f8e6addaa9c12e94e83c4d17baf8f86554c111f2ac6d774f483fca03ad06b268059f7c8bcf64c7fb93689e153dc2fed79dada7b289195", + // mintTx: "0x0000000000000000000000000000000000000000000000000000000000000000", + // } + + // assertions + // if (!claimRes.claimedKeyId) { + // throw new Error(`Expected "claimedKeyId" in claimRes`); + // } + // if (!claimRes.pubkey) { + // throw new Error(`Expected "pubkey" in claimRes`); + // } + // if (!claimRes.mintTx) { + // throw new Error(`Expected "mintTx" in claimRes`); + // } + + // claimRes.signatures.forEach((sig: any) => { + // if (!sig.r) { + // throw new Error(`Expected "r" in sig`); + // } + // if (!sig.s) { + // throw new Error(`Expected "s" in sig`); + // } + // if (!sig.v) { + // throw new Error(`Expected "v" in sig`); + // } + // }); + + log('✅ testUseEoaSessionSigsToExecuteJsClaimKeys'); +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts new file mode 100644 index 0000000000..270f431905 --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -0,0 +1,105 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing the capability to claim keys using EOA (Externally Owned Account) session sigs. This test ensures that multiple keys can be claimed correctly. + * + * - Given: EOA sessionSigs are properly generated for the environment. + * - When: These sessionSigs are used to execute JS code within Lit Action. + * - And: The Lit Action JS code attempts to claim a key using the provided sessionSigs. + * - Then: The claim operation should successfully return signatures, derived key IDs, and validate the existence and structure of claimed results. + * * + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToExecuteJsClaimMultipleKeys + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToExecuteJsClaimMultipleKeys + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToExecuteJsClaimMultipleKeys + */ +export const testUseEoaSessionSigsToExecuteJsClaimMultipleKeys = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: eoaSessionSigs, + code: `(async () => { + Lit.Actions.claimKey({keyId: "foo"}); + Lit.Actions.claimKey({keyId: "bar"}); + })();`, + }); + + // Expected output: + // { + // claims: { + // bar: { + // signatures: [ + // { + // r: "0x7ee7b329462acb08d1dd1d3fba17f8ac76263454e2582bc0d5f36c74f4aaac68", + // s: "0x1b20cd8ac8ab1efdcf500d7ff100229deee42ce44b6420619c609a694af33aad", + // v: 28, + // }, { + // r: "0x2bd6db983d5f5dd239b4fe27b087acf0547e49a69e6c62b8e1435d3890a5d4c5", + // s: "0x15a8a80b2a5bf16e9c155bfe9d5da1109847334b8a0a74a9ce277cdfc6b05fdd", + // v: 28, + // }, { + // r: "0x9294c656bdb6764fca46e431dc4b15c653e6347a41eb657d23145d93a1fa19d0", + // s: "0x7afe0be470e9393dda32c356a9a262f7794a59f8e75e551bdb7634beb3a0a114", + // v: 28, + // } + // ], + // derivedKeyId: "0961c21c8a46c4992003a7b7af9449c15f772a269633ae3242f6ed146708a819", + // }, + // foo: { + // signatures: [ + // { + // r: "0xc39c073d69c8878bf06c813af9d090b41e15319abc9677e20f07085c96451e98", + // s: "0x6ef6a3d4b365119f4a9613a89fd57af01c4a350a20222935581be306b4c8aba4", + // v: 27, + // }, { + // r: "0xa2473911de4b252349cadde340de121ce3195929cd1ebb4c717f3d9d65c67988", + // s: "0x597a45d27a3100fa0bb144644f6bdec62c8a827f35427814cea64f8d3d9a9fa8", + // v: 27, + // }, { + // r: "0x97c393fb1f733b946bfaafdbb13c46192f4cf5ad2b2a9fcf9ff0355a7a2dc5fa", + // s: "0x152737c1b0aba904182bb5ac70e3a99ba4301b631df55bd21b91d705eb5ef4d2", + // v: 27, + // } + // ], + // derivedKeyId: "7698c828a5e4ae6dd6f98ae72fcb5a96bc83f53fa6a09c614e28ceab8198d5ca", + // }, + // }, + // signatures: {}, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // assertions + if (!res.claims.foo) { + throw new Error(`Expected "foo" in res.claims`); + } + if (!res.claims.foo.derivedKeyId) { + throw new Error(`Expected "derivedKeyId" in res.claims.foo`); + } + + if (!res.claims.foo.signatures) { + throw new Error(`Expected "signatures" in res.claims.foo`); + } + + res.claims.foo.signatures.forEach((sig: any) => { + if (!sig.r) { + throw new Error(`Expected "r" in sig`); + } + if (!sig.s) { + throw new Error(`Expected "s" in sig`); + } + if (!sig.v) { + throw new Error(`Expected "v" in sig`); + } + }); +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsConsoleLog.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsConsoleLog.ts new file mode 100644 index 0000000000..b09b213bbd --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsConsoleLog.ts @@ -0,0 +1,54 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToExecuteJsConsoleLog + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToExecuteJsConsoleLog + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToExecuteJsConsoleLog + */ +export const testUseEoaSessionSigsToExecuteJsConsoleLog = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: eoaSessionSigs, + code: `(async () => { + console.log('hello world') + })();`, + }); + + console.log('res:', res); + + // Expected output: + // { + // success: true, + // signedData: {}, + // decryptedData: {}, + // claimData: {}, + // response: "", + // logs: "hello world\n", + // } + + // -- assertions + if (res.response) { + throw new Error(`Expected "response" to be falsy`); + } + + if (!res.logs) { + throw new Error(`Expected "logs" in res`); + } + + if (!res.logs.includes('hello world')) { + throw new Error(`Expected "logs" to include 'hello world'`); + } + + if (!res.success) { + throw new Error(`Expected "success" in res`); + } +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts new file mode 100644 index 0000000000..5489c1ea8e --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts @@ -0,0 +1,69 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToExecuteJsJsonResponse + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToExecuteJsJsonResponse + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToExecuteJsJsonResponse + */ +export const testUseEoaSessionSigsToExecuteJsJsonResponse = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: eoaSessionSigs, + code: `(async () => { + console.log('hello world') + + LitActions.setResponse({ + response: JSON.stringify({hello: 'world'}) + }); + + })();`, + }); + + // Expected output: + // { + // success: true, + // signedData: {}, + // decryptedData: {}, + // claimData: {}, + // response: "{\"hello\":\"world\"}", + // logs: "hello world\n", + // } + + // -- assertions + if (!res.response) { + throw new Error(`Expected "response" in res`); + } + + if (!res.response.startsWith('{')) { + throw new Error(`Expected "response" to start with {`); + } + + if (!res.response.endsWith('}')) { + throw new Error(`Expected "response" to end with }`); + } + + if (!res.logs) { + throw new Error(`Expected "logs" in res`); + } + + if (!res.logs.includes('hello world')) { + throw new Error(`Expected "logs" to include 'hello world'`); + } + + if (!res.success) { + throw new Error(`Expected "success" in res`); + } + + if (res.success !== true) { + throw new Error(`Expected "success" to be true`); + } +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigning.ts new file mode 100644 index 0000000000..49275a856e --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigning.ts @@ -0,0 +1,66 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning + */ +export const testUseEoaSessionSigsToExecuteJsSigning = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: eoaSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.pkp.publicKey, + }, + }); + + // -- Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "63311a761842b41686875862a3fb09975c838afff6ae11c5c3940da458dffe79", + // s: "1c25f352b4a8bf15510cecbee4e798270cdf68c45a26cf93dc32d6e03dfc720a", + // recid: 0, + // signature: "0x63311a761842b41686875862a3fb09975c838afff6ae11c5c3940da458dffe791c25f352b4a8bf15510cecbee4e798270cdf68c45a26cf93dc32d6e03dfc720a1b", + // publicKey: "0423F38A7663289FC58841B5F8E068FA43106BC7DDEE38D1F2542C03ABEC45B6733BE2D85A703C7B238865E45DF2175DD2A1736C56F2BAD0A965837F64BB21FB03", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + log('✅ testUseEoaSessionSigsToExecuteJsSigning'); +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts new file mode 100644 index 0000000000..719c4154bf --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts @@ -0,0 +1,121 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigningInParallel + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigningInParallel + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigningInParallel + */ +export const testUseEoaSessionSigsToExecuteJsSigningInParallel = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const fn = async (index: number) => { + log(`Index: ${index}`); + + return await devEnv.litNodeClient.executeJs({ + sessionSigs: eoaSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.pkp.publicKey, + }, + }); + }; + + const res = await Promise.all([fn(1), fn(2), fn(3)]); + log('res:', res); + + // -- Expected output: + // [ + // { + // claims: {}, + // signatures: { + // sig: { + // r: "d5bc8b53b9f69604c2dfb2d1d3e6c8b7e01a225346055ee798f5f67fe542a05a", + // s: "0153071ac4c7f9b08330361575b109dec07d1c335edeecd85db47398795a00d0", + // recid: 0, + // signature: "0xd5bc8b53b9f69604c2dfb2d1d3e6c8b7e01a225346055ee798f5f67fe542a05a0153071ac4c7f9b08330361575b109dec07d1c335edeecd85db47398795a00d01b", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // }, { + // claims: {}, + // signatures: { + // sig: { + // r: "d2ad9086e810a5fd9b49dc4c2a0e7e2cf417dd79f8e75cc5f7b7b21d1b7ae9bc", + // s: "5e28b3321e73bab4177f6a69fec924f9daec294cf89a9a4d9c1a8fad18810bbd", + // recid: 1, + // signature: "0xd2ad9086e810a5fd9b49dc4c2a0e7e2cf417dd79f8e75cc5f7b7b21d1b7ae9bc5e28b3321e73bab4177f6a69fec924f9daec294cf89a9a4d9c1a8fad18810bbd1c", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // }, { + // claims: {}, + // signatures: { + // sig: { + // r: "50f87167ba2c8a92e78c95f34e2683a23c372fcc6d104ef9f4d9050d5e1621f3", + // s: "443f5895668e8df6b5d6097a3e9f363923dc2cb83a4734b79359c8213f220fa9", + // recid: 0, + // signature: "0x50f87167ba2c8a92e78c95f34e2683a23c372fcc6d104ef9f4d9050d5e1621f3443f5895668e8df6b5d6097a3e9f363923dc2cb83a4734b79359c8213f220fa91b", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + // ] + + // -- assertions + res.forEach((r) => { + if (!r.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!r.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!r.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!r.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!r.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(r.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + }); + + log('✅ testUseEoaSessionSigsToExecuteJsSigningInParallel'); +}; diff --git a/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts b/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts new file mode 100644 index 0000000000..a0fb81fe4c --- /dev/null +++ b/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts @@ -0,0 +1,62 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseEoaSessionSigsToPkpSign + * ✅ NETWORK=manzano yarn test:local --filter=testUseEoaSessionSigsToPkpSign + * ✅ NETWORK=localchain yarn test:local --filter=testUseEoaSessionSigsToPkpSign + */ +export const testUseEoaSessionSigsToPkpSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const runWithSessionSigs = await devEnv.litNodeClient.pkpSign({ + toSign: alice.loveLetter, + pubKey: alice.pkp.publicKey, + sessionSigs: eoaSessionSigs, + }); + + // Expected output: + // { + // r: "25fc0d2fecde8ed801e9fee5ad26f2cf61d82e6f45c8ad1ad1e4798d3b747fd9", + // s: "549fe745b4a09536e6e7108d814cf7e44b93f1d73c41931b8d57d1b101833214", + // recid: 1, + // signature: "0x25fc0d2fecde8ed801e9fee5ad26f2cf61d82e6f45c8ad1ad1e4798d3b747fd9549fe745b4a09536e6e7108d814cf7e44b93f1d73c41931b8d57d1b1018332141c", + // publicKey: "04A3CD53CCF63597D3FFCD1DF1E8236F642C7DF8196F532C8104625635DC55A1EE59ABD2959077432FF635DF2CED36CC153050902B71291C4D4867E7DAAF964049", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + // r, s, dataSigned, and public key should be present + if (!runWithSessionSigs.r) { + throw new Error(`Expected "r" in runWithSessionSigs`); + } + if (!runWithSessionSigs.s) { + throw new Error(`Expected "s" in runWithSessionSigs`); + } + if (!runWithSessionSigs.dataSigned) { + throw new Error(`Expected "dataSigned" in runWithSessionSigs`); + } + if (!runWithSessionSigs.publicKey) { + throw new Error(`Expected "publicKey" in runWithSessionSigs`); + } + + // signature must start with 0x + if (!runWithSessionSigs.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // recid must be parseable as a number + if (isNaN(runWithSessionSigs.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + log('✅ testUseEoaSessionSigsToPkpSign'); +}; diff --git a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts new file mode 100644 index 0000000000..3a809b7f21 --- /dev/null +++ b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts @@ -0,0 +1,32 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getInvalidLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ NOT AVAILABLE IN CAYENNE + * ❌ NOT AVAILABLE IN MANZANO + * ✅ NETWORK=localchain yarn test:local --filter=testUseInvalidLitActionCodeToGenerateSessionSigs + */ +export const testUseInvalidLitActionCodeToGenerateSessionSigs = async ( + devEnv: TinnyEnvironment +) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + + try { + await getInvalidLitActionSessionSigs(devEnv, alice); + } catch (e: any) { + if ( + e.message === + 'There was an error getting the signing shares from the nodes' + ) { + console.log('✅ testUseInvalidLitActionCodeToGenerateSessionSigs passed'); + } else { + throw e; + } + } +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts new file mode 100644 index 0000000000..6200661671 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts @@ -0,0 +1,97 @@ +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptFile + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptFile + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptFile + */ +export const testUsePkpSessionSigsToEncryptDecryptFile = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const message = 'Hello world'; + const blob = new Blob([message], { type: 'text/plain' }); + const blobArray = new Uint8Array(await blob.arrayBuffer()); + + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.authMethodOwnedPkp.ethAddress, + }); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: pkpSessionSigs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const pkpSessionSigs2 = await getPkpSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decriptedFile = await LitJsSdk.decryptToFile( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: pkpSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (blobArray.length !== decriptedFile.length) { + throw new Error( + `decrypted file should match the original file but received ${decriptedFile}` + ); + } + for (let i = 0; i < blobArray.length; i++) { + if (blobArray[i] !== decriptedFile[i]) { + throw new Error(`decrypted file should match the original file`); + } + } + + console.log('decriptedFile:', decriptedFile); +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts new file mode 100644 index 0000000000..daaf80e1d6 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts @@ -0,0 +1,83 @@ +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptString + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptString + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptString + */ +export const testUsePkpSessionSigsToEncryptDecryptString = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.authMethodOwnedPkp.ethAddress, + }); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: pkpSessionSigs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const pkpSessionSigs2 = await getPkpSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decryptRes = await LitJsSdk.decryptToString( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: pkpSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (decryptRes !== 'Hello world') { + throw new Error( + `Expected decryptRes to be 'Hello world' but got ${decryptRes}` + ); + } +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts new file mode 100644 index 0000000000..26c7e8afb0 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts @@ -0,0 +1,92 @@ +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptZip + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptZip + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToEncryptDecryptZip + */ +export const testUsePkpSessionSigsToEncryptDecryptZip = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const message = 'Hello world'; + + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.authMethodOwnedPkp.ethAddress, + }); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.zipAndEncryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: pkpSessionSigs, + dataToEncrypt: message, + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const pkpSessionSigs2 = await getPkpSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decryptedZip = await LitJsSdk.decryptToZip( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: pkpSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + const decryptedMessage = await decryptedZip['string.txt'].async('string'); + + if (message !== decryptedMessage) { + throw new Error( + `decryptedMessage should be ${message} but received ${decryptedMessage}` + ); + } + + console.log('decryptedMessage:', decryptedMessage); +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts new file mode 100644 index 0000000000..c3084c34fa --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts @@ -0,0 +1,170 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing the capability to claim keys using PKP session sigs. This test ensures that keys can be claimed correctly. + * + * - Given: PKP sessionSigs are properly generated for the environment. + * - When: These sessionSigs are used to execute JS code within Lit Action. + * - And: The Lit Action JS code attempts to claim a key using the provided sessionSigs. + * - Then: The claim operation should successfully return signatures, derived key IDs, and validate the existence and structure of claimed results. + * + * - Note: The key claiming process involves multiple nodes within the Lit network verifying the sessionSigs and collaboratively signing the claim, which results in the generation of a new key pair if successful. + * + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToExecuteJsClaimKeys + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToExecuteJsClaimKeys + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToExecuteJsClaimKeys + */ +export const testUsePkpSessionSigsToExecuteJsClaimKeys = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: pkpSessionSigs, + code: `(async () => { + Lit.Actions.claimKey({keyId: "foo"}); + })();`, + }); + + console.log('res:', res); + + // Expected output: + // { + // claims: { + // foo: { + // signatures: [ + // { + // r: "0x31e5dcf6eed3619aa6ff68d0c8f7a4bcf082acc2f12c3d5bcae9b8bbaf883c07", + // s: "0x405f671d1c659022105775b18afe805e01eaa1d0799c6b92887baef77dc023f5", + // v: 27, + // }, { + // r: "0xf2e9fe653d9155bd93feb7fe122c07a81769076fe44567c3ea93bb828f87146e", + // s: "0x01adf2b2780511f70b0b037360ff4b0c2b8d04657a689af780180bed9e6ea3c5", + // v: 27, + // }, { + // r: "0xfe1dcacd79f53b42b24dae75521f01315f34bbc492233e26083995c82218a3ff", + // s: "0x0b708b11704d986b50bce9f648bb5d40e8b9ad87f3a337a213999c7751dc1c0c", + // v: 27, + // } + // ], + // derivedKeyId: "22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0", + // }, + // }, + // signatures: {}, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // assertions + if (!res.claims.foo) { + throw new Error(`Expected "foo" in res.claims`); + } + if (!res.claims.foo.derivedKeyId) { + throw new Error(`Expected "derivedKeyId" in res.claims.foo`); + } + + if (!res.claims.foo.signatures) { + throw new Error(`Expected "signatures" in res.claims.foo`); + } + + res.claims.foo.signatures.forEach((sig: any) => { + if (!sig.r) { + throw new Error(`Expected "r" in sig`); + } + if (!sig.s) { + throw new Error(`Expected "s" in sig`); + } + if (!sig.v) { + throw new Error(`Expected "v" in sig`); + } + }); + + // const claimRequest: ClaimRequest = { + // authMethod: devEnv.bobsWalletAuthMethod, + // signer: devEnv.hotWallet, + // mintCallback: async (claimRes: ClaimResult) => { + // console.log('claimRes:', claimRes); + + // const litContracts = await devEnv.getContractsClient(claimRes.signer); + // const pkpInfo = await litContracts.pkpNftContractUtils.write.claimAndMint( + // `0x${claimRes.derivedKeyId}`, + // claimRes.signatures + // ); + + // return pkpInfo.tokenId; + // }, + // }; + + // const claimRes = await devEnv.litNodeClient.claimKeyId(claimRequest); + + // console.log('claimRes:', claimRes); + + // Expected output: + // { + // signatures: [ + // { + // r: "0xf73ec73f2dd7858d9b463598420169cf153f8cd409c82af606b3832ff82f8774", + // s: "0x0de6ab4437749fdf1e6239a8d13af516ac9a0744fc0725f9897a880151799fde", + // v: 28, + // }, { + // r: "0x65ec2ac206c4d18aaf12d6d1f17826543c1f329657214cea66c509fcdec8d633", + // s: "0x710e2efb2c61f9ae504721d7bea0b8d1d3c519167e48e4d67c77bf61dfeca735", + // v: 28, + // }, { + // r: "0xe51bd0670463cb5b5e9994870362b3eaa747cb5732e5c666ccf25495fe9aaa54", + // s: "0x1b49aed6d46833c9b9ee0fa13a4009c533309dafdfd51dd30165f2556b6cdcf1", + // v: 27, + // }, { + // r: "0x4278d3f7f2eb38801da5940858be54527e42ee11b25d7b239cb491139c00765d", + // s: "0x13dac60eaa90a548a4c99f1e09ac24e07cb1ef7447e55d3c82cf2ea6d69ec190", + // v: 27, + // }, { + // r: "0xb18158eccd4b099d0cfae4c2f987843cbaf039ce50164410fe4f529e6dc2bb6a", + // s: "0x284d9d5326deeb3d10e2c1d81ed1a7d6fca584c46ad9606a4dad9f12d81874ab", + // v: 27, + // }, { + // r: "0x28ad76574d39d646948642d05f599a982a1dd0776e2e36138315f5fb2c03666e", + // s: "0x2a125a028df39b9230f5d866383fcda0107cc7ee2f42fa1f323d41b34f67273a", + // v: 27, + // }, { + // r: "0xb7ab5120aeffeaee6e8d6ab1456d6823a15fae7e5a70b88d2556dc85450486cf", + // s: "0x6e1e9ac479066d95d62a6cd86f0cb3db92e07367acf43873fb5a7b8ad558a09d", + // v: 28, + // } + // ], + // claimedKeyId: "4825e3caf11a273792ad0405524820410cd15d6323ae4621537f0a89c1322a74", + // pubkey: "049528b98ac4829b5eaf8f8e6addaa9c12e94e83c4d17baf8f86554c111f2ac6d774f483fca03ad06b268059f7c8bcf64c7fb93689e153dc2fed79dada7b289195", + // mintTx: "0x0000000000000000000000000000000000000000000000000000000000000000", + // } + + // assertions + // if (!claimRes.claimedKeyId) { + // throw new Error(`Expected "claimedKeyId" in claimRes`); + // } + // if (!claimRes.pubkey) { + // throw new Error(`Expected "pubkey" in claimRes`); + // } + // if (!claimRes.mintTx) { + // throw new Error(`Expected "mintTx" in claimRes`); + // } + + // claimRes.signatures.forEach((sig: any) => { + // if (!sig.r) { + // throw new Error(`Expected "r" in sig`); + // } + // if (!sig.s) { + // throw new Error(`Expected "s" in sig`); + // } + // if (!sig.v) { + // throw new Error(`Expected "v" in sig`); + // } + // }); +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts new file mode 100644 index 0000000000..a4de221f96 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -0,0 +1,104 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing the capability to claim keys using PKP session sigs. This test ensures that multiple keys can be claimed correctly. + * + * - Given: PKP sessionSigs are properly generated for the environment. + * - When: These sessionSigs are used to execute JS code within Lit Action. + * - And: The Lit Action JS code attempts to claim a key using the provided sessionSigs. + * - Then: The claim operation should successfully return signatures, derived key IDs, and validate the existence and structure of claimed results. + * * + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToExecuteJsClaimMultipleKeys + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToExecuteJsClaimMultipleKeys + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToExecuteJsClaimMultipleKeys + */ +export const testUsePkpSessionSigsToExecuteJsClaimMultipleKeys = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: pkpSessionSigs, + code: `(async () => { + Lit.Actions.claimKey({keyId: "foo"}); + Lit.Actions.claimKey({keyId: "bar"}); + })();`, + }); + + // Expected output: + // { + // claims: { + // bar: { + // signatures: [ + // { + // r: "0x7ee7b329462acb08d1dd1d3fba17f8ac76263454e2582bc0d5f36c74f4aaac68", + // s: "0x1b20cd8ac8ab1efdcf500d7ff100229deee42ce44b6420619c609a694af33aad", + // v: 28, + // }, { + // r: "0x2bd6db983d5f5dd239b4fe27b087acf0547e49a69e6c62b8e1435d3890a5d4c5", + // s: "0x15a8a80b2a5bf16e9c155bfe9d5da1109847334b8a0a74a9ce277cdfc6b05fdd", + // v: 28, + // }, { + // r: "0x9294c656bdb6764fca46e431dc4b15c653e6347a41eb657d23145d93a1fa19d0", + // s: "0x7afe0be470e9393dda32c356a9a262f7794a59f8e75e551bdb7634beb3a0a114", + // v: 28, + // } + // ], + // derivedKeyId: "0961c21c8a46c4992003a7b7af9449c15f772a269633ae3242f6ed146708a819", + // }, + // foo: { + // signatures: [ + // { + // r: "0xc39c073d69c8878bf06c813af9d090b41e15319abc9677e20f07085c96451e98", + // s: "0x6ef6a3d4b365119f4a9613a89fd57af01c4a350a20222935581be306b4c8aba4", + // v: 27, + // }, { + // r: "0xa2473911de4b252349cadde340de121ce3195929cd1ebb4c717f3d9d65c67988", + // s: "0x597a45d27a3100fa0bb144644f6bdec62c8a827f35427814cea64f8d3d9a9fa8", + // v: 27, + // }, { + // r: "0x97c393fb1f733b946bfaafdbb13c46192f4cf5ad2b2a9fcf9ff0355a7a2dc5fa", + // s: "0x152737c1b0aba904182bb5ac70e3a99ba4301b631df55bd21b91d705eb5ef4d2", + // v: 27, + // } + // ], + // derivedKeyId: "7698c828a5e4ae6dd6f98ae72fcb5a96bc83f53fa6a09c614e28ceab8198d5ca", + // }, + // }, + // signatures: {}, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // assertions + if (!res.claims.foo) { + throw new Error(`Expected "foo" in res.claims`); + } + if (!res.claims.foo.derivedKeyId) { + throw new Error(`Expected "derivedKeyId" in res.claims.foo`); + } + + if (!res.claims.foo.signatures) { + throw new Error(`Expected "signatures" in res.claims.foo`); + } + + res.claims.foo.signatures.forEach((sig: any) => { + if (!sig.r) { + throw new Error(`Expected "r" in sig`); + } + if (!sig.s) { + throw new Error(`Expected "s" in sig`); + } + if (!sig.v) { + throw new Error(`Expected "v" in sig`); + } + }); +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts new file mode 100644 index 0000000000..e5d18aeab7 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts @@ -0,0 +1,52 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToExecuteJsConsoleLog + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToExecuteJsConsoleLog + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToExecuteJsConsoleLog + */ +export const testUsePkpSessionSigsToExecuteJsConsoleLog = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: pkpSessionSigs, + code: `(async () => { + console.log('hello world') + })();`, + }); + + // Expected output: + // { + // success: true, + // signedData: {}, + // decryptedData: {}, + // claimData: {}, + // response: "", + // logs: "hello world\n", + // } + + // -- assertions + if (res.response) { + throw new Error(`Expected "response" to be falsy`); + } + + if (!res.logs) { + throw new Error(`Expected "logs" in res`); + } + + if (!res.logs.includes('hello world')) { + throw new Error(`Expected "logs" to include 'hello world'`); + } + + if (!res.success) { + throw new Error(`Expected "success" in res`); + } +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts new file mode 100644 index 0000000000..dfee097b12 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts @@ -0,0 +1,69 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToExecuteJsJsonResponse + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToExecuteJsJsonResponse + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToExecuteJsJsonResponse + */ +export const testUsePkpSessionSigsToExecuteJsJsonResponse = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: pkpSessionSigs, + code: `(async () => { + console.log('hello world') + + LitActions.setResponse({ + response: JSON.stringify({hello: 'world'}) + }); + + })();`, + }); + + // Expected output: + // { + // success: true, + // signedData: {}, + // decryptedData: {}, + // claimData: {}, + // response: "{\"hello\":\"world\"}", + // logs: "hello world\n", + // } + + // -- assertions + if (!res.response) { + throw new Error(`Expected "response" in res`); + } + + if (!res.response.startsWith('{')) { + throw new Error(`Expected "response" to start with {`); + } + + if (!res.response.endsWith('}')) { + throw new Error(`Expected "response" to end with }`); + } + + if (!res.logs) { + throw new Error(`Expected "logs" in res`); + } + + if (!res.logs.includes('hello world')) { + throw new Error(`Expected "logs" to include 'hello world'`); + } + + if (!res.success) { + throw new Error(`Expected "success" in res`); + } + + if (res.success !== true) { + throw new Error(`Expected "success" to be true`); + } +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts new file mode 100644 index 0000000000..3e4145681b --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts @@ -0,0 +1,80 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToExecuteJsSigning + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToExecuteJsSigning + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToExecuteJsSigning + */ +export const testUsePkpSessionSigsToExecuteJsSigning = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: pkpSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.authMethodOwnedPkp.publicKey, + }, + }); + + // -- Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "8d2a3b3fa49e67b6bf9de15adfc0b5fbe04b6d730cbef60f4c211c4803bd9c3f", + // s: "1f819cc7a74a72e6f1b16a9a665f19cdd7294132d8a1c70871a752a6d70615e4", + // recid: 1, + // signature: "0x8d2a3b3fa49e67b6bf9de15adfc0b5fbe04b6d730cbef60f4c211c4803bd9c3f1f819cc7a74a72e6f1b16a9a665f19cdd7294132d8a1c70871a752a6d70615e41c", + // publicKey: "044395E44BA89AC0D0E76DEECD937C7BC0AE96B47766AB01CEC5449A8F869754560ACAEAC82CD48FAD3553AD47D7FAA99131F6E7E1B19DEBA058BB6D6B97F2BDB1", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!res.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(res.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + log('✅ res:', res); +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts new file mode 100644 index 0000000000..554f0ed1c6 --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts @@ -0,0 +1,121 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToExecuteJsSigningInParallel + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToExecuteJsSigningInParallel + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToExecuteJsSigningInParallel + */ +export const testUsePkpSessionSigsToExecuteJsSigningInParallel = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const fn = async (index: number) => { + log(`Index: ${index}`); + + return await devEnv.litNodeClient.executeJs({ + sessionSigs: pkpSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.authMethodOwnedPkp.publicKey, + }, + }); + }; + + const res = await Promise.all([fn(1), fn(2), fn(3)]); + log('res:', res); + + // -- Expected output: + // [ + // { + // claims: {}, + // signatures: { + // sig: { + // r: "d5bc8b53b9f69604c2dfb2d1d3e6c8b7e01a225346055ee798f5f67fe542a05a", + // s: "0153071ac4c7f9b08330361575b109dec07d1c335edeecd85db47398795a00d0", + // recid: 0, + // signature: "0xd5bc8b53b9f69604c2dfb2d1d3e6c8b7e01a225346055ee798f5f67fe542a05a0153071ac4c7f9b08330361575b109dec07d1c335edeecd85db47398795a00d01b", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // }, { + // claims: {}, + // signatures: { + // sig: { + // r: "d2ad9086e810a5fd9b49dc4c2a0e7e2cf417dd79f8e75cc5f7b7b21d1b7ae9bc", + // s: "5e28b3321e73bab4177f6a69fec924f9daec294cf89a9a4d9c1a8fad18810bbd", + // recid: 1, + // signature: "0xd2ad9086e810a5fd9b49dc4c2a0e7e2cf417dd79f8e75cc5f7b7b21d1b7ae9bc5e28b3321e73bab4177f6a69fec924f9daec294cf89a9a4d9c1a8fad18810bbd1c", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // }, { + // claims: {}, + // signatures: { + // sig: { + // r: "50f87167ba2c8a92e78c95f34e2683a23c372fcc6d104ef9f4d9050d5e1621f3", + // s: "443f5895668e8df6b5d6097a3e9f363923dc2cb83a4734b79359c8213f220fa9", + // recid: 0, + // signature: "0x50f87167ba2c8a92e78c95f34e2683a23c372fcc6d104ef9f4d9050d5e1621f3443f5895668e8df6b5d6097a3e9f363923dc2cb83a4734b79359c8213f220fa91b", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + // ] + + // -- assertions + res.forEach((r) => { + if (!r.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!r.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!r.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!r.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!r.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(r.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + }); + + log('✅ testUsePkpSessionSigsToExecuteJsSigningInParallel'); +}; diff --git a/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts b/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts new file mode 100644 index 0000000000..f350628a7b --- /dev/null +++ b/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts @@ -0,0 +1,60 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUsePkpSessionSigsToPkpSign + * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToPkpSign + * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToPkpSign + */ +export const testUsePkpSessionSigsToPkpSign = async (devEnv: TinnyEnvironment) => { + const alice = await devEnv.createRandomPerson(); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.pkpSign({ + toSign: alice.loveLetter, + pubKey: alice.authMethodOwnedPkp.publicKey, + sessionSigs: pkpSessionSigs, + }); + + // -- Expected output: + // { + // r: "f67785b9c516a1fdbd224e9591554171d594bb1fb9799c851bac56212956838a", + // s: "799edb2732f2ebeaf90ea84cbf4c2a2e2ba509487a19d5c6b88210afe362ce42", + // recid: 1, + // signature: "0xf67785b9c516a1fdbd224e9591554171d594bb1fb9799c851bac56212956838a799edb2732f2ebeaf90ea84cbf4c2a2e2ba509487a19d5c6b88210afe362ce421c", + // publicKey: "0486C6E6E854337411A3884E0DEFF15D6D69663594826313BB73E18C465A079B4C2850719F45E9BE2FAC18AA78FFF2C7AEC912FA9D646B2F088C6CAAA8F7A0144A", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + // r, s, dataSigned, and public key should be present + if (!res.r) { + throw new Error(`Expected "r" in res`); + } + if (!res.s) { + throw new Error(`Expected "s" in res`); + } + if (!res.dataSigned) { + throw new Error(`Expected "dataSigned" in res`); + } + if (!res.publicKey) { + throw new Error(`Expected "publicKey" in res`); + } + + // signature must start with 0x + if (!res.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // recid must be parseable as a number + if (isNaN(res.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + log('✅ res:', res); +}; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts new file mode 100644 index 0000000000..2b3f765f8c --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts @@ -0,0 +1,99 @@ +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile + * ✅ NETWORK=manzano yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + const alice = await devEnv.createRandomPerson(); + + const message = 'Hello world'; + const blob = new Blob([message], { type: 'text/plain' }); + const blobArray = new Uint8Array(await blob.arrayBuffer()); + + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.authMethodOwnedPkp.ethAddress, + }); + + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: pkpSessionSigs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const pkpSessionSigs2 = await getPkpSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decriptedFile = await LitJsSdk.decryptToFile( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: pkpSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (blobArray.length !== decriptedFile.length) { + throw new Error( + `decrypted file should match the original file but received ${decriptedFile}` + ); + } + for (let i = 0; i < blobArray.length; i++) { + if (blobArray[i] !== decriptedFile[i]) { + throw new Error(`decrypted file should match the original file`); + } + } + + console.log('decriptedFile:', decriptedFile); + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts new file mode 100644 index 0000000000..cf72950d3e --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts @@ -0,0 +1,87 @@ +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ❌ NOT AVAILABLE IN CAYENNE + * ❌ NOT AVAILABLE IN MANZANO + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString + * + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.authMethodOwnedPkp.ethAddress, + }); + + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: litActionSessionSigs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const litActionSessionSigs2 = await getLitActionSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decryptRes = await LitJsSdk.decryptToString( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: litActionSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (decryptRes !== 'Hello world') { + throw new Error( + `Expected decryptRes to be 'Hello world' but got ${decryptRes}` + ); + } + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts new file mode 100644 index 0000000000..c9a25bddd1 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts @@ -0,0 +1,94 @@ +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ❌ Not supported in Cayenne + * ❌ Not supported in Manzano + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + const alice = await devEnv.createRandomPerson(); + + const message = 'Hello world'; + + // set access control conditions for encrypting and decrypting + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: alice.authMethodOwnedPkp.ethAddress, + }); + + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const encryptRes = await LitJsSdk.zipAndEncryptString( + { + accessControlConditions: accs, + chain: 'ethereum', + sessionSigs: litActionSessionSigs, + dataToEncrypt: message, + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output: + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + const accsResourceString = + await LitAccessControlConditionResource.composeLitActionResourceString( + accs, + encryptRes.dataToEncryptHash + ); + + const litActionSessionSigs2 = await getLitActionSessionSigs(devEnv, alice, [ + { + resource: new LitAccessControlConditionResource(accsResourceString), + ability: LitAbility.AccessControlConditionDecryption, + }, + ]); + + // -- Decrypt the encrypted string + const decryptedZip = await LitJsSdk.decryptToZip( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + sessionSigs: litActionSessionSigs2, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + const decryptedMessage = await decryptedZip['string.txt'].async('string'); + + if (message !== decryptedMessage) { + throw new Error( + `decryptedMessage should be ${message} but received ${decryptedMessage}` + ); + } + + console.log('decryptedMessage:', decryptedMessage); + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts new file mode 100644 index 0000000000..638988e3b6 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts @@ -0,0 +1,116 @@ +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LitAbility } from '@lit-protocol/types'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing the capability to claim keys using Lit ACtion PKP session sigs. This test ensures that multiple keys can be claimed correctly. + * + * - Given: Lit ACtion PKP sessionSigs are properly generated for the environment. + * - When: These sessionSigs are used to execute JS code within Lit Action. + * - And: The Lit Action JS code attempts to claim a key using the provided sessionSigs. + * - Then: The claim operation should successfully return signatures, derived key IDs, and validate the existence and structure of claimed results. + * * + * Test Commands: + * ❌ Not supported in Cayenne + * ❌ Not supported in Manzano + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + Lit.Actions.claimKey({keyId: "foo"}); + Lit.Actions.claimKey({keyId: "bar"}); + })();`, + }); + + // Expected output: + // { + // claims: { + // bar: { + // signatures: [ + // { + // r: "0x7ee7b329462acb08d1dd1d3fba17f8ac76263454e2582bc0d5f36c74f4aaac68", + // s: "0x1b20cd8ac8ab1efdcf500d7ff100229deee42ce44b6420619c609a694af33aad", + // v: 28, + // }, { + // r: "0x2bd6db983d5f5dd239b4fe27b087acf0547e49a69e6c62b8e1435d3890a5d4c5", + // s: "0x15a8a80b2a5bf16e9c155bfe9d5da1109847334b8a0a74a9ce277cdfc6b05fdd", + // v: 28, + // }, { + // r: "0x9294c656bdb6764fca46e431dc4b15c653e6347a41eb657d23145d93a1fa19d0", + // s: "0x7afe0be470e9393dda32c356a9a262f7794a59f8e75e551bdb7634beb3a0a114", + // v: 28, + // } + // ], + // derivedKeyId: "0961c21c8a46c4992003a7b7af9449c15f772a269633ae3242f6ed146708a819", + // }, + // foo: { + // signatures: [ + // { + // r: "0xc39c073d69c8878bf06c813af9d090b41e15319abc9677e20f07085c96451e98", + // s: "0x6ef6a3d4b365119f4a9613a89fd57af01c4a350a20222935581be306b4c8aba4", + // v: 27, + // }, { + // r: "0xa2473911de4b252349cadde340de121ce3195929cd1ebb4c717f3d9d65c67988", + // s: "0x597a45d27a3100fa0bb144644f6bdec62c8a827f35427814cea64f8d3d9a9fa8", + // v: 27, + // }, { + // r: "0x97c393fb1f733b946bfaafdbb13c46192f4cf5ad2b2a9fcf9ff0355a7a2dc5fa", + // s: "0x152737c1b0aba904182bb5ac70e3a99ba4301b631df55bd21b91d705eb5ef4d2", + // v: 27, + // } + // ], + // derivedKeyId: "7698c828a5e4ae6dd6f98ae72fcb5a96bc83f53fa6a09c614e28ceab8198d5ca", + // }, + // }, + // signatures: {}, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // assertions + if (!res.claims.foo) { + throw new Error(`Expected "foo" in res.claims`); + } + if (!res.claims.foo.derivedKeyId) { + throw new Error(`Expected "derivedKeyId" in res.claims.foo`); + } + + if (!res.claims.foo.signatures) { + throw new Error(`Expected "signatures" in res.claims.foo`); + } + + res.claims.foo.signatures.forEach((sig: any) => { + if (!sig.r) { + throw new Error(`Expected "r" in sig`); + } + if (!sig.s) { + throw new Error(`Expected "s" in sig`); + } + if (!sig.v) { + throw new Error(`Expected "v" in sig`); + } + }); + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts new file mode 100644 index 0000000000..3fe3b2b482 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -0,0 +1,106 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * ## Scenario: + * Testing the capability to claim keys using Lit Action PKP session sigs. This test ensures that multiple keys can be claimed correctly. + * + * - Given: Lit Action PKP sessionSigs are properly generated for the environment. + * - When: These sessionSigs are used to execute JS code within Lit Action. + * - And: The Lit Action JS code attempts to claim a key using the provided sessionSigs. + * - Then: The claim operation should successfully return signatures, derived key IDs, and validate the existence and structure of claimed results. + * * + * Test Commands: + * ❌ Not supported in Cayenne + * ❌ Not supported in Manzano + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + Lit.Actions.claimKey({keyId: "foo"}); + Lit.Actions.claimKey({keyId: "bar"}); + })();`, + }); + + // Expected output: + // { + // claims: { + // bar: { + // signatures: [ + // { + // r: "0x7ee7b329462acb08d1dd1d3fba17f8ac76263454e2582bc0d5f36c74f4aaac68", + // s: "0x1b20cd8ac8ab1efdcf500d7ff100229deee42ce44b6420619c609a694af33aad", + // v: 28, + // }, { + // r: "0x2bd6db983d5f5dd239b4fe27b087acf0547e49a69e6c62b8e1435d3890a5d4c5", + // s: "0x15a8a80b2a5bf16e9c155bfe9d5da1109847334b8a0a74a9ce277cdfc6b05fdd", + // v: 28, + // }, { + // r: "0x9294c656bdb6764fca46e431dc4b15c653e6347a41eb657d23145d93a1fa19d0", + // s: "0x7afe0be470e9393dda32c356a9a262f7794a59f8e75e551bdb7634beb3a0a114", + // v: 28, + // } + // ], + // derivedKeyId: "0961c21c8a46c4992003a7b7af9449c15f772a269633ae3242f6ed146708a819", + // }, + // foo: { + // signatures: [ + // { + // r: "0xc39c073d69c8878bf06c813af9d090b41e15319abc9677e20f07085c96451e98", + // s: "0x6ef6a3d4b365119f4a9613a89fd57af01c4a350a20222935581be306b4c8aba4", + // v: 27, + // }, { + // r: "0xa2473911de4b252349cadde340de121ce3195929cd1ebb4c717f3d9d65c67988", + // s: "0x597a45d27a3100fa0bb144644f6bdec62c8a827f35427814cea64f8d3d9a9fa8", + // v: 27, + // }, { + // r: "0x97c393fb1f733b946bfaafdbb13c46192f4cf5ad2b2a9fcf9ff0355a7a2dc5fa", + // s: "0x152737c1b0aba904182bb5ac70e3a99ba4301b631df55bd21b91d705eb5ef4d2", + // v: 27, + // } + // ], + // derivedKeyId: "7698c828a5e4ae6dd6f98ae72fcb5a96bc83f53fa6a09c614e28ceab8198d5ca", + // }, + // }, + // signatures: {}, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // assertions + if (!res.claims.foo) { + throw new Error(`Expected "foo" in res.claims`); + } + if (!res.claims.foo.derivedKeyId) { + throw new Error(`Expected "derivedKeyId" in res.claims.foo`); + } + + if (!res.claims.foo.signatures) { + throw new Error(`Expected "signatures" in res.claims.foo`); + } + + res.claims.foo.signatures.forEach((sig: any) => { + if (!sig.r) { + throw new Error(`Expected "r" in sig`); + } + if (!sig.s) { + throw new Error(`Expected "s" in sig`); + } + if (!sig.v) { + throw new Error(`Expected "v" in sig`); + } + }); + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts new file mode 100644 index 0000000000..c81bbf5929 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts @@ -0,0 +1,67 @@ +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LitAbility } from '@lit-protocol/types'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ Not supported on cayenne + * ❌ Not supported on manzano + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + console.log('hello world') + })();`, + }); + + console.log('res:', res); + + // Expected output: + // { + // success: true, + // signedData: {}, + // decryptedData: {}, + // claimData: {}, + // response: "", + // logs: "hello world\n", + // } + + // -- assertions + if (res.response) { + throw new Error(`Expected "response" to be falsy`); + } + + if (!res.logs) { + throw new Error(`Expected "logs" in res`); + } + + if (!res.logs.includes('hello world')) { + throw new Error(`Expected "logs" to include 'hello world'`); + } + + if (!res.success) { + throw new Error(`Expected "success" in res`); + } + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts new file mode 100644 index 0000000000..5c968800f1 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts @@ -0,0 +1,70 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ Not supported on cayenne + * ❌ Not supported on manzano + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + console.log('hello world') + + LitActions.setResponse({ + response: JSON.stringify({hello: 'world'}) + }); + + })();`, + }); + + // Expected output: + // { + // success: true, + // signedData: {}, + // decryptedData: {}, + // claimData: {}, + // response: "{\"hello\":\"world\"}", + // logs: "hello world\n", + // } + + // -- assertions + if (!res.response) { + throw new Error(`Expected "response" in res`); + } + + if (!res.response.startsWith('{')) { + throw new Error(`Expected "response" to start with {`); + } + + if (!res.response.endsWith('}')) { + throw new Error(`Expected "response" to end with }`); + } + + if (!res.logs) { + throw new Error(`Expected "logs" in res`); + } + + if (!res.logs.includes('hello world')) { + throw new Error(`Expected "logs" to include 'hello world'`); + } + + if (!res.success) { + throw new Error(`Expected "success" in res`); + } + + if (res.success !== true) { + throw new Error(`Expected "success" to be true`); + } + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts new file mode 100644 index 0000000000..7f66deda66 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts @@ -0,0 +1,82 @@ +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LitAbility } from '@lit-protocol/types'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ NOT AVAILABLE IN CAYENNE + * ❌ NOT AVAILABLE IN HABANERO + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.authMethodOwnedPkp.publicKey, + }, + }); + + // -- Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "6d5ce6f948ff763939c204fc0f1b750fa0267ed567ed59581082d0cbf283feef", + // s: "4957ece75c60388500c4b7aa38a5fbafb7c20427db181aff7806af54c16ee145", + // recid: 1, + // signature: "0x6d5ce6f948ff763939c204fc0f1b750fa0267ed567ed59581082d0cbf283feef4957ece75c60388500c4b7aa38a5fbafb7c20427db181aff7806af54c16ee1451c", + // publicKey: "04D10D941B04491FDC99B048E2252A69137333254C482511D6CCDD401C080AF4F51BF65D9AE2413FCE066E326D7F0CED9C139DD9BA2D1C6334FD8C14CA4DD7F3D0", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + log('✅ res:', res); + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts new file mode 100644 index 0000000000..735e25f0b3 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts @@ -0,0 +1,123 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ Not available in Cayenne + * ❌ Not available in Habanero + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel + */ +export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel = + async (devEnv: TinnyEnvironment) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const fn = async (index: number) => { + log(`Index: ${index}`); + + return await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.authMethodOwnedPkp.publicKey, + }, + }); + }; + + const res = await Promise.all([fn(1), fn(2), fn(3)]); + log('res:', res); + + // -- Expected output: + // [ + // { + // claims: {}, + // signatures: { + // sig: { + // r: "d5bc8b53b9f69604c2dfb2d1d3e6c8b7e01a225346055ee798f5f67fe542a05a", + // s: "0153071ac4c7f9b08330361575b109dec07d1c335edeecd85db47398795a00d0", + // recid: 0, + // signature: "0xd5bc8b53b9f69604c2dfb2d1d3e6c8b7e01a225346055ee798f5f67fe542a05a0153071ac4c7f9b08330361575b109dec07d1c335edeecd85db47398795a00d01b", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // }, { + // claims: {}, + // signatures: { + // sig: { + // r: "d2ad9086e810a5fd9b49dc4c2a0e7e2cf417dd79f8e75cc5f7b7b21d1b7ae9bc", + // s: "5e28b3321e73bab4177f6a69fec924f9daec294cf89a9a4d9c1a8fad18810bbd", + // recid: 1, + // signature: "0xd2ad9086e810a5fd9b49dc4c2a0e7e2cf417dd79f8e75cc5f7b7b21d1b7ae9bc5e28b3321e73bab4177f6a69fec924f9daec294cf89a9a4d9c1a8fad18810bbd1c", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // }, { + // claims: {}, + // signatures: { + // sig: { + // r: "50f87167ba2c8a92e78c95f34e2683a23c372fcc6d104ef9f4d9050d5e1621f3", + // s: "443f5895668e8df6b5d6097a3e9f363923dc2cb83a4734b79359c8213f220fa9", + // recid: 0, + // signature: "0x50f87167ba2c8a92e78c95f34e2683a23c372fcc6d104ef9f4d9050d5e1621f3443f5895668e8df6b5d6097a3e9f363923dc2cb83a4734b79359c8213f220fa91b", + // publicKey: "0489782A60B39C758DD8405965DC83DE5F1DB9572861EBAB6064090223C3B7F60DD71C6E673D81550E127BE18497BEA8C349E3B91C8170AD572AD0572009797EA5", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + // ] + + // -- assertions + res.forEach((r) => { + if (!r.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!r.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!r.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!r.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + // -- signatures.sig.signature must start with 0x + if (!r.signatures.sig.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // -- signatures.sig.recid must be parseable as a number + if (isNaN(r.signatures.sig.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + }); + + log('✅ testUsePkpSessionSigsToExecuteJsSigningInParallel'); + }; diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts new file mode 100644 index 0000000000..603342f783 --- /dev/null +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts @@ -0,0 +1,67 @@ +import { LitPKPResource } from '@lit-protocol/auth-helpers'; +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { log } from '@lit-protocol/misc'; +import { LitAbility } from '@lit-protocol/types'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ NOT AVAILABLE IN CAYENNE + * ❌ NOT AVAILABLE IN HABANERO + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToPkpSign + * + **/ +export const testUseValidLitActionCodeGeneratedSessionSigsToPkpSign = async ( + devEnv: TinnyEnvironment +) => { + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const res = await devEnv.litNodeClient.pkpSign({ + toSign: alice.loveLetter, + pubKey: alice.authMethodOwnedPkp.publicKey, + sessionSigs: litActionSessionSigs, + }); + + // -- Expected output: + // { + // r: "ab2cef959db920d56f001c3b05637ee49af4c4441f2867ea067c413594a4c87b", + // s: "4bf11e17b4bb618aa6ed75cbf0406e6babfd953c5b201da697077c5fbf5b542e", + // recid: 1, + // signature: "0xab2cef959db920d56f001c3b05637ee49af4c4441f2867ea067c413594a4c87b4bf11e17b4bb618aa6ed75cbf0406e6babfd953c5b201da697077c5fbf5b542e1c", + // publicKey: "04400AD53C2F8BA11EBC69F05D1076D5BEE4EAE668CD66BABADE2E0770F756FDEEFC2C1D20F9A698EA3FEC6E9C944FF9FAFC2DC339B8E9392AFB9CC8AE75C5E5EC", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + // r, s, dataSigned, and public key should be present + if (!res.r) { + throw new Error(`Expected "r" in res`); + } + if (!res.s) { + throw new Error(`Expected "s" in res`); + } + if (!res.dataSigned) { + throw new Error(`Expected "dataSigned" in res`); + } + if (!res.publicKey) { + throw new Error(`Expected "publicKey" in res`); + } + + // signature must start with 0x + if (!res.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // recid must be parseable as a number + if (isNaN(res.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + log('✅ res:', res); +}; From 757d588dedc66864d0fcec692e9a22677ce38f0f Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 16:21:50 +0100 Subject: [PATCH 032/263] fix: unable to polyfill fetch when using cross-fetch, replaced with node-fetch as dev dependency for now --- local-tests/build.mjs | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/local-tests/build.mjs b/local-tests/build.mjs index 0ea3586e8e..644b2bce10 100644 --- a/local-tests/build.mjs +++ b/local-tests/build.mjs @@ -34,7 +34,7 @@ export const build = async () => { export const postBuildPolyfill = () => { try { const file = fs.readFileSync(`./${TEST_DIR}/build/test.mjs`, 'utf8'); - const content = `import fetch from 'cross-fetch'; + const content = `import fetch from 'node-fetch'; try { if (!globalThis.fetch) { globalThis.fetch = fetch; diff --git a/package.json b/package.json index 91460ceed7..f396e9b806 100644 --- a/package.json +++ b/package.json @@ -172,9 +172,9 @@ "cypress-metamask": "^1.0.5-development", "cypress-metamask-v2": "^1.7.2", "esbuild": "0.19.12", - "esbuild-plugin-tsc": "^0.4.0", "esbuild-node-builtins": "^0.1.0", "esbuild-node-externals": "^1.13.0", + "esbuild-plugin-tsc": "^0.4.0", "eslint": "8.48.0", "eslint-config-next": "12.2.3", "eslint-config-prettier": "9.1.0", @@ -189,6 +189,7 @@ "lerna": "^5.4.3", "live-server": "^1.2.2", "lokijs": "^1.5.12", + "node-fetch": "^2.6.1", "node-localstorage": "^3.0.5", "nodemon": "^2.0.20", "nx": "17.3.0", From 84f7095fe06bd667c4117c601679ac7729b54cd9 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Wed, 24 Apr 2024 16:34:19 +0100 Subject: [PATCH 033/263] chore: pretty pretty pretty lint --- ...thSigWithUnspecifiedDelegateesToPkpSign.ts | 2 +- ...UseEoaSessionSigsToEncryptDecryptString.ts | 4 - ...stUseEoaSessionSigsToExecuteJsClaimKeys.ts | 1 - ...SessionSigsToExecuteJsClaimMultipleKeys.ts | 1 - ...seEoaSessionSigsToExecuteJsJsonResponse.ts | 2 +- ...SessionSigsToExecuteJsSigningInParallel.ts | 2 +- .../tests/testUseEoaSessionSigsToPkpSign.ts | 2 +- ...validLitActionCodeToGenerateSessionSigs.ts | 2 +- ...stUsePkpSessionSigsToExecuteJsClaimKeys.ts | 2 +- ...SessionSigsToExecuteJsClaimMultipleKeys.ts | 2 +- ...tUsePkpSessionSigsToExecuteJsConsoleLog.ts | 2 +- ...sePkpSessionSigsToExecuteJsJsonResponse.ts | 2 +- ...testUsePkpSessionSigsToExecuteJsSigning.ts | 2 +- ...SessionSigsToExecuteJsSigningInParallel.ts | 2 +- .../tests/testUsePkpSessionSigsToPkpSign.ts | 6 +- ...eneratedSessionSigsToExecuteJsClaimKeys.ts | 2 +- ...SessionSigsToExecuteJsClaimMultipleKeys.ts | 2 +- ...neratedSessionSigsToExecuteJsConsoleLog.ts | 2 +- ...eGeneratedSessionSigsToExecuteJsSigning.ts | 2 +- ...SessionSigsToExecuteJsSigningInParallel.ts | 2 +- ...ActionCodeGeneratedSessionSigsToPkpSign.ts | 2 +- yarn.lock | 1527 ++++++++--------- 22 files changed, 733 insertions(+), 840 deletions(-) diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts index 77f3700308..c319e809e5 100644 --- a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts @@ -23,7 +23,7 @@ export const testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign devEnv.setUnavailable(LIT_TESTNET.CAYENNE); const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); - + const appOwnersCapacityDelegationAuthSig = await alice.createCapacityDelegationAuthSig(); diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts index a79276ac4a..840a8e0a9c 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts @@ -45,12 +45,10 @@ export const testUseEoaSessionSigsToEncryptDecryptString = async ( // -- assertions if (!encryptRes.ciphertext) { - throw new Error(`Expected "ciphertext" in encryptRes`); } if (!encryptRes.dataToEncryptHash) { - throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); } @@ -80,10 +78,8 @@ export const testUseEoaSessionSigsToEncryptDecryptString = async ( ); if (decryptRes !== 'Hello world') { - throw new Error( `Expected decryptRes to be 'Hello world' but got ${decryptRes}` ); } - }; diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts index 78cdb6b6f2..53d2c4ae37 100644 --- a/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimKeys.ts @@ -31,7 +31,6 @@ export const testUseEoaSessionSigsToExecuteJsClaimKeys = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts index 270f431905..eb10ff3d13 100644 --- a/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -21,7 +21,6 @@ export const testUseEoaSessionSigsToExecuteJsClaimMultipleKeys = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts index 5489c1ea8e..42ac64beeb 100644 --- a/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsJsonResponse.ts @@ -13,7 +13,7 @@ export const testUseEoaSessionSigsToExecuteJsJsonResponse = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.executeJs({ diff --git a/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts index 719c4154bf..e5c38682b6 100644 --- a/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts +++ b/local-tests/tests/testUseEoaSessionSigsToExecuteJsSigningInParallel.ts @@ -14,7 +14,7 @@ export const testUseEoaSessionSigsToExecuteJsSigningInParallel = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); const fn = async (index: number) => { diff --git a/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts b/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts index a0fb81fe4c..ae5d396788 100644 --- a/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseEoaSessionSigsToPkpSign.ts @@ -14,7 +14,7 @@ export const testUseEoaSessionSigsToPkpSign = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); const runWithSessionSigs = await devEnv.litNodeClient.pkpSign({ diff --git a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts index 3a809b7f21..791b64047e 100644 --- a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts +++ b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts @@ -14,7 +14,7 @@ export const testUseInvalidLitActionCodeToGenerateSessionSigs = async ( ) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); try { diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts index c3084c34fa..61648d5598 100644 --- a/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimKeys.ts @@ -23,7 +23,7 @@ export const testUsePkpSessionSigsToExecuteJsClaimKeys = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.executeJs({ diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts index a4de221f96..d218252fd8 100644 --- a/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -21,7 +21,7 @@ export const testUsePkpSessionSigsToExecuteJsClaimMultipleKeys = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.executeJs({ diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts index e5d18aeab7..211af2f0d6 100644 --- a/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsConsoleLog.ts @@ -13,7 +13,7 @@ export const testUsePkpSessionSigsToExecuteJsConsoleLog = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.executeJs({ diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts index dfee097b12..12a79fa9f7 100644 --- a/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsJsonResponse.ts @@ -13,7 +13,7 @@ export const testUsePkpSessionSigsToExecuteJsJsonResponse = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.executeJs({ diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts index 3e4145681b..0ddfdb2bb4 100644 --- a/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigning.ts @@ -14,7 +14,7 @@ export const testUsePkpSessionSigsToExecuteJsSigning = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.executeJs({ diff --git a/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts index 554f0ed1c6..796eef4732 100644 --- a/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts +++ b/local-tests/tests/testUsePkpSessionSigsToExecuteJsSigningInParallel.ts @@ -14,7 +14,7 @@ export const testUsePkpSessionSigsToExecuteJsSigningInParallel = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const fn = async (index: number) => { diff --git a/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts b/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts index f350628a7b..e08e60a23c 100644 --- a/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUsePkpSessionSigsToPkpSign.ts @@ -10,9 +10,11 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; * ✅ NETWORK=manzano yarn test:local --filter=testUsePkpSessionSigsToPkpSign * ✅ NETWORK=localchain yarn test:local --filter=testUsePkpSessionSigsToPkpSign */ -export const testUsePkpSessionSigsToPkpSign = async (devEnv: TinnyEnvironment) => { +export const testUsePkpSessionSigsToPkpSign = async ( + devEnv: TinnyEnvironment +) => { const alice = await devEnv.createRandomPerson(); - + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); const res = await devEnv.litNodeClient.pkpSign({ diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts index 638988e3b6..0606cac29b 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts @@ -23,7 +23,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys = async (devEnv: TinnyEnvironment) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ { diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts index 3fe3b2b482..4244e3be5e 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -21,7 +21,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultip async (devEnv: TinnyEnvironment) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts index c81bbf5929..c358f22d61 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts @@ -15,7 +15,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog async (devEnv: TinnyEnvironment) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts index 7f66deda66..345eebf948 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts @@ -16,7 +16,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning = async (devEnv: TinnyEnvironment) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ { diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts index 735e25f0b3..fbe8766817 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts @@ -14,7 +14,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInPa async (devEnv: TinnyEnvironment) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts index 603342f783..9ec3c85bf9 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts @@ -18,7 +18,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToPkpSign = async ( ) => { devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); - + const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); diff --git a/yarn.lock b/yarn.lock index 500b580f33..66ee163b86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2003,7 +2003,7 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== -"@gar/promisify@^1.1.3": +"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== @@ -2078,14 +2078,7 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@isaacs/fs-minipass@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" - integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== - dependencies: - minipass "^7.0.4" - -"@isaacs/string-locale-compare@*", "@isaacs/string-locale-compare@^1.1.0": +"@isaacs/string-locale-compare@^1.0.1", "@isaacs/string-locale-compare@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" integrity sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ== @@ -3517,46 +3510,6 @@ lru-cache "^10.0.1" socks-proxy-agent "^8.0.3" -"@npmcli/arborist@*", "@npmcli/arborist@^7.2.1": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-7.4.2.tgz#deb6eb3d88ab6913f0efeb4ebca64151d091d331" - integrity sha512-13flK0DTIhG7VEmPtoKFoi+88hIjuZxuZAvnHUTthIFql1Kc51VlsMRpbJPIcDEZHaHkILwFjHRXtCUYdFWvAQ== - dependencies: - "@isaacs/string-locale-compare" "^1.1.0" - "@npmcli/fs" "^3.1.0" - "@npmcli/installed-package-contents" "^2.0.2" - "@npmcli/map-workspaces" "^3.0.2" - "@npmcli/metavuln-calculator" "^7.0.0" - "@npmcli/name-from-folder" "^2.0.0" - "@npmcli/node-gyp" "^3.0.0" - "@npmcli/package-json" "^5.0.0" - "@npmcli/query" "^3.1.0" - "@npmcli/redact" "^1.1.0" - "@npmcli/run-script" "^7.0.2" - bin-links "^4.0.1" - cacache "^18.0.0" - common-ancestor-path "^1.0.1" - hosted-git-info "^7.0.1" - json-parse-even-better-errors "^3.0.0" - json-stringify-nice "^1.1.4" - minimatch "^9.0.4" - nopt "^7.0.0" - npm-install-checks "^6.2.0" - npm-package-arg "^11.0.1" - npm-pick-manifest "^9.0.0" - npm-registry-fetch "^16.2.0" - npmlog "^7.0.1" - pacote "^17.0.4" - parse-conflict-json "^3.0.0" - proc-log "^3.0.0" - promise-all-reject-late "^1.0.0" - promise-call-limit "^3.0.1" - read-package-json-fast "^3.0.2" - semver "^7.3.7" - ssri "^10.0.5" - treeverse "^3.0.0" - walk-up-path "^3.0.1" - "@npmcli/arborist@5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-5.3.0.tgz#321d9424677bfc08569e98a5ac445ee781f32053" @@ -3597,32 +3550,75 @@ treeverse "^2.0.0" walk-up-path "^1.0.0" -"@npmcli/ci-detect@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-3.0.2.tgz#facf5e48f553dd876cc9f5a749b269186ed7f7e6" - integrity sha512-P7nZG0skRVa9lH0OQmFG62CrzOySUiuPbKopjVAj3sXP0m1om9XfIvTp46h+NvlpTyd121JekiXFZj+1pnbm9g== - -"@npmcli/config@*": - version "8.2.2" - resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-8.2.2.tgz#7383559f04e753cad007c845defaacd0c47c6e30" - integrity sha512-VvMHPIzcsKHCaNh9h4kCbn7NyDtcNJFMOUZ8Wu9SWhds5Egr1gMGU2fv+M50P1V5iAUZWZcv2Iguo5HTckpzww== +"@npmcli/arborist@^2.3.0", "@npmcli/arborist@^2.5.0", "@npmcli/arborist@^2.9.0": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-2.10.0.tgz#424c2d73a7ae59c960b0cc7f74fed043e4316c2c" + integrity sha512-CLnD+zXG9oijEEzViimz8fbOoFVb7hoypiaf7p6giJhvYtrxLAyY3cZAMPIFQvsG731+02eMDp3LqVBNo7BaZA== dependencies: - "@npmcli/map-workspaces" "^3.0.2" - ci-info "^4.0.0" - ini "^4.1.2" - nopt "^7.0.0" - proc-log "^3.0.0" - read-package-json-fast "^3.0.2" + "@isaacs/string-locale-compare" "^1.0.1" + "@npmcli/installed-package-contents" "^1.0.7" + "@npmcli/map-workspaces" "^1.0.2" + "@npmcli/metavuln-calculator" "^1.1.0" + "@npmcli/move-file" "^1.1.0" + "@npmcli/name-from-folder" "^1.0.1" + "@npmcli/node-gyp" "^1.0.1" + "@npmcli/package-json" "^1.0.1" + "@npmcli/run-script" "^1.8.2" + bin-links "^2.2.1" + cacache "^15.0.3" + common-ancestor-path "^1.0.1" + json-parse-even-better-errors "^2.3.1" + json-stringify-nice "^1.1.4" + mkdirp "^1.0.4" + mkdirp-infer-owner "^2.0.0" + npm-install-checks "^4.0.0" + npm-package-arg "^8.1.5" + npm-pick-manifest "^6.1.0" + npm-registry-fetch "^11.0.0" + pacote "^11.3.5" + parse-conflict-json "^1.1.1" + proc-log "^1.0.0" + promise-all-reject-late "^1.0.0" + promise-call-limit "^1.0.1" + read-package-json-fast "^2.0.2" + readdir-scoped-modules "^1.1.0" + rimraf "^3.0.2" semver "^7.3.5" - walk-up-path "^3.0.1" + ssri "^8.0.1" + treeverse "^1.0.4" + walk-up-path "^1.0.0" -"@npmcli/disparity-colors@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/disparity-colors/-/disparity-colors-3.0.0.tgz#60ea8c6eb5ba9de2d1950e15b06205b2c3ab7833" - integrity sha512-5R/z157/f20Fi0Ou4ZttL51V0xz0EdPEOauFtPCEYOLInDBRCj1/TxOJ5aGTrtShxEshN2d+hXb9ZKSi5RLBcg== +"@npmcli/ci-detect@^1.2.0", "@npmcli/ci-detect@^1.3.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" + integrity sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q== + +"@npmcli/config@^2.3.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-2.4.0.tgz#1447b0274f9502871dabd3ab1d8302472d515b1f" + integrity sha512-fwxu/zaZnvBJohXM3igzqa3P1IVYWi5N343XcKvKkJbAx+rTqegS5tAul4NLiMPQh6WoS5a4er6oo/ieUx1f4g== + dependencies: + ini "^2.0.0" + mkdirp-infer-owner "^2.0.0" + nopt "^5.0.0" + semver "^7.3.4" + walk-up-path "^1.0.0" + +"@npmcli/disparity-colors@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/disparity-colors/-/disparity-colors-1.0.1.tgz#b23c864c9658f9f0318d5aa6d17986619989535c" + integrity sha512-kQ1aCTTU45mPXN+pdAaRxlxr3OunkyztjbbxDY/aIcPS5CnCUrx+1+NvA6pTcYR7wmLZe37+Mi5v3nfbwPxq3A== dependencies: ansi-styles "^4.3.0" +"@npmcli/fs@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" + integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + "@npmcli/fs@^2.1.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" @@ -3638,6 +3634,20 @@ dependencies: semver "^7.3.5" +"@npmcli/git@^2.0.7", "@npmcli/git@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" + integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== + dependencies: + "@npmcli/promise-spawn" "^1.3.2" + lru-cache "^6.0.0" + mkdirp "^1.0.4" + npm-pick-manifest "^6.1.1" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.5" + which "^2.0.2" + "@npmcli/git@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-3.0.2.tgz#5c5de6b4d70474cf2d09af149ce42e4e1dacb931" @@ -3653,21 +3663,7 @@ semver "^7.3.5" which "^2.0.2" -"@npmcli/git@^5.0.0", "@npmcli/git@^5.0.3": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-5.0.6.tgz#d7b24eb2cff98754c8868faab40405abfa1abe28" - integrity sha512-4x/182sKXmQkf0EtXxT26GEsaOATpD7WVtza5hrYivWZeo6QefC6xq9KAXrnjtFKBZ4rZwR7aX/zClYYXgtwLw== - dependencies: - "@npmcli/promise-spawn" "^7.0.0" - lru-cache "^10.0.1" - npm-pick-manifest "^9.0.0" - proc-log "^4.0.0" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^4.0.0" - -"@npmcli/installed-package-contents@^1.0.7": +"@npmcli/installed-package-contents@^1.0.6", "@npmcli/installed-package-contents@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== @@ -3675,23 +3671,15 @@ npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -"@npmcli/installed-package-contents@^2.0.1", "@npmcli/installed-package-contents@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33" - integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ== - dependencies: - npm-bundled "^3.0.0" - npm-normalize-package-bin "^3.0.0" - -"@npmcli/map-workspaces@*", "@npmcli/map-workspaces@^3.0.2": - version "3.0.6" - resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz#27dc06c20c35ef01e45a08909cab9cb3da08cea6" - integrity sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA== +"@npmcli/map-workspaces@^1.0.2", "@npmcli/map-workspaces@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-1.0.4.tgz#915708b55afa25e20bc2c14a766c124c2c5d4cab" + integrity sha512-wVR8QxhyXsFcD/cORtJwGQodeeaDf0OxcHie8ema4VgFeqwYkFsDPnSrIRSytX8xR6nKPAH89WnwTcaU608b/Q== dependencies: - "@npmcli/name-from-folder" "^2.0.0" - glob "^10.2.2" - minimatch "^9.0.0" - read-package-json-fast "^3.0.0" + "@npmcli/name-from-folder" "^1.0.1" + glob "^7.1.6" + minimatch "^3.0.4" + read-package-json-fast "^2.0.1" "@npmcli/map-workspaces@^2.0.3": version "2.0.4" @@ -3703,6 +3691,15 @@ minimatch "^5.0.1" read-package-json-fast "^2.0.3" +"@npmcli/metavuln-calculator@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-1.1.1.tgz#2f95ff3c6d88b366dd70de1c3f304267c631b458" + integrity sha512-9xe+ZZ1iGVaUovBVFI9h3qW+UuECUzhvZPxK9RaEA2mjU26o5D0JloGYWwLYvQELJNmBdQB6rrpuN8jni6LwzQ== + dependencies: + cacache "^15.0.5" + pacote "^11.1.11" + semver "^7.3.2" + "@npmcli/metavuln-calculator@^3.0.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz#9359bd72b400f8353f6a28a25c8457b562602622" @@ -3713,16 +3710,13 @@ pacote "^13.0.3" semver "^7.3.5" -"@npmcli/metavuln-calculator@^7.0.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.0.tgz#70aad00623d47297cd2c950a686ef4220e4a9040" - integrity sha512-D4VZzVLZ4Mw+oUCWyQ6qzlm5SGlrLnhKtZscDwQXFFc1FUPvw69Ibo2E5ZpJAmjFSYkA5UlCievWmREW0JLC3w== +"@npmcli/move-file@^1.0.1", "@npmcli/move-file@^1.1.0": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== dependencies: - cacache "^18.0.0" - json-parse-even-better-errors "^3.0.0" - pacote "^18.0.0" - proc-log "^4.1.0" - semver "^7.3.5" + mkdirp "^1.0.4" + rimraf "^3.0.2" "@npmcli/move-file@^2.0.0": version "2.0.1" @@ -3737,33 +3731,22 @@ resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz#77ecd0a4fcb772ba6fe927e2e2e155fbec2e6b1a" integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== -"@npmcli/name-from-folder@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz#c44d3a7c6d5c184bb6036f4d5995eee298945815" - integrity sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg== +"@npmcli/node-gyp@^1.0.1", "@npmcli/node-gyp@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" + integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== "@npmcli/node-gyp@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz#8c20e53e34e9078d18815c1d2dda6f2420d75e35" integrity sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A== -"@npmcli/node-gyp@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a" - integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA== - -"@npmcli/package-json@*", "@npmcli/package-json@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-5.1.0.tgz#10d117b5fb175acc14c70901a151c52deffc843e" - integrity sha512-1aL4TuVrLS9sf8quCLerU3H9J4vtCtgu8VauYozrmEyU57i/EdKleCnsQ7vpnABIH6c9mnTxcH5sFkO3BlV8wQ== +"@npmcli/package-json@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-1.0.1.tgz#1ed42f00febe5293c3502fd0ef785647355f6e89" + integrity sha512-y6jnu76E9C23osz8gEMBayZmaZ69vFOIk8vR1FJL/wbEJ54+9aVG9rLTjQKSXfgYZEr50nw1txBBFfBZZe+bYg== dependencies: - "@npmcli/git" "^5.0.0" - glob "^10.2.2" - hosted-git-info "^7.0.0" - json-parse-even-better-errors "^3.0.0" - normalize-package-data "^6.0.0" - proc-log "^4.0.0" - semver "^7.5.3" + json-parse-even-better-errors "^2.3.1" "@npmcli/package-json@^2.0.0": version "2.0.0" @@ -3772,6 +3755,13 @@ dependencies: json-parse-even-better-errors "^2.3.1" +"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" + integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== + dependencies: + infer-owner "^1.0.4" + "@npmcli/promise-spawn@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz#53283b5f18f855c6925f23c24e67c911501ef573" @@ -3779,36 +3769,15 @@ dependencies: infer-owner "^1.0.4" -"@npmcli/promise-spawn@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz#a836de2f42a2245d629cf6fbb8dd6c74c74c55af" - integrity sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg== - dependencies: - which "^4.0.0" - -"@npmcli/query@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/query/-/query-3.1.0.tgz#bc202c59e122a06cf8acab91c795edda2cdad42c" - integrity sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ== +"@npmcli/run-script@^1.8.2", "@npmcli/run-script@^1.8.3", "@npmcli/run-script@^1.8.4", "@npmcli/run-script@^1.8.6": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" + integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== dependencies: - postcss-selector-parser "^6.0.10" - -"@npmcli/redact@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/redact/-/redact-1.1.0.tgz#78e53a6a34f013543a73827a07ebdc3a6f10454b" - integrity sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ== - -"@npmcli/run-script@*", "@npmcli/run-script@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-8.0.0.tgz#644f8e28fd3cde25e40a79d3b35cb14076ec848b" - integrity sha512-5noc+eCQmX1W9nlFUe65n5MIteikd3vOA2sEPdXtlUv68KWyHNFZnT/LDRXu/E4nZ5yxjciP30pADr/GQ97W1w== - dependencies: - "@npmcli/node-gyp" "^3.0.0" - "@npmcli/package-json" "^5.0.0" - "@npmcli/promise-spawn" "^7.0.0" - node-gyp "^10.0.0" - proc-log "^4.0.0" - which "^4.0.0" + "@npmcli/node-gyp" "^1.0.2" + "@npmcli/promise-spawn" "^1.3.2" + node-gyp "^7.1.0" + read-package-json-fast "^2.0.1" "@npmcli/run-script@^4.1.0", "@npmcli/run-script@^4.1.3", "@npmcli/run-script@^4.1.7": version "4.2.1" @@ -3821,17 +3790,6 @@ read-package-json-fast "^2.0.3" which "^2.0.2" -"@npmcli/run-script@^7.0.0", "@npmcli/run-script@^7.0.2": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-7.0.4.tgz#9f29aaf4bfcf57f7de2a9e28d1ef091d14b2e6eb" - integrity sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg== - dependencies: - "@npmcli/node-gyp" "^3.0.0" - "@npmcli/package-json" "^5.0.0" - "@npmcli/promise-spawn" "^7.0.0" - node-gyp "^10.0.0" - which "^4.0.0" - "@nrwl/cli@15.9.7": version "15.9.7" resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-15.9.7.tgz#1db113f5cb1cfe63213097be1ece041eef33da1f" @@ -4849,50 +4807,6 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== -"@sigstore/bundle@^2.3.0", "@sigstore/bundle@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-2.3.1.tgz#f6cdc67c8400e58ca27f0ef495b27a9327512073" - integrity sha512-eqV17lO3EIFqCWK3969Rz+J8MYrRZKw9IBHpSo6DEcEX2c+uzDFOgHE9f2MnyDpfs48LFO4hXmk9KhQ74JzU1g== - dependencies: - "@sigstore/protobuf-specs" "^0.3.1" - -"@sigstore/core@^1.0.0", "@sigstore/core@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@sigstore/core/-/core-1.1.0.tgz#5583d8f7ffe599fa0a89f2bf289301a5af262380" - integrity sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg== - -"@sigstore/protobuf-specs@^0.3.0", "@sigstore/protobuf-specs@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.3.1.tgz#7095819fa7c5743efde48a858c37b30fab190a09" - integrity sha512-aIL8Z9NsMr3C64jyQzE0XlkEyBLpgEJJFDHLVVStkFV5Q3Il/r/YtY6NJWKQ4cy4AE7spP1IX5Jq7VCAxHHMfQ== - -"@sigstore/sign@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@sigstore/sign/-/sign-2.3.0.tgz#c35e10a3d707e0c69a29bd9f93fa2bdc6275817c" - integrity sha512-tsAyV6FC3R3pHmKS880IXcDJuiFJiKITO1jxR1qbplcsBkZLBmjrEw5GbC7ikD6f5RU1hr7WnmxB/2kKc1qUWQ== - dependencies: - "@sigstore/bundle" "^2.3.0" - "@sigstore/core" "^1.0.0" - "@sigstore/protobuf-specs" "^0.3.1" - make-fetch-happen "^13.0.0" - -"@sigstore/tuf@^2.3.1": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@sigstore/tuf/-/tuf-2.3.2.tgz#e9c5bffc2a5f3434f87195902d7f9cd7f48c70fa" - integrity sha512-mwbY1VrEGU4CO55t+Kl6I7WZzIl+ysSzEYdA1Nv/FTrl2bkeaPXo5PnWZAVfcY2zSdhOpsUTJW67/M2zHXGn5w== - dependencies: - "@sigstore/protobuf-specs" "^0.3.0" - tuf-js "^2.2.0" - -"@sigstore/verify@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@sigstore/verify/-/verify-1.2.0.tgz#48549186305d8a5e471a3a304cf4cb3e0c99dde7" - integrity sha512-hQF60nc9yab+Csi4AyoAmilGNfpXT+EXdBgFkP9OgPwIBPwyqVf7JAWPtmqrrrneTmAT6ojv7OlH1f6Ix5BG4Q== - dependencies: - "@sigstore/bundle" "^2.3.1" - "@sigstore/core" "^1.1.0" - "@sigstore/protobuf-specs" "^0.3.1" - "@simplewebauthn/browser@^7.2.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@simplewebauthn/browser/-/browser-7.4.0.tgz#3e25b5e9f45d03eb60d3e4f8812d8d2acfd7dba6" @@ -5583,19 +5497,6 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@tufjs/canonical-json@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a" - integrity sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA== - -"@tufjs/models@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-2.0.0.tgz#c7ab241cf11dd29deb213d6817dabb8c99ce0863" - integrity sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg== - dependencies: - "@tufjs/canonical-json" "2.0.0" - minimatch "^9.0.3" - "@typechain/ethers-v5@^11.1.1": version "11.1.2" resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-11.1.2.tgz#82510c1744f37a2f906b9e0532ac18c0b74ffe69" @@ -6817,16 +6718,16 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abbrev@*, abbrev@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" - integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== - -abbrev@1, abbrev@^1.0.0: +abbrev@1, abbrev@^1.0.0, abbrev@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + abi-decoder@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/abi-decoder/-/abi-decoder-2.3.0.tgz#e56b4e7b45f9a612c8aa2c76655948e7bb2687b3" @@ -6937,7 +6838,7 @@ agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: dependencies: debug "^4.3.4" -agentkeepalive@^4.2.1: +agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== @@ -7079,12 +6980,12 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -ansicolors@*, ansicolors@~0.3.2: +ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== -ansistyles@*: +ansistyles@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" integrity sha512-6QWEyvMgIXX0eO972y7YPBLSBsq7UWKFAoNNTLGaOJ9bstcEL9sCbcjf96dVfNDdUsRoGOK82vWFJlKApXds7g== @@ -7129,6 +7030,11 @@ append-transform@^2.0.0: dependencies: default-require-extensions "^3.0.0" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + "aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" @@ -7146,11 +7052,19 @@ archive-type@^4.0.0: dependencies: file-type "^4.2.0" -archy@*, archy@^1.0.0: +archy@^1.0.0, archy@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + are-we-there-yet@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" @@ -7159,10 +7073,13 @@ are-we-there-yet@^3.0.0: delegates "^1.0.0" readable-stream "^3.6.0" -are-we-there-yet@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-4.0.2.tgz#aed25dd0eae514660d49ac2b2366b175c614785a" - integrity sha512-ncSWAawFhKMJDTdoAeOV+jyW1VCMj5QIAwULIBV0SSR7B/RLPPEQiknKcg/RIIZlUQrxELpsxMiTUoAQ4sIUyg== +are-we-there-yet@~1.1.2: + version "1.1.7" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" arg@5.0.2, arg@^5.0.2: version "5.0.2" @@ -8442,6 +8359,18 @@ bignumber.js@^9.0.0, bignumber.js@^9.0.1: resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== +bin-links@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-2.3.0.tgz#1ff241c86d2c29b24ae52f49544db5d78a4eb967" + integrity sha512-JzrOLHLwX2zMqKdyYZjkDgQGT+kHDkIhv2/IK2lJ00qLxV4TmFoHi8drDBb6H5Zrz1YfgHkai4e2MGPqnoUhqA== + dependencies: + cmd-shim "^4.0.1" + mkdirp-infer-owner "^2.0.0" + npm-normalize-package-bin "^1.0.0" + read-cmd-shim "^2.0.0" + rimraf "^3.0.0" + write-file-atomic "^3.0.3" + bin-links@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-3.0.3.tgz#3842711ef3db2cd9f16a5f404a996a12db355a6e" @@ -8454,22 +8383,12 @@ bin-links@^3.0.0: rimraf "^3.0.0" write-file-atomic "^4.0.0" -bin-links@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.3.tgz#9e4a3c5900830aee3d7f52178b65e01dcdde64a5" - integrity sha512-obsRaULtJurnfox/MDwgq6Yo9kzbv1CPTk/1/s7Z/61Lezc8IKkFCOXNeVLXz0456WRzBQmSsDWlai2tIhBsfA== - dependencies: - cmd-shim "^6.0.0" - npm-normalize-package-bin "^3.0.0" - read-cmd-shim "^4.0.0" - write-file-atomic "^5.0.0" - binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== -binary-extensions@^2.0.0, binary-extensions@^2.3.0: +binary-extensions@^2.0.0, binary-extensions@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== @@ -8938,23 +8857,29 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@*, cacache@^18.0.0: - version "18.0.2" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.2.tgz#fd527ea0f03a603be5c0da5805635f8eef00c60c" - integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== +cacache@^15.0.3, cacache@^15.0.5, cacache@^15.2.0, cacache@^15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== dependencies: - "@npmcli/fs" "^3.1.0" - fs-minipass "^3.0.0" - glob "^10.2.2" - lru-cache "^10.0.1" - minipass "^7.0.3" - minipass-collect "^2.0.1" + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" p-map "^4.0.0" - ssri "^10.0.0" - tar "^6.1.11" - unique-filename "^3.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: version "16.1.3" @@ -8980,6 +8905,24 @@ cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" +cacache@^18.0.0: + version "18.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.2.tgz#fd527ea0f03a603be5c0da5805635f8eef00c60c" + integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -9175,11 +9118,6 @@ chalk-template@0.4.0: dependencies: chalk "^4.1.2" -chalk@*, chalk@^5.0.1, chalk@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - chalk@4.1.2, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -9221,6 +9159,11 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.0.1, chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + chance@^1.1.4: version "1.1.11" resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.11.tgz#78e10e1f9220a5bbc60a83e3f28a5d8558d84d1b" @@ -9331,11 +9274,6 @@ chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.7" -chownr@*, chownr@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" - integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== - chownr@^1.1.1, chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -9356,17 +9294,12 @@ ci-info@^3.2.0, ci-info@^3.4.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -ci-info@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" - integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== - -cidr-regex@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-4.0.5.tgz#c90181992feb60ce28b8cc7590970ab94ab1060a" - integrity sha512-gljhROSwEnEvC+2lKqfkv1dU2v46h8Cwob19LlfGeGRMDLuwFD5+3D6+/vaa9/QrVLDASiSQ2OYQwzzjQ5I57A== +cidr-regex@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-3.1.1.tgz#ba1972c57c66f61875f18fd7dd487469770b571d" + integrity sha512-RBqYd32aDwbCMFJRL6wHOlDNYJsPNTt8vC82ErHF5vKt8QQzxm1FrkW8s/R5pVrXMf17sba09Uoy91PKiddAsw== dependencies: - ip-regex "^5.0.0" + ip-regex "^4.1.0" cids@^0.7.1: version "0.7.5" @@ -9450,13 +9383,13 @@ cli-boxes@^3.0.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== -cli-columns@*: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-4.0.0.tgz#9fe4d65975238d55218c41bd2ed296a7fa555646" - integrity sha512-XW2Vg+w+L9on9wtwKpyzluIPCWXjaBahI7mTcYjx+BVIYD9c3yqcv/yKC7CmdCZat4rq2yiE1UMSJC5ivKfMtQ== +cli-columns@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e" + integrity sha512-iQYpDgpPPmCjn534ikQOhi+ydP6uMar+DtJ6a0In4aGL/PKqWfao75s6eF81quQQaz7isGz+goNECLARRZswdg== dependencies: - string-width "^4.2.3" - strip-ansi "^6.0.1" + string-width "^2.0.0" + strip-ansi "^3.0.1" cli-cursor@3.1.0, cli-cursor@^3.1.0: version "3.1.0" @@ -9482,7 +9415,7 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== -cli-table3@*, cli-table3@^0.6.0, cli-table3@~0.6.0, cli-table3@~0.6.1: +cli-table3@^0.6.0, cli-table3@~0.6.0, cli-table3@~0.6.1: version "0.6.4" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.4.tgz#d1c536b8a3f2e7bec58f67ac9e5769b1b30088b0" integrity sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw== @@ -9615,6 +9548,13 @@ clsx@^1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +cmd-shim@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" + integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== + dependencies: + mkdirp-infer-owner "^2.0.0" + cmd-shim@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-5.0.0.tgz#8d0aaa1a6b0708630694c4dbde070ed94c707724" @@ -9622,11 +9562,6 @@ cmd-shim@^5.0.0: dependencies: mkdirp-infer-owner "^2.0.0" -cmd-shim@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.2.tgz#435fd9e5c95340e61715e19f90209ed6fcd9e0a4" - integrity sha512-+FFYbB0YLaAkhkcrjkyNLYDiOsFSfRjwjY19LXk/psmMx1z00xlCv7hhQoTGXXIKi+YXHL/iiFo8NqMVQX9nOw== - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -9682,7 +9617,7 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.3: +color-support@^1.1.2, color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== @@ -9697,7 +9632,7 @@ colors@1.4.0, colors@^1.4.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -columnify@*, columnify@^1.6.0: +columnify@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== @@ -9705,6 +9640,14 @@ columnify@*, columnify@^1.6.0: strip-ansi "^6.0.1" wcwidth "^1.0.0" +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + integrity sha512-rFl+iXVT1nhLQPfGDw+3WcS8rmm7XsLKUmhsGE3ihzzpIikeGrTaZPIRKYWeLsLBypsHzjXIvYEltVUZS84XxQ== + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -9922,7 +9865,7 @@ console-browserify@^1.2.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.1.0: +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== @@ -10363,11 +10306,6 @@ css-what@^6.0.1, css-what@^6.1.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - csso@^5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" @@ -11142,7 +11080,7 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.1.0: +diff@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== @@ -11514,7 +11452,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encoding@^0.1.11, encoding@^0.1.13: +encoding@^0.1.11, encoding@^0.1.12, encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -13370,7 +13308,7 @@ fast-url-parser@1.1.3, fast-url-parser@^1.1.3: dependencies: punycode "^1.3.2" -fastest-levenshtein@*: +fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== @@ -13924,6 +13862,21 @@ g@^2.0.1: resolved "https://registry.yarnpkg.com/g/-/g-2.0.1.tgz#0b5963ebd0ca70e3bc8c6766934a021821c8b857" integrity sha512-Fi6Ng5fZ/ANLQ15H11hCe+09sgUoNvDEBevVgx3KoYOhsH5iLNPn54hx0jPZ+3oSWr+xajnp2Qau9VmPsc7hTA== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gauge@^4.0.3: version "4.0.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" @@ -13938,19 +13891,19 @@ gauge@^4.0.3: strip-ansi "^6.0.1" wide-align "^1.1.5" -gauge@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-5.0.1.tgz#1efc801b8ff076b86ef3e9a7a280a975df572112" - integrity sha512-CmykPMJGuNan/3S4kZOpvvPYSNqSHANiWnh9XcMU2pSjtBfF0XzZ2p1bFAxTbnFxyBuPxQYHhzwaoOmUdqzvxQ== +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.3" - console-control-strings "^1.1.0" - has-unicode "^2.0.1" - signal-exit "^4.0.1" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.5" + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -14188,17 +14141,6 @@ glob-slasher@^1.0.1: lodash.isobject "^2.4.1" toxic "^1.0.0" -glob@*, glob@^10.2.2, glob@^10.3.10, glob@^10.3.7: - version "10.3.12" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" - integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.6" - minimatch "^9.0.1" - minipass "^7.0.4" - path-scurry "^1.10.2" - glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -14223,6 +14165,17 @@ glob@7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.2.2, glob@^10.3.10: + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0, glob@~7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -14431,7 +14384,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@*, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.8, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -14555,7 +14508,7 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" -has-unicode@^2.0.1: +has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== @@ -14718,13 +14671,6 @@ hook-std@^2.0.0: resolved "https://registry.yarnpkg.com/hook-std/-/hook-std-2.0.0.tgz#ff9aafdebb6a989a354f729bb6445cf4a3a7077c" integrity sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g== -hosted-git-info@*, hosted-git-info@^7.0.0, hosted-git-info@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" - integrity sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA== - dependencies: - lru-cache "^10.0.1" - hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -14737,7 +14683,7 @@ hosted-git-info@^3.0.6: dependencies: lru-cache "^6.0.0" -hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: +hosted-git-info@^4.0.0, hosted-git-info@^4.0.1, hosted-git-info@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== @@ -14751,6 +14697,13 @@ hosted-git-info@^5.0.0: dependencies: lru-cache "^7.5.1" +hosted-git-info@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" + integrity sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA== + dependencies: + lru-cache "^10.0.1" + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -15103,6 +15056,13 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== +ignore-walk@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== + dependencies: + minimatch "^3.0.4" + ignore-walk@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" @@ -15110,13 +15070,6 @@ ignore-walk@^5.0.1: dependencies: minimatch "^5.0.1" -ignore-walk@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9" - integrity sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw== - dependencies: - minimatch "^9.0.0" - ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -15198,17 +15151,12 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -ini@*, ini@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.2.tgz#7f646dbd9caea595e61f88ef60bfff8b01f8130a" - integrity sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw== - ini@1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== -ini@2.0.0: +ini@2.0.0, ini@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== @@ -15218,18 +15166,18 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -init-package-json@*: - version "6.0.2" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-6.0.2.tgz#0d780b752dd1dd83b8649945df38a07df4f990a6" - integrity sha512-ZQ9bxt6PkqIH6fPU69HPheOMoUqIqVqwZj0qlCBfoSCG4lplQhVM/qB3RS4f0RALK3WZZSrNQxNtCZgphuf3IA== +init-package-json@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.5.tgz#78b85f3c36014db42d8f32117252504f68022646" + integrity sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA== dependencies: - "@npmcli/package-json" "^5.0.0" - npm-package-arg "^11.0.0" - promzard "^1.0.0" - read "^3.0.1" + npm-package-arg "^8.1.5" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "^4.1.1" semver "^7.3.5" validate-npm-package-license "^3.0.4" - validate-npm-package-name "^5.0.0" + validate-npm-package-name "^3.0.0" init-package-json@^3.0.2: version "3.0.2" @@ -15357,10 +15305,10 @@ ip-address@^9.0.5: jsbn "1.1.0" sprintf-js "^1.1.3" -ip-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-5.0.0.tgz#cd313b2ae9c80c07bd3851e12bf4fa4dc5480632" - integrity sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw== +ip-regex@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== ipaddr.js@1.9.1: version "1.9.1" @@ -15477,12 +15425,12 @@ is-ci@^3.0.0, is-ci@^3.0.1: dependencies: ci-info "^3.2.0" -is-cidr@*: - version "5.0.5" - resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-5.0.5.tgz#6898e3e84a320cecaa505654b33463399baf9e8e" - integrity sha512-zDlCvz2v8dBpumuGD4/fc7wzFKY6UYOvFW29JWSstdJoByGN3TKwS0tFA9VWc7DM01VOVOn/DaR84D8Mihp9Rg== +is-cidr@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-4.0.2.tgz#94c7585e4c6c77ceabf920f8cde51b8c0fda8814" + integrity sha512-z4a1ENUajDbEl/Q6/pVBpTR1nBjjEE1X7qb7bmWYanNnPoKAvUCPFKeXV6Fe4mgTkWKBqiHIcwsI3SndiO5FeA== dependencies: - cidr-regex "^4.0.4" + cidr-regex "^3.1.1" is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.6.0, is-core-module@^2.8.1: version "2.13.1" @@ -17020,11 +16968,6 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-parse-even-better-errors@*, json-parse-even-better-errors@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz#02bb29fb5da90b5444581749c22cedd3597c6cb0" - integrity sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg== - json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -17220,21 +17163,26 @@ jszip@^3.10.1: readable-stream "~2.3.6" setimmediate "^1.0.5" +just-diff-apply@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-3.1.2.tgz#710d8cda00c65dc4e692df50dbe9bac5581c2193" + integrity sha512-TCa7ZdxCeq6q3Rgms2JCRHTCfWAETPZ8SzYUbkYF6KR3I03sN29DaOIC+xyWboIcMvjAsD5iG2u/RWzHD8XpgQ== + just-diff-apply@^5.2.0: version "5.5.0" resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.5.0.tgz#771c2ca9fa69f3d2b54e7c3f5c1dfcbcc47f9f0f" integrity sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw== +just-diff@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-3.1.1.tgz#d50c597c6fd4776495308c63bdee1b6839082647" + integrity sha512-sdMWKjRq8qWZEjDcVA6llnUT8RDEBIfOiGpYFPYa9u+2c39JCsejktSP7mj5eRid5EIvTzIpQ2kDOCw1Nq9BjQ== + just-diff@^5.0.1: version "5.2.0" resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241" integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw== -just-diff@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-6.0.2.tgz#03b65908543ac0521caf6d8eb85035f7d27ea285" - integrity sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA== - keccak@^1.0.2: version "1.4.0" resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" @@ -17442,13 +17390,15 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libnpmaccess@*: - version "8.0.3" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-8.0.3.tgz#7377b2fa07f722cb68a29e1e31f19972cf01f5e0" - integrity sha512-0dU2ZZ8eWrI3JcPIEA5wnQ5s+OGeNtjrg0MHz1vcs06hRLDhZeXBWthuXG47jV1GO5ogClQi7RAFNAWVEjViWw== +libnpmaccess@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" + integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== dependencies: - npm-package-arg "^11.0.1" - npm-registry-fetch "^16.2.0" + aproba "^2.0.0" + minipass "^3.1.1" + npm-package-arg "^8.1.2" + npm-registry-fetch "^11.0.0" libnpmaccess@^6.0.3: version "6.0.4" @@ -17460,84 +17410,79 @@ libnpmaccess@^6.0.3: npm-package-arg "^9.0.1" npm-registry-fetch "^13.0.0" -libnpmdiff@*: - version "6.0.9" - resolved "https://registry.yarnpkg.com/libnpmdiff/-/libnpmdiff-6.0.9.tgz#7a8a1bfd5209342e852c5ee65d604b57a6c19dbe" - integrity sha512-K3Ey7VFXkasHOHa9S8SbALRMMEJkx5cHdAitJoLZH4pPL2cX89hdkNTQi8vcvjOlENbE2AjNsSjRkGhzeKfiSA== - dependencies: - "@npmcli/arborist" "^7.2.1" - "@npmcli/disparity-colors" "^3.0.0" - "@npmcli/installed-package-contents" "^2.0.2" - binary-extensions "^2.3.0" - diff "^5.1.0" - minimatch "^9.0.4" - npm-package-arg "^11.0.1" - pacote "^17.0.4" - tar "^6.2.1" - -libnpmexec@*: - version "7.0.10" - resolved "https://registry.yarnpkg.com/libnpmexec/-/libnpmexec-7.0.10.tgz#dd41dddaf5987a59e067e686d10b5189a9302065" - integrity sha512-MwjY0SzG9pHBMW+Otl/6ZA2s4kRUYxelo9vIKeWHG3CV0b/4mzi88rYNk3fv46hQ4ypIIEZYOzV/pHky/DS8og== - dependencies: - "@npmcli/arborist" "^7.2.1" - "@npmcli/run-script" "^7.0.2" - ci-info "^4.0.0" - npm-package-arg "^11.0.1" - npmlog "^7.0.1" - pacote "^17.0.4" - proc-log "^3.0.0" - read "^3.0.1" - read-package-json-fast "^3.0.2" - semver "^7.3.7" - walk-up-path "^3.0.1" +libnpmdiff@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/libnpmdiff/-/libnpmdiff-2.0.4.tgz#bb1687992b1a97a8ea4a32f58ad7c7f92de53b74" + integrity sha512-q3zWePOJLHwsLEUjZw3Kyu/MJMYfl4tWCg78Vl6QGSfm4aXBUSVzMzjJ6jGiyarsT4d+1NH4B1gxfs62/+y9iQ== + dependencies: + "@npmcli/disparity-colors" "^1.0.1" + "@npmcli/installed-package-contents" "^1.0.7" + binary-extensions "^2.2.0" + diff "^5.0.0" + minimatch "^3.0.4" + npm-package-arg "^8.1.1" + pacote "^11.3.0" + tar "^6.1.0" -libnpmfund@*: - version "5.0.7" - resolved "https://registry.yarnpkg.com/libnpmfund/-/libnpmfund-5.0.7.tgz#0ac10dc7e554f3ba596089557d6f2dd6a35664b1" - integrity sha512-wRQSh2AeXFUtfHBciYha7m2+0xhX9PWa+ufMlfUFtUm6yTNsgghoZe8dciERklwhh2iax/9I+O/1lqKsGvJBaQ== +libnpmexec@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/libnpmexec/-/libnpmexec-2.0.1.tgz#729ae3e15a3ba225964ccf248117a75d311eeb73" + integrity sha512-4SqBB7eJvJWmUKNF42Q5qTOn20DRjEE4TgvEh2yneKlAiRlwlhuS9MNR45juWwmoURJlf2K43bozlVt7OZiIOw== dependencies: - "@npmcli/arborist" "^7.2.1" + "@npmcli/arborist" "^2.3.0" + "@npmcli/ci-detect" "^1.3.0" + "@npmcli/run-script" "^1.8.4" + chalk "^4.1.0" + mkdirp-infer-owner "^2.0.0" + npm-package-arg "^8.1.2" + pacote "^11.3.1" + proc-log "^1.0.0" + read "^1.0.7" + read-package-json-fast "^2.0.2" + walk-up-path "^1.0.0" -libnpmhook@*: - version "10.0.2" - resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-10.0.2.tgz#1528c6c8120bf97523bc1671dc49b48b96170c89" - integrity sha512-LF5peX3rmk2HqABmMXWhjdJ+HHHPIwMz7NXUM67MLSIy+JAExTymcQZgbGM9m/YQ6JDRPW8SBhWeWM0+vPNezw== +libnpmfund@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/libnpmfund/-/libnpmfund-1.1.0.tgz#ee91313905b3194b900530efa339bc3f9fc4e5c4" + integrity sha512-Kfmh3pLS5/RGKG5WXEig8mjahPVOxkik6lsbH4iX0si1xxNi6eeUh/+nF1MD+2cgalsQif3O5qyr6mNz2ryJrQ== dependencies: - aproba "^2.0.0" - npm-registry-fetch "^16.2.0" + "@npmcli/arborist" "^2.5.0" -libnpmorg@*: +libnpmhook@^6.0.2: version "6.0.3" - resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-6.0.3.tgz#6c2af127fc54e965800c53ace0b3e6e55a8a2d21" - integrity sha512-oxyQjJqvhvi0YqCOHQWLfWWre7NtWOGghX29LhhaqcDv3+Q61c4lJbht/iEEd00eucuHPjqfeh4aWXP6ftj2aA== + resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-6.0.3.tgz#1d7f0d7e6a7932fbf7ce0881fdb0ed8bf8748a30" + integrity sha512-3fmkZJibIybzmAvxJ65PeV3NzRc0m4xmYt6scui5msocThbEp4sKFT80FhgrCERYDjlUuFahU6zFNbJDHbQ++g== dependencies: aproba "^2.0.0" - npm-registry-fetch "^16.2.0" + npm-registry-fetch "^11.0.0" -libnpmpack@*: - version "6.0.9" - resolved "https://registry.yarnpkg.com/libnpmpack/-/libnpmpack-6.0.9.tgz#c1e42cef93d46c9f31e015c298232fff15bbb734" - integrity sha512-rkGVbP0amt7qNPL/u4NbH0MqhECRrvdRPcszXalYc6TP2ubEBPT54c5LFLxTLROSKjfre6PVvzc1ZNKc8jBWhQ== +libnpmorg@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-2.0.3.tgz#4e605d4113dfa16792d75343824a0625c76703bc" + integrity sha512-JSGl3HFeiRFUZOUlGdiNcUZOsUqkSYrg6KMzvPZ1WVZ478i47OnKSS0vkPmX45Pai5mTKuwIqBMcGWG7O8HfdA== dependencies: - "@npmcli/arborist" "^7.2.1" - "@npmcli/run-script" "^7.0.2" - npm-package-arg "^11.0.1" - pacote "^17.0.4" + aproba "^2.0.0" + npm-registry-fetch "^11.0.0" -libnpmpublish@*: - version "9.0.5" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-9.0.5.tgz#39e06b94fa140ae733e7ad0cdbbdc385ab31728e" - integrity sha512-MSKHZN2NXmp8GafDMy2eH/FK6c0BjpCbuJ4vJU4xPqCguy0w805VoRnsCwxyrvzCC13MB2tU6VOAX08GioINBA== +libnpmpack@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/libnpmpack/-/libnpmpack-2.0.1.tgz#d3eac25cc8612f4e7cdeed4730eee339ba51c643" + integrity sha512-He4/jxOwlaQ7YG7sIC1+yNeXeUDQt8RLBvpI68R3RzPMZPa4/VpxhlDo8GtBOBDYoU8eq6v1wKL38sq58u4ibQ== dependencies: - ci-info "^4.0.0" - normalize-package-data "^6.0.0" - npm-package-arg "^11.0.1" - npm-registry-fetch "^16.2.0" - proc-log "^3.0.0" - semver "^7.3.7" - sigstore "^2.2.0" - ssri "^10.0.5" + "@npmcli/run-script" "^1.8.3" + npm-package-arg "^8.1.0" + pacote "^11.2.6" + +libnpmpublish@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" + integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== + dependencies: + normalize-package-data "^3.0.2" + npm-package-arg "^8.1.2" + npm-registry-fetch "^11.0.0" + semver "^7.1.3" + ssri "^8.0.1" libnpmpublish@^6.0.4: version "6.0.5" @@ -17550,31 +17495,31 @@ libnpmpublish@^6.0.4: semver "^7.3.7" ssri "^9.0.0" -libnpmsearch@*: - version "7.0.2" - resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-7.0.2.tgz#d088934c720179513baca0d8cccaddcf0da76e49" - integrity sha512-SvYcq3SmexQWhch1i/9ML+vQx82+thVMRvgtZc/Yjf6s0Cfu/87ZQ3bb6jFe/whwaXxjwdDX8MrdmNXNKG+JPA== +libnpmsearch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-3.1.2.tgz#aee81b9e4768750d842b627a3051abc89fdc15f3" + integrity sha512-BaQHBjMNnsPYk3Bl6AiOeVuFgp72jviShNBw5aHaHNKWqZxNi38iVNoXbo6bG/Ccc/m1To8s0GtMdtn6xZ1HAw== dependencies: - npm-registry-fetch "^16.2.0" + npm-registry-fetch "^11.0.0" -libnpmteam@*: - version "6.0.2" - resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-6.0.2.tgz#f83cf778785b89cdbf463dd6025669c0df2aa06b" - integrity sha512-EUTKCj1PmstpZE/MJ8QVs9L6wi4lMzD7TPyxHXiXWSsUy0/a1gKysW8TjC9dIAMVb/3okUUxiP/LIRwdShBpAQ== +libnpmteam@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-2.0.4.tgz#9dbe2e18ae3cb97551ec07d2a2daf9944f3edc4c" + integrity sha512-FPrVJWv820FZFXaflAEVTLRWZrerCvfe7ZHSMzJ/62EBlho2KFlYKjyNEsPW3JiV7TLSXi3vo8u0gMwIkXSMTw== dependencies: aproba "^2.0.0" - npm-registry-fetch "^16.2.0" + npm-registry-fetch "^11.0.0" -libnpmversion@*: - version "5.0.2" - resolved "https://registry.yarnpkg.com/libnpmversion/-/libnpmversion-5.0.2.tgz#aea7b09bc270c778cbc8be7bf02e4b60566989cf" - integrity sha512-6JBnLhd6SYgKRekJ4cotxpURLGbEtKxzw+a8p5o+wNwrveJPMH8yW/HKjeewyHzWmxzzwn9EQ3TkF2onkrwstA== +libnpmversion@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/libnpmversion/-/libnpmversion-1.2.1.tgz#689aa7fe0159939b3cbbf323741d34976f4289e9" + integrity sha512-AA7x5CFgBFN+L4/JWobnY5t4OAHjQuPbAwUYJ7/NtHuyLut5meb+ne/aj0n7PWNiTGCJcRw/W6Zd2LoLT7EZuQ== dependencies: - "@npmcli/git" "^5.0.3" - "@npmcli/run-script" "^7.0.2" - json-parse-even-better-errors "^3.0.0" - proc-log "^3.0.0" - semver "^7.3.7" + "@npmcli/git" "^2.0.7" + "@npmcli/run-script" "^1.8.4" + json-parse-even-better-errors "^2.3.1" + semver "^7.3.5" + stringify-package "^1.0.1" libsodium-wrappers@^0.7.6: version "0.7.13" @@ -18096,7 +18041,29 @@ make-error@1.x, make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@*, make-fetch-happen@^13.0.0: +make-fetch-happen@^10.0.3, make-fetch-happen@^10.0.6: + version "10.2.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" + integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== + dependencies: + agentkeepalive "^4.2.1" + cacache "^16.1.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-fetch "^2.0.3" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + socks-proxy-agent "^7.0.0" + ssri "^9.0.0" + +make-fetch-happen@^13.0.0: version "13.0.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== @@ -18113,27 +18080,27 @@ make-fetch-happen@*, make-fetch-happen@^13.0.0: promise-retry "^2.0.1" ssri "^10.0.0" -make-fetch-happen@^10.0.3, make-fetch-happen@^10.0.6: - version "10.2.1" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" - integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== +make-fetch-happen@^9.0.1, make-fetch-happen@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== dependencies: - agentkeepalive "^4.2.1" - cacache "^16.1.0" + agentkeepalive "^4.1.3" + cacache "^15.2.0" http-cache-semantics "^4.1.0" - http-proxy-agent "^5.0.0" + http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0" is-lambda "^1.0.1" - lru-cache "^7.7.1" - minipass "^3.1.6" + lru-cache "^6.0.0" + minipass "^3.1.3" minipass-collect "^1.0.2" - minipass-fetch "^2.0.3" + minipass-fetch "^1.3.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" - negotiator "^0.6.3" + negotiator "^0.6.2" promise-retry "^2.0.1" - socks-proxy-agent "^7.0.0" - ssri "^9.0.0" + socks-proxy-agent "^6.0.0" + ssri "^8.0.0" makeerror@1.0.12: version "1.0.12" @@ -18456,7 +18423,7 @@ minimatch@^7.1.3: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4: +minimatch@^9.0.1: version "9.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== @@ -18491,6 +18458,17 @@ minipass-collect@^2.0.1: dependencies: minipass "^7.0.3" +minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + minipass-fetch@^2.0.3: version "2.1.2" resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add" @@ -18528,7 +18506,7 @@ minipass-json-stream@^1.0.1: jsonparse "^1.3.1" minipass "^3.0.0" -minipass-pipeline@*, minipass-pipeline@^1.2.4: +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== @@ -18542,11 +18520,6 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" -minipass@*, "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -18555,7 +18528,7 @@ minipass@^2.6.0, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== @@ -18567,6 +18540,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minizlib@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" @@ -18574,7 +18552,7 @@ minizlib@^1.3.3: dependencies: minipass "^2.9.0" -minizlib@^2.1.1, minizlib@^2.1.2: +minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -18582,14 +18560,6 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -minizlib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012" - integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== - dependencies: - minipass "^7.0.4" - rimraf "^5.0.5" - mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -18603,7 +18573,7 @@ mkdirp-classic@^0.5.2: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp-infer-owner@*, mkdirp-infer-owner@^2.0.0: +mkdirp-infer-owner@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== @@ -18619,7 +18589,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*, mkdirp@^3.0.1: +mkdirp@*: version "3.0.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== @@ -18696,11 +18666,6 @@ mri@^1.2.0: resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== -ms@*, ms@2.1.3, ms@^2.0.0, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -18711,6 +18676,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + multibase@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" @@ -18795,11 +18765,6 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mute-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" - integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== - nan@^2.12.1, nan@^2.14.0, nan@^2.18.0, nan@^2.2.1: version "2.19.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" @@ -18862,7 +18827,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3, negotiator@^0.6.3: +negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -18981,7 +18946,7 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== -node-gyp@*, node-gyp@^10.0.0, node-gyp@^10.0.1: +node-gyp@^10.0.1: version "10.1.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.1.0.tgz#75e6f223f2acb4026866c26a2ead6aab75a8ca7e" integrity sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA== @@ -18997,6 +18962,22 @@ node-gyp@*, node-gyp@^10.0.0, node-gyp@^10.0.1: tar "^6.1.2" which "^4.0.0" +node-gyp@^7.1.0, node-gyp@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^5.0.0" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^3.0.2" + semver "^7.3.2" + tar "^6.0.2" + which "^2.0.2" + node-gyp@^9.0.0: version "9.4.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.1.tgz#8a1023e0d6766ecb52764cc3a734b36ff275e185" @@ -19069,13 +19050,6 @@ nofilter@^3.1.0: resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" integrity sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g== -nopt@*, nopt@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" - integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== - dependencies: - abbrev "^2.0.0" - nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -19090,6 +19064,13 @@ nopt@^6.0.0: dependencies: abbrev "^1.0.0" +nopt@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== + dependencies: + abbrev "^2.0.0" + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -19107,7 +19088,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0: +normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== @@ -19127,16 +19108,6 @@ normalize-package-data@^4.0.0: semver "^7.3.5" validate-npm-package-license "^3.0.4" -normalize-package-data@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.0.tgz#68a96b3c11edd462af7189c837b6b1064a484196" - integrity sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg== - dependencies: - hosted-git-info "^7.0.0" - is-core-module "^2.8.1" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -19168,10 +19139,12 @@ normalize-url@^6.0.0, normalize-url@^6.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== -npm-audit-report@*: - version "5.0.0" - resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-5.0.0.tgz#83ac14aeff249484bde81eff53c3771d5048cf95" - integrity sha512-EkXrzat7zERmUhHaoren1YhTxFwsOu5jypE84k6632SXTHcQE1z8V51GC6GVZt8LxkC+tbBcKMUBZAgk8SUSbw== +npm-audit-report@^2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-2.1.5.tgz#a5b8850abe2e8452fce976c8960dd432981737b5" + integrity sha512-YB8qOoEmBhUH1UJgh1xFAv7Jg1d+xoNhsDYiFQlEFThEBui0W1vIz2ZK6FVg4WZjwEdl7uBQlm1jy3MUfyHeEw== + dependencies: + chalk "^4.0.0" npm-bundled@^1.1.1: version "1.1.2" @@ -19187,17 +19160,10 @@ npm-bundled@^2.0.0: dependencies: npm-normalize-package-bin "^2.0.0" -npm-bundled@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7" - integrity sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ== - dependencies: - npm-normalize-package-bin "^3.0.0" - -npm-install-checks@*, npm-install-checks@^6.0.0, npm-install-checks@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" - integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== +npm-install-checks@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" + integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== dependencies: semver "^7.1.1" @@ -19208,7 +19174,7 @@ npm-install-checks@^5.0.0: dependencies: semver "^7.1.1" -npm-normalize-package-bin@^1.0.1: +npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== @@ -19218,21 +19184,6 @@ npm-normalize-package-bin@^2.0.0: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz#9447a1adaaf89d8ad0abe24c6c84ad614a675fff" integrity sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ== -npm-normalize-package-bin@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" - integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== - -npm-package-arg@*, npm-package-arg@^11.0.0, npm-package-arg@^11.0.1: - version "11.0.2" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.2.tgz#1ef8006c4a9e9204ddde403035f7ff7d718251ca" - integrity sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw== - dependencies: - hosted-git-info "^7.0.0" - proc-log "^4.0.0" - semver "^7.3.5" - validate-npm-package-name "^5.0.0" - npm-package-arg@11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.1.tgz#f208b0022c29240a1c532a449bdde3f0a4708ebc" @@ -19252,6 +19203,15 @@ npm-package-arg@8.1.1: semver "^7.0.0" validate-npm-package-name "^3.0.0" +npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.1, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: + version "8.1.5" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== + dependencies: + hosted-git-info "^4.0.1" + semver "^7.3.4" + validate-npm-package-name "^3.0.0" + npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: version "9.1.2" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-9.1.2.tgz#fc8acecb00235f42270dda446f36926ddd9ac2bc" @@ -19262,6 +19222,16 @@ npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: semver "^7.3.5" validate-npm-package-name "^4.0.0" +npm-packlist@^2.1.4: + version "2.2.2" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" + integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== + dependencies: + glob "^7.1.6" + ignore-walk "^3.0.3" + npm-bundled "^1.1.1" + npm-normalize-package-bin "^1.0.1" + npm-packlist@^5.1.0, npm-packlist@^5.1.1: version "5.1.3" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.3.tgz#69d253e6fd664b9058b85005905012e00e69274b" @@ -19272,22 +19242,15 @@ npm-packlist@^5.1.0, npm-packlist@^5.1.1: npm-bundled "^2.0.0" npm-normalize-package-bin "^2.0.0" -npm-packlist@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-8.0.2.tgz#5b8d1d906d96d21c85ebbeed2cf54147477c8478" - integrity sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA== - dependencies: - ignore-walk "^6.0.4" - -npm-pick-manifest@*, npm-pick-manifest@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz#f87a4c134504a2c7931f2bb8733126e3c3bb7e8f" - integrity sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg== +npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.0, npm-pick-manifest@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" + integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== dependencies: - npm-install-checks "^6.0.0" - npm-normalize-package-bin "^3.0.0" - npm-package-arg "^11.0.0" - semver "^7.3.5" + npm-install-checks "^4.0.0" + npm-normalize-package-bin "^1.0.1" + npm-package-arg "^8.1.2" + semver "^7.3.4" npm-pick-manifest@^7.0.0: version "7.0.2" @@ -19299,27 +19262,24 @@ npm-pick-manifest@^7.0.0: npm-package-arg "^9.0.0" semver "^7.3.5" -npm-profile@*: - version "9.0.1" - resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-9.0.1.tgz#b0817357addb1804992bd9fed363992441847738" - integrity sha512-9o6dw5eu3tiqX1XFOXjznO73Jzin48Oyo9qAhfaEHXzeZHXpdzgDmzWruWk7uJsu5GMIsigx5hva5rB5NhfSWw== +npm-profile@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-5.0.4.tgz#73e5bd1d808edc2c382d7139049cc367ac43161b" + integrity sha512-OKtU7yoAEBOnc8zJ+/uo5E4ugPp09sopo+6y1njPp+W99P8DvQon3BJYmpvyK2Bf1+3YV5LN1bvgXRoZ1LUJBA== dependencies: - npm-registry-fetch "^16.0.0" - proc-log "^4.0.0" + npm-registry-fetch "^11.0.0" -npm-registry-fetch@*, npm-registry-fetch@^16.0.0, npm-registry-fetch@^16.2.0: - version "16.2.1" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz#c367df2d770f915da069ff19fd31762f4bca3ef1" - integrity sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA== +npm-registry-fetch@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" + integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== dependencies: - "@npmcli/redact" "^1.1.0" - make-fetch-happen "^13.0.0" - minipass "^7.0.2" - minipass-fetch "^3.0.0" + make-fetch-happen "^9.0.1" + minipass "^3.1.3" + minipass-fetch "^1.3.0" minipass-json-stream "^1.0.1" - minizlib "^2.1.2" - npm-package-arg "^11.0.0" - proc-log "^4.0.0" + minizlib "^2.0.0" + npm-package-arg "^8.0.0" npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1, npm-registry-fetch@^13.3.0: version "13.3.1" @@ -19348,10 +19308,10 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -npm-user-validate@*: - version "2.0.0" - resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-2.0.0.tgz#7b69bbbff6f7992a1d9a8968d52fd6b6db5431b6" - integrity sha512-sSWeqAYJ2dUPStJB+AEj0DyLRltr/f6YNcvCA7phkB8/RMLMnVsQ41GMwHo/ERZLYNDsyB2wPm7pZo1mqPOl7Q== +npm-user-validate@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.1.tgz#31428fc5475fe8416023f178c0ab47935ad8c561" + integrity sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw== npm@^7.0.0: version "7.24.2" @@ -19429,14 +19389,24 @@ npm@^7.0.0: which "^2.0.2" write-file-atomic "^3.0.3" -npmlog@*, npmlog@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-7.0.1.tgz#7372151a01ccb095c47d8bf1d0771a4ff1f53ac8" - integrity sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg== +npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== dependencies: - are-we-there-yet "^4.0.0" + are-we-there-yet "^2.0.0" console-control-strings "^1.1.0" - gauge "^5.0.0" + gauge "^3.0.0" set-blocking "^2.0.0" npmlog@^6.0.0, npmlog@^6.0.2: @@ -19860,7 +19830,7 @@ open@^8.0.9, open@^8.4.0, open@~8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" -opener@*, opener@^1.5.1: +opener@^1.5.1, opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== @@ -20168,29 +20138,30 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" -pacote@*, pacote@^18.0.0: - version "18.0.0" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-18.0.0.tgz#974491c8b5a40f42830bc55361924ca7c7e45784" - integrity sha512-ma7uVt/q3Sb3XbLwUjOeClz+7feHjMOFegHn5whw++x+GzikZkAq/2auklSbRuy6EI2iJh1/ZqCpVaUcxRaeqQ== +pacote@^11.1.11, pacote@^11.2.6, pacote@^11.3.0, pacote@^11.3.1, pacote@^11.3.5: + version "11.3.5" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" + integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== dependencies: - "@npmcli/git" "^5.0.0" - "@npmcli/installed-package-contents" "^2.0.1" - "@npmcli/promise-spawn" "^7.0.0" - "@npmcli/run-script" "^8.0.0" - cacache "^18.0.0" - fs-minipass "^3.0.0" - minipass "^7.0.2" - npm-package-arg "^11.0.0" - npm-packlist "^8.0.0" - npm-pick-manifest "^9.0.0" - npm-registry-fetch "^16.0.0" - proc-log "^4.0.0" + "@npmcli/git" "^2.1.0" + "@npmcli/installed-package-contents" "^1.0.6" + "@npmcli/promise-spawn" "^1.2.0" + "@npmcli/run-script" "^1.8.2" + cacache "^15.0.5" + chownr "^2.0.0" + fs-minipass "^2.1.0" + infer-owner "^1.0.4" + minipass "^3.1.3" + mkdirp "^1.0.3" + npm-package-arg "^8.0.1" + npm-packlist "^2.1.4" + npm-pick-manifest "^6.0.0" + npm-registry-fetch "^11.0.0" promise-retry "^2.0.1" - read-package-json "^7.0.0" - read-package-json-fast "^3.0.0" - sigstore "^2.2.0" - ssri "^10.0.0" - tar "^6.1.11" + read-package-json-fast "^2.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.1.0" pacote@^13.0.3, pacote@^13.6.1: version "13.6.2" @@ -20219,30 +20190,6 @@ pacote@^13.0.3, pacote@^13.6.1: ssri "^9.0.0" tar "^6.1.11" -pacote@^17.0.4: - version "17.0.7" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-17.0.7.tgz#14b59a9bf5e3442c891af86825b97b7d72f48fba" - integrity sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ== - dependencies: - "@npmcli/git" "^5.0.0" - "@npmcli/installed-package-contents" "^2.0.1" - "@npmcli/promise-spawn" "^7.0.0" - "@npmcli/run-script" "^7.0.0" - cacache "^18.0.0" - fs-minipass "^3.0.0" - minipass "^7.0.2" - npm-package-arg "^11.0.0" - npm-packlist "^8.0.0" - npm-pick-manifest "^9.0.0" - npm-registry-fetch "^16.0.0" - proc-log "^4.0.0" - promise-retry "^2.0.1" - read-package-json "^7.0.0" - read-package-json-fast "^3.0.0" - sigstore "^2.2.0" - ssri "^10.0.0" - tar "^6.1.11" - pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -20282,14 +20229,14 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.7: pbkdf2 "^3.1.2" safe-buffer "^5.2.1" -parse-conflict-json@*, parse-conflict-json@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz#67dc55312781e62aa2ddb91452c7606d1969960c" - integrity sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw== +parse-conflict-json@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-1.1.1.tgz#54ec175bde0f2d70abf6be79e0e042290b86701b" + integrity sha512-4gySviBiW5TRl7XHvp1agcS7SOe0KZOjC//71dzZVWJrY9hCrgtvl5v3SyIxCZ4fZF47TxD9nfzmxcx76xmbUw== dependencies: - json-parse-even-better-errors "^3.0.0" - just-diff "^6.0.0" - just-diff-apply "^5.2.0" + json-parse-even-better-errors "^2.3.0" + just-diff "^3.0.1" + just-diff-apply "^3.0.0" parse-conflict-json@^2.0.1: version "2.0.2" @@ -20727,14 +20674,6 @@ possible-typed-array-names@^1.0.0: resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== -postcss-selector-parser@^6.0.10: - version "6.0.16" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz#3b88b9f5c5abd989ef4e2fc9ec8eedd34b20fb04" - integrity sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - postcss@8.4.14: version "8.4.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" @@ -20835,6 +20774,11 @@ private@^0.1.6, private@^0.1.8: resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== +proc-log@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-1.0.0.tgz#0d927307401f69ed79341e83a0b2c9a13395eb77" + integrity sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg== + proc-log@^2.0.0, proc-log@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685" @@ -20845,11 +20789,6 @@ proc-log@^3.0.0: resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== -proc-log@^4.0.0, proc-log@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" - integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -20887,11 +20826,6 @@ promise-call-limit@^1.0.1: resolved "https://registry.yarnpkg.com/promise-call-limit/-/promise-call-limit-1.0.2.tgz#f64b8dd9ef7693c9c7613e7dfe8d6d24de3031ea" integrity sha512-1vTUnfI2hzui8AEIixbdAJlFY4LFDXqQswy/2eOlThAscXCY4It8FdVuI0fMJGAB2aWGbdQf/gv0skKYXmdrHA== -promise-call-limit@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/promise-call-limit/-/promise-call-limit-3.0.1.tgz#3570f7a3f2aaaf8e703623a552cd74749688cf19" - integrity sha512-utl+0x8gIDasV5X+PI5qWEPqH6fJS0pFtQ/4gZ95xfEFb/89dmh+/b895TbFDBLiafBvxD/PGTKfvxl4kH/pQg== - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -20928,13 +20862,6 @@ promzard@^0.3.0: dependencies: read "1" -promzard@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.1.tgz#3b77251a24f988c0886f5649d4f642bcdd53e558" - integrity sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A== - dependencies: - read "^3.0.1" - prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -21098,7 +21025,7 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qrcode-terminal@*: +qrcode-terminal@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ== @@ -21331,25 +21258,17 @@ react@18.0.0: dependencies: loose-envify "^1.1.0" +read-cmd-shim@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" + integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== + read-cmd-shim@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-3.0.1.tgz#868c235ec59d1de2db69e11aec885bc095aea087" integrity sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g== -read-cmd-shim@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" - integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== - -read-package-json-fast@*, read-package-json-fast@^3.0.0, read-package-json-fast@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" - integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== - dependencies: - json-parse-even-better-errors "^3.0.0" - npm-normalize-package-bin "^3.0.0" - -read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: +read-package-json-fast@^2.0.1, read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== @@ -21357,15 +21276,15 @@ read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -read-package-json@*, read-package-json@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-7.0.0.tgz#d605c9dcf6bc5856da24204aa4e9518ee9714be0" - integrity sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg== +read-package-json@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.1.2.tgz#b444d047de7c75d4a160cb056d00c0693c1df703" + integrity sha512-Dqer4pqzamDE2O4M55xp1qZMuLPqi4ldk2ya648FOMHRjwMzFhuxVrG04wd0c38IsvkVdr3vgHI6z+QTPdAjrQ== dependencies: - glob "^10.2.2" - json-parse-even-better-errors "^3.0.0" - normalize-package-data "^6.0.0" - npm-normalize-package-bin "^3.0.0" + glob "^7.1.1" + json-parse-even-better-errors "^2.3.0" + normalize-package-data "^3.0.0" + npm-normalize-package-bin "^1.0.0" read-package-json@^5.0.0, read-package-json@^5.0.1: version "5.0.2" @@ -21430,14 +21349,7 @@ read-pkg@^5.0.0, read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -read@*, read@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/read/-/read-3.0.1.tgz#926808f0f7c83fa95f1ef33c0e2c09dbb28fd192" - integrity sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw== - dependencies: - mute-stream "^1.0.0" - -read@1, read@^1.0.7: +read@1, read@^1.0.7, read@~1.0.1, read@~1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" integrity sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ== @@ -21463,7 +21375,7 @@ readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.8, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.8, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -21486,7 +21398,7 @@ readable-stream@~1.0.15: isarray "0.0.1" string_decoder "~0.10.x" -readdir-scoped-modules@*, readdir-scoped-modules@^1.1.0: +readdir-scoped-modules@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== @@ -21763,7 +21675,7 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" -request@^2.79.0, request@^2.85.0: +request@^2.79.0, request@^2.85.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -21934,13 +21846,6 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== -rimraf@*, rimraf@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" - integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== - dependencies: - glob "^10.3.7" - rimraf@^2.2.8: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -22235,13 +22140,6 @@ semver-regex@^3.1.2: resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.4.tgz#13053c0d4aa11d070a2f2872b6b1e3ae1e1971b4" integrity sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA== -semver@*, semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" - "semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.6.0, semver@^5.7.1: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -22266,6 +22164,13 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + semver@~5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -22375,7 +22280,7 @@ servify@^0.1.12: request "^2.79.0" xhr "^2.3.3" -set-blocking@^2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== @@ -22496,7 +22401,7 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -22515,18 +22420,6 @@ signale@^1.2.1: figures "^2.0.0" pkg-conf "^2.1.0" -sigstore@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-2.3.0.tgz#c56b32818d4dc989f6ea3c0897f4d9bff5d14bed" - integrity sha512-q+o8L2ebiWD1AxD17eglf1pFrl9jtW7FHa0ygqY6EKvibK8JHyq9Z26v9MZXeDiw+RbfOJ9j2v70M10Hd6E06A== - dependencies: - "@sigstore/bundle" "^2.3.1" - "@sigstore/core" "^1.0.0" - "@sigstore/protobuf-specs" "^0.3.1" - "@sigstore/sign" "^2.3.0" - "@sigstore/tuf" "^2.3.1" - "@sigstore/verify" "^1.2.0" - simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -22664,6 +22557,15 @@ sockjs@^0.3.24: uuid "^8.3.2" websocket-driver "^0.7.4" +socks-proxy-agent@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" + integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== + dependencies: + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" + socks-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" @@ -22973,13 +22875,20 @@ sshpk@^1.14.1, sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@*, ssri@^10.0.0, ssri@^10.0.5: +ssri@^10.0.0: version "10.0.5" resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.5.tgz#e49efcd6e36385196cb515d3a2ad6c3f0265ef8c" integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== dependencies: minipass "^7.0.3" +ssri@^8.0.0, ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + ssri@^9.0.0, ssri@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" @@ -23158,7 +23067,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.1.0: +string-width@^2.0.0, string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -23249,6 +23158,11 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-package@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" + integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== + "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -23670,18 +23584,6 @@ tar-stream@^2.1.4, tar-stream@~2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@*: - version "7.0.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-7.0.1.tgz#8f6ccebcd91b69e9767a6fc4892799e8b0e606d5" - integrity sha512-IjMhdQMZFpKsHEQT3woZVxBtCQY+0wk3CVxdRkGXEgyGa0dNS/ehPvOMr2nmfC7x5Zj2N+l6yZUpmICjLGS35w== - dependencies: - "@isaacs/fs-minipass" "^4.0.0" - chownr "^3.0.0" - minipass "^5.0.0" - minizlib "^3.0.1" - mkdirp "^3.0.1" - yallist "^5.0.0" - tar@6.1.11: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" @@ -23707,7 +23609,7 @@ tar@^4.0.2: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.1.0, tar@^6.1.11, tar@^6.1.2, tar@^6.2.1: +tar@^6.0.2, tar@^6.1.0, tar@^6.1.11, tar@^6.1.2: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== @@ -23791,7 +23693,7 @@ text-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== -text-table@*, text-table@^0.2.0: +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== @@ -23850,7 +23752,7 @@ timers-browserify@^2.0.12: dependencies: setimmediate "^1.0.4" -tiny-relative-date@*: +tiny-relative-date@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A== @@ -24000,10 +23902,10 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -treeverse@*, treeverse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-3.0.0.tgz#dd82de9eb602115c6ebd77a574aae67003cb48c8" - integrity sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ== +treeverse@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-1.0.4.tgz#a6b0ebf98a1bca6846ddc7ecbc900df08cb9cd5f" + integrity sha512-whw60l7r+8ZU8Tu/Uc2yxtc4ZTZbR/PF3u1IPNKGQ6p8EICLb3Z2lAgoqw9bqYd8IkgnsaOcLzYHFckjqNsf0g== treeverse@^2.0.0: version "2.0.0" @@ -24130,15 +24032,6 @@ tty-browserify@^0.0.1: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== -tuf-js@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-2.2.0.tgz#4daaa8620ba7545501d04dfa933c98abbcc959b9" - integrity sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg== - dependencies: - "@tufjs/models" "2.0.0" - debug "^4.3.4" - make-fetch-happen "^13.0.0" - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -24490,6 +24383,13 @@ union@~0.5.0: dependencies: qs "^6.4.0" +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + unique-filename@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" @@ -24504,6 +24404,13 @@ unique-filename@^3.0.0: dependencies: unique-slug "^4.0.0" +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + unique-slug@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9" @@ -24748,7 +24655,7 @@ utf8@3.0.0, utf8@^3.0.0: resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -24855,14 +24762,7 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -validate-npm-package-name@*, validate-npm-package-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" - integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== - dependencies: - builtins "^5.0.0" - -validate-npm-package-name@^3.0.0: +validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" integrity sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw== @@ -24876,6 +24776,13 @@ validate-npm-package-name@^4.0.0: dependencies: builtins "^5.0.0" +validate-npm-package-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" + integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== + dependencies: + builtins "^5.0.0" + valtio@1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.0.tgz#c029dcd17a0f99d2fbec933721fe64cfd32a31ed" @@ -24955,11 +24862,6 @@ walk-up-path@^1.0.0: resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e" integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg== -walk-up-path@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" - integrity sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA== - walker@^1.0.7, walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -25502,13 +25404,6 @@ which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, gopd "^1.0.1" has-tostringtag "^1.0.2" -which@*, which@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" - integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== - dependencies: - isexe "^3.1.1" - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -25516,7 +25411,14 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.5: +which@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + +wide-align@^1.1.0, wide-align@^1.1.2, wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== @@ -25609,14 +25511,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@*, write-file-atomic@^5.0.0, write-file-atomic@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" - integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^4.0.1" - write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -25626,7 +25520,7 @@ write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^3.0.0: +write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== @@ -25644,6 +25538,14 @@ write-file-atomic@^4.0.0, write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +write-file-atomic@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" @@ -25820,11 +25722,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yallist@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" - integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== - yaml@^1.10.0, yaml@^1.7.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" From 9becb9b2bf395daf1ab5083438a3dec28a9e29ac Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Thu, 25 Apr 2024 01:44:41 +0100 Subject: [PATCH 034/263] feat: add unit test https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1578642253 --- packages/misc/src/lib/misc.spec.ts | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/misc/src/lib/misc.spec.ts b/packages/misc/src/lib/misc.spec.ts index e3ca2c12b7..9bd57b0981 100644 --- a/packages/misc/src/lib/misc.spec.ts +++ b/packages/misc/src/lib/misc.spec.ts @@ -239,3 +239,35 @@ describe('utils', () => { expect(res.requestId).toBeDefined(); }); }); + +describe('double escaped JSON string', () => { + test('A doubly escaped JSON string', () => { + const doublyEscapedJson = '{\\"key\\": \\"value\\"}'; + expect(utilsModule.normalizeAndStringify(doublyEscapedJson)).toBe( + '{"key":"value"}' + ); + }); + + test('A triply escaped JSON string', () => { + const triplyEscapedJson = '{\\\\\\"key\\\\\\": \\\\\\"value\\\\\\"}'; + expect(utilsModule.normalizeAndStringify(triplyEscapedJson)).toBe( + '{"key":"value"}' + ); + }); + + test('A correctly escaped JSON string (for comparison)', () => { + const correctlyEscapedJson = '{"key":"value"}'; + expect(utilsModule.normalizeAndStringify(correctlyEscapedJson)).toBe( + '{"key":"value"}' + ); + }); + + test('regular siwe message', () => { + const regularString = + 'litprotocol.com wants you to sign in with your Ethereum account:\\n0x3edB...'; + + expect(utilsModule.normalizeAndStringify(regularString)).toBe( + regularString + ); + }); +}); From 077130860e44dd8bcb3cca68538a9624341c4804 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Thu, 25 Apr 2024 03:29:47 +0100 Subject: [PATCH 035/263] feat(bls):add helper function to combine bls sigs https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1578647103 --- .../lib/helpers/handle-bls-response.spec.ts | 61 +++++++++++++++++++ .../src/lib/helpers/handle-bls-response.ts | 26 ++++++++ .../src/lib/lit-node-client-nodejs.ts | 15 +---- packages/types/src/lib/interfaces.ts | 37 ++++++++++- 4 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts new file mode 100644 index 0000000000..79a0a227ab --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts @@ -0,0 +1,61 @@ +import { handleBlsResponseData } from './handle-bls-response'; + +describe('handleBlsResponseData', () => { + it('should return an array of signed data', () => { + const responseData = [ + { + result: 'success', + signatureShare: { + ProofOfPossession: + '01b191b1d281857a95d2fd189683db366ab1088723338c1805daa4650459e9fcaebaa57b58108c284d233404dd5f2e58f208aafb87d981098aba3fe850980184a4b29643a21107b03f1d928646245b57af3745a81418989e0b6aad9bd1f192723c', + }, + shareIndex: 0, + curveType: 'BLS', + siweMessage: + "litprotocol.com wants you to sign in with your Ethereum account:\n0x7f2e96c99F9551915DA9e9F828F512330f130acB\n\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. (3) 'Auth': 'Auth' for 'lit-resolvedauthcontext://*'.\n\nURI: lit:session:73e09d1ad1faa329bef12ebaf9b982d2925746e3677cabd4b6b7196096a6ee02\nVersion: 1\nChain ID: 1\nNonce: 0xa5f18dbc0fa2080649042ab8cb6cef3b246c20c15b62482ba43fb4ca2a4642cb\nIssued At: 2024-04-25T02:09:35Z\nExpiration Time: 2024-04-26T02:09:50.822Z\nResources:\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZM3F1bjlxWDNmVUJIVmZyQTlmM3Y5UnB5eVBvOFJIRXVFTjFYWVBxMVByQSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOlt7ImFwcElkIjoibGl0IiwiYXV0aE1ldGhvZFR5cGUiOjEsImV4cGlyYXRpb24iOjE3MTQwOTczODYsInVzZWRGb3JTaWduU2Vzc2lvbktleVJlcXVlc3QiOnRydWUsInVzZXJJZCI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCJ9XSwiYXV0aFNpZ0FkZHJlc3MiOm51bGwsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0", + dataSigned: + 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + blsRootPubkey: + 'a6f7c284ac766db1b43f8c65d8ff15c7271a05b0863b5205d96459fd32aa353e9390ce0626560fb76720c1a5c8ca6902', + }, + { + result: 'success', + signatureShare: { + ProofOfPossession: + '038178034edcd5b48da4e2af6eb0891ece41389aa6119c80546d3fa00b5d2ba87eaec327b18d8013714b486246807498c8198e70cf8e917b1a5f1d8d0846787172521d41994de95bd641bdc1d9ccee9b459ceeb03f156cf357a4ff8faf5d2e167d', + }, + shareIndex: 2, + curveType: 'BLS', + siweMessage: + "litprotocol.com wants you to sign in with your Ethereum account:\n0x7f2e96c99F9551915DA9e9F828F512330f130acB\n\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. (3) 'Auth': 'Auth' for 'lit-resolvedauthcontext://*'.\n\nURI: lit:session:73e09d1ad1faa329bef12ebaf9b982d2925746e3677cabd4b6b7196096a6ee02\nVersion: 1\nChain ID: 1\nNonce: 0xa5f18dbc0fa2080649042ab8cb6cef3b246c20c15b62482ba43fb4ca2a4642cb\nIssued At: 2024-04-25T02:09:35Z\nExpiration Time: 2024-04-26T02:09:50.822Z\nResources:\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZM3F1bjlxWDNmVUJIVmZyQTlmM3Y5UnB5eVBvOFJIRXVFTjFYWVBxMVByQSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOlt7ImFwcElkIjoibGl0IiwiYXV0aE1ldGhvZFR5cGUiOjEsImV4cGlyYXRpb24iOjE3MTQwOTczODYsInVzZWRGb3JTaWduU2Vzc2lvbktleVJlcXVlc3QiOnRydWUsInVzZXJJZCI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCJ9XSwiYXV0aFNpZ0FkZHJlc3MiOm51bGwsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0", + dataSigned: + 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + blsRootPubkey: + 'a6f7c284ac766db1b43f8c65d8ff15c7271a05b0863b5205d96459fd32aa353e9390ce0626560fb76720c1a5c8ca6902', + }, + { + result: 'success', + signatureShare: { + ProofOfPossession: + '0292a026325a166398b85b53f3a7a34d147c5337e189d75c33c0f227f7926c839b408dfcc5d242a8685a81c68e0ccedc080c051219161dbc37f06627259b19d15120ab2f710075a44b1dcef18d511bb99b6625c8f575d2688c6b5b01ba6bf448c9', + }, + shareIndex: 1, + curveType: 'BLS', + siweMessage: + "litprotocol.com wants you to sign in with your Ethereum account:\n0x7f2e96c99F9551915DA9e9F828F512330f130acB\n\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. (3) 'Auth': 'Auth' for 'lit-resolvedauthcontext://*'.\n\nURI: lit:session:73e09d1ad1faa329bef12ebaf9b982d2925746e3677cabd4b6b7196096a6ee02\nVersion: 1\nChain ID: 1\nNonce: 0xa5f18dbc0fa2080649042ab8cb6cef3b246c20c15b62482ba43fb4ca2a4642cb\nIssued At: 2024-04-25T02:09:35Z\nExpiration Time: 2024-04-26T02:09:50.822Z\nResources:\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZM3F1bjlxWDNmVUJIVmZyQTlmM3Y5UnB5eVBvOFJIRXVFTjFYWVBxMVByQSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOlt7ImFwcElkIjoibGl0IiwiYXV0aE1ldGhvZFR5cGUiOjEsImV4cGlyYXRpb24iOjE3MTQwOTczODYsInVzZWRGb3JTaWduU2Vzc2lvbktleVJlcXVlc3QiOnRydWUsInVzZXJJZCI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCJ9XSwiYXV0aFNpZ0FkZHJlc3MiOm51bGwsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0", + dataSigned: + 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + blsRootPubkey: + 'a6f7c284ac766db1b43f8c65d8ff15c7271a05b0863b5205d96459fd32aa353e9390ce0626560fb76720c1a5c8ca6902', + }, + ] as any; + + const result = handleBlsResponseData(responseData); + + expect(result).toEqual([ + 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + ]); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts new file mode 100644 index 0000000000..f35ff19f50 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts @@ -0,0 +1,26 @@ +import { log } from '@lit-protocol/misc'; +import { BlsResponseData } from '@lit-protocol/types'; + +/** + * Handles the response data from BLS signature scheme. + * @param responseData - The response data from BLS signature scheme. + * @returns An array of signed data. + * @throws Error if no data is provided. + */ +export function handleBlsResponseData( + responseData: BlsResponseData[] +): string[] { + if (!responseData) { + throw new Error('[handleBlsResponseData] No data provided'); + } + + const signatureShares = responseData.map((s) => ({ + ProofOfPossession: s.signatureShare.ProofOfPossession, + })); + log(`[handleBlsResponseData] signatureShares:`, signatureShares); + + const signedDataList = responseData.map((s) => s.dataSigned); + log(`[handleBlsResponseData] signedDataList:`, signedDataList); + + return signedDataList; +} diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 2a1de0b29f..f533c3b6e5 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -118,6 +118,7 @@ import type { BlsResponseData, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; +import { handleBlsResponseData } from './helpers/handle-bls-response'; export class LitNodeClientNodeJs extends LitCore @@ -2557,19 +2558,7 @@ export class LitNodeClientNodeJs let signedDataList: any[] = []; if (curveType === LIT_CURVE.BLS) { - let _responseData: BlsResponseData[] = responseData; - - const signatureShares = _responseData.map((s) => ({ - ProofOfPossession: s.signatureShare.ProofOfPossession, - })); - - log(`[signSessionKey] signatureShares:`, signatureShares); - - signedDataList = _responseData.map((s) => { - return s.dataSigned; - }); - - signedDataList = _responseData; + signedDataList = handleBlsResponseData(responseData); } else { signedDataList = responseData.map( (r: any) => (r as SignedData).signedData diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 0d54cab457..073c6eb8f3 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -322,8 +322,43 @@ export interface JsonSignSessionKeyRequestV1 { epoch?: number; } +// [ +// { +// "result": "success", +// "signatureShare": { +// "ProofOfPossession": "01b191b1d281857a95d2fd189683db366ab1088723338c1805daa4650459e9fcaebaa57b58108c284d233404dd5f2e58f208aafb87d981098aba3fe850980184a4b29643a21107b03f1d928646245b57af3745a81418989e0b6aad9bd1f192723c" +// }, +// "shareIndex": 0, +// "curveType": "BLS", +// "siweMessage": "litprotocol.com wants you to sign in with your Ethereum account:\n0x7f2e96c99F9551915DA9e9F828F512330f130acB\n\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. (3) 'Auth': 'Auth' for 'lit-resolvedauthcontext://*'.\n\nURI: lit:session:73e09d1ad1faa329bef12ebaf9b982d2925746e3677cabd4b6b7196096a6ee02\nVersion: 1\nChain ID: 1\nNonce: 0xa5f18dbc0fa2080649042ab8cb6cef3b246c20c15b62482ba43fb4ca2a4642cb\nIssued At: 2024-04-25T02:09:35Z\nExpiration Time: 2024-04-26T02:09:50.822Z\nResources:\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZM3F1bjlxWDNmVUJIVmZyQTlmM3Y5UnB5eVBvOFJIRXVFTjFYWVBxMVByQSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOlt7ImFwcElkIjoibGl0IiwiYXV0aE1ldGhvZFR5cGUiOjEsImV4cGlyYXRpb24iOjE3MTQwOTczODYsInVzZWRGb3JTaWduU2Vzc2lvbktleVJlcXVlc3QiOnRydWUsInVzZXJJZCI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCJ9XSwiYXV0aFNpZ0FkZHJlc3MiOm51bGwsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0", +// "dataSigned": "b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5", +// "blsRootPubkey": "a6f7c284ac766db1b43f8c65d8ff15c7271a05b0863b5205d96459fd32aa353e9390ce0626560fb76720c1a5c8ca6902" +// }, +// { +// "result": "success", +// "signatureShare": { +// "ProofOfPossession": "038178034edcd5b48da4e2af6eb0891ece41389aa6119c80546d3fa00b5d2ba87eaec327b18d8013714b486246807498c8198e70cf8e917b1a5f1d8d0846787172521d41994de95bd641bdc1d9ccee9b459ceeb03f156cf357a4ff8faf5d2e167d" +// }, +// "shareIndex": 2, +// "curveType": "BLS", +// "siweMessage": "litprotocol.com wants you to sign in with your Ethereum account:\n0x7f2e96c99F9551915DA9e9F828F512330f130acB\n\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. (3) 'Auth': 'Auth' for 'lit-resolvedauthcontext://*'.\n\nURI: lit:session:73e09d1ad1faa329bef12ebaf9b982d2925746e3677cabd4b6b7196096a6ee02\nVersion: 1\nChain ID: 1\nNonce: 0xa5f18dbc0fa2080649042ab8cb6cef3b246c20c15b62482ba43fb4ca2a4642cb\nIssued At: 2024-04-25T02:09:35Z\nExpiration Time: 2024-04-26T02:09:50.822Z\nResources:\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZM3F1bjlxWDNmVUJIVmZyQTlmM3Y5UnB5eVBvOFJIRXVFTjFYWVBxMVByQSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOlt7ImFwcElkIjoibGl0IiwiYXV0aE1ldGhvZFR5cGUiOjEsImV4cGlyYXRpb24iOjE3MTQwOTczODYsInVzZWRGb3JTaWduU2Vzc2lvbktleVJlcXVlc3QiOnRydWUsInVzZXJJZCI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCJ9XSwiYXV0aFNpZ0FkZHJlc3MiOm51bGwsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0", +// "dataSigned": "b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5", +// "blsRootPubkey": "a6f7c284ac766db1b43f8c65d8ff15c7271a05b0863b5205d96459fd32aa353e9390ce0626560fb76720c1a5c8ca6902" +// }, +// { +// "result": "success", +// "signatureShare": { +// "ProofOfPossession": "0292a026325a166398b85b53f3a7a34d147c5337e189d75c33c0f227f7926c839b408dfcc5d242a8685a81c68e0ccedc080c051219161dbc37f06627259b19d15120ab2f710075a44b1dcef18d511bb99b6625c8f575d2688c6b5b01ba6bf448c9" +// }, +// "shareIndex": 1, +// "curveType": "BLS", +// "siweMessage": "litprotocol.com wants you to sign in with your Ethereum account:\n0x7f2e96c99F9551915DA9e9F828F512330f130acB\n\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Execution' for 'lit-litaction://*'. (2) 'Threshold': 'Signing' for 'lit-pkp://*'. (3) 'Auth': 'Auth' for 'lit-resolvedauthcontext://*'.\n\nURI: lit:session:73e09d1ad1faa329bef12ebaf9b982d2925746e3677cabd4b6b7196096a6ee02\nVersion: 1\nChain ID: 1\nNonce: 0xa5f18dbc0fa2080649042ab8cb6cef3b246c20c15b62482ba43fb4ca2a4642cb\nIssued At: 2024-04-25T02:09:35Z\nExpiration Time: 2024-04-26T02:09:50.822Z\nResources:\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZM3F1bjlxWDNmVUJIVmZyQTlmM3Y5UnB5eVBvOFJIRXVFTjFYWVBxMVByQSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOlt7ImFwcElkIjoibGl0IiwiYXV0aE1ldGhvZFR5cGUiOjEsImV4cGlyYXRpb24iOjE3MTQwOTczODYsInVzZWRGb3JTaWduU2Vzc2lvbktleVJlcXVlc3QiOnRydWUsInVzZXJJZCI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCJ9XSwiYXV0aFNpZ0FkZHJlc3MiOm51bGwsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0", +// "dataSigned": "b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5", +// "blsRootPubkey": "a6f7c284ac766db1b43f8c65d8ff15c7271a05b0863b5205d96459fd32aa353e9390ce0626560fb76720c1a5c8ca6902" +// } +// ] export interface BlsResponseData { - result: boolean; + result: boolean | 'success'; signatureShare: { ProofOfPossession: string; }; From edc48453f701616d22407bbe391abeb7d7d7c515 Mon Sep 17 00:00:00 2001 From: Ansonhkg Date: Thu, 25 Apr 2024 03:52:01 +0100 Subject: [PATCH 036/263] chore: pretty pretty pretty linty lint --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 3b18d74d40..ea1affe089 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2969,7 +2969,6 @@ export class LitNodeClientNodeJs * @throws An error if any of the required parameters are missing or if `litActionCode` and `ipfsId` exist at the same time. */ getPkpSessionSigs = async (params: GetPkpSessionSigs) => { - const chain = params?.chain || 'ethereum'; const pkpSessionSigs = this.getSessionSigs({ From 35ede368ee826b7323dcdb1ff87f332393cdf935 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 25 Apr 2024 22:00:05 +0100 Subject: [PATCH 037/263] feat(migration): update pkpSign function --- packages/core/src/lib/lit-core.ts | 54 +++++++-------- .../src/lib/helpers/normalize-array.test.ts | 28 ++++++++ .../src/lib/helpers/normalize-array.ts | 15 +++++ .../src/lib/lit-node-client-nodejs.ts | 67 ++++++++++--------- packages/types/src/lib/interfaces.ts | 60 +++++------------ 5 files changed, 121 insertions(+), 103 deletions(-) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 27cdb169e0..293eebe194 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -1018,48 +1018,40 @@ export class LitCore { }; /** + * Retrieves the session signature for a given URL from the sessionSigs map. + * Throws an error if sessionSigs is not provided or if the session signature for the URL is not found. * - * Get either auth sig or session auth sig - * + * @param sessionSigs - The session signatures map. + * @param url - The URL for which to retrieve the session signature. + * @returns The session signature for the given URL. + * @throws An error if sessionSigs is not provided or if the session signature for the URL is not found. */ - getSessionOrAuthSig = ({ - authSig, + getSessionSigByUrl = ({ sessionSigs, url, - mustHave = true, }: { - authSig?: AuthSig; - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; url: string; - mustHave?: boolean; - }): AuthSig | SessionSig => { - if (!authSig && !sessionSigs) { - if (mustHave) { - throwError({ - message: `You must pass either authSig, or sessionSigs`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } else { - log(`authSig or sessionSigs not found. This may be using authMethod`); - } + }): AuthSig => { + if (!sessionSigs) { + return throwError({ + message: `You must pass in sessionSigs`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); } - if (sessionSigs) { - const sigToPassToNode = sessionSigs[url]; + const sigToPassToNode = sessionSigs[url]; - if (!sigToPassToNode) { - throwError({ - message: `You passed sessionSigs but we could not find session sig for node ${url}`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } - - return sigToPassToNode; + if (!sessionSigs[url]) { + throwError({ + message: `You passed sessionSigs but we could not find session sig for node ${url}`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); } - return authSig!; + return sigToPassToNode; }; validateAccessControlConditionsSchema = async ( diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.test.ts new file mode 100644 index 0000000000..a2b9424e16 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.test.ts @@ -0,0 +1,28 @@ +import { ethers } from 'ethers'; +import { normalizeArray } from './normalize-array'; + +describe('normalizeArray', () => { + it('should normalize an array-like object', () => { + const toSign = new Uint8Array([1, 2, 3]); + + const result = normalizeArray(toSign); + + expect(result).toEqual([1, 2, 3]); + }); + + it('should normalize a Buffer', () => { + const toSign = Buffer.from('hello'); + + const result = normalizeArray(toSign); + + expect(result).toEqual([104, 101, 108, 108, 111]); + }); + + it('should normalize a Buffer from ethers', () => { + const toSign = ethers.utils.toUtf8Bytes('hello'); + + const result = normalizeArray(toSign); + + expect(result).toEqual([104, 101, 108, 108, 111]); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts new file mode 100644 index 0000000000..2da12ecbe7 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts @@ -0,0 +1,15 @@ +/** + * Converts an ArrayLike object to a regular array. + * + * Context: the nodes will only accept a normal array type as a paramater due to serizalization issues with Uint8Array type. this loop below is to normalize the message to a basic array. + * + * @param toSign - The ArrayLike object to be converted. + * @returns The converted array.´ + */ +export const normalizeArray = (toSign: ArrayLike) => { + const arr = []; + for (let i = 0; i < toSign.length; i++) { + arr.push((toSign as Buffer)[i]); + } + return arr; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 54f77b9d0e..71c4cf444b 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -118,8 +118,10 @@ import type { JsonSignSessionKeyRequestV1, BlsResponseData, SessionKeyCache, + JsonPkpSignSdkParams, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; +import { normalizeArray } from './helpers/normalize-array'; const TEMP_CACHE_PERIOD = 30000; // 30 seconds @@ -1068,8 +1070,7 @@ export class LitNodeClientNodeJs this.getLitActionRequestBody(params); // -- choose the right signature - const sigToPassToNode = this.getSessionOrAuthSig({ - authSig, + const sigToPassToNode = this.getSessionSigByUrl({ sessionSigs, url, }); @@ -1577,7 +1578,7 @@ export class LitNodeClientNodeJs ): Promise | RejectedNodePromises> => { const nodePromises = this.getNodePromises((url: string) => { // -- choose the right signature - const sigToPassToNode = this.getSessionOrAuthSig({ + const sigToPassToNode = this.getSessionSigByUrl({ authSig, sessionSigs, url, @@ -1741,13 +1742,19 @@ export class LitNodeClientNodeJs return returnVal; }; - pkpSign = async (params: JsonPkpSignRequest) => { - let { authSig, sessionSigs, toSign, pubKey, authMethods } = params; - - pubKey = hexPrefixed(pubKey); - + /** + * Use PKP to sign + * + * @param { JsonPkpSignSdkParams } params + * @param params.toSign - The data to sign + * @param params.pubKey - The public key to sign with + * @param params.sessionSigs - The session signatures to use + * @param params.authMethods - (optional) The auth methods to use + */ + pkpSign = async (params: JsonPkpSignSdkParams) => { // -- validate required params - (['toSign', 'pubKey'] as (keyof JsonPkpSignRequest)[]).forEach((key) => { + const requiredParamKeys = ['toSign', 'pubKey']; + (requiredParamKeys as (keyof JsonPkpSignSdkParams)[]).forEach((key) => { if (!params[key]) { throwError({ message: `"${key}" cannot be undefined, empty, or null. Please provide a valid value.`, @@ -1758,42 +1765,42 @@ export class LitNodeClientNodeJs }); // -- validate present of accepted auth methods - if (!authSig && !sessionSigs && (!authMethods || authMethods.length <= 0)) { + if ( + !params.sessionSigs && + (!params.authMethods || params.authMethods.length <= 0) + ) { throwError({ - message: `Either authSig, sessionSigs, or authMethods (length > 0) must be present.`, + message: `Either sessionSigs or authMethods (length > 0) must be present.`, errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, }); } - // the nodes will only accept a normal array type as a paramater due to serizalization issues with Uint8Array type. - // this loop below is to normalize the message to a basic array. - const arr = []; - for (let i = 0; i < toSign.length; i++) { - arr.push((toSign as Buffer)[i]); - } - toSign = arr; + // yes, 'key' is in lower case, because this is what the node expects + const pubkey = hexPrefixed(params.pubKey); + + const normalizedToSignArray = normalizeArray(params.toSign); const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { const nodePromises = this.getNodePromises((url: string) => { - // -- choose the right signature - const sigToPassToNode = this.getSessionOrAuthSig({ - authSig, - sessionSigs, + // -- get the session sig from the url key + const sessionSig = this.getSessionSigByUrl({ + sessionSigs: params.sessionSigs, url, - mustHave: false, }); - logWithRequestId(id, 'sigToPassToNode:', sigToPassToNode); + const hasAuthMethod = + params.authMethods && params.authMethods.length > 0; - const reqBody = { - toSign, - pubkey: pubKey, - ...(sigToPassToNode && - sigToPassToNode !== undefined && { authSig: sigToPassToNode }), - ...(authMethods && authMethods.length > 0 && { authMethods }), + const reqBody: JsonPkpSignRequest = { + toSign: normalizedToSignArray, + pubkey: pubkey, + authSig: sessionSig, + ...(hasAuthMethod && { + authMethods: params.authMethods, + }), }; logWithRequestId(id, 'reqBody:', reqBody); diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 8ffafc8abd..67f1c4da2e 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -244,17 +244,7 @@ export interface BaseJsonExecutionRequest { authMethods?: AuthMethod[]; } -export interface WithAuthSig extends BaseJsonExecutionRequest { - authSig: AuthSig; - sessionSigs?: any; -} - -export interface WithSessionSigs extends BaseJsonExecutionRequest { - sessionSigs: any; - authSig?: AuthSig; -} - -export type JsonExecutionRequest = WithAuthSig | WithSessionSigs; +export type JsonExecutionRequest = {} & BaseJsonExecutionRequest; export interface JsExecutionRequestBody { authSig?: AuthSig; @@ -266,32 +256,26 @@ export interface JsExecutionRequestBody { export interface BaseJsonPkpSignRequest { toSign: ArrayLike; - pubKey: string; + pubkey: string; // yes, pub"key" is lower case in the node. + authMethods?: AuthMethod[]; } -export interface WithAuthMethodSigning extends BaseJsonPkpSignRequest { - // auth methods to resolve - authMethods: AuthMethod[]; - sessionSigs?: any; - authSig?: AuthSig; -} -export interface WithSessionSigsSigning extends BaseJsonPkpSignRequest { - sessionSigs: any; - authSig?: AuthSig; - authMethods?: AuthMethod[]; +/** + * The 'pkpSign' function param. Please note that the structure + * is different than the payload sent to the node. + */ +export interface JsonPkpSignSdkParams extends BaseJsonPkpSignRequest { + pubKey: string; + sessionSigs: SessionSigsMap; } -export interface WithAuthSigSigning extends BaseJsonPkpSignRequest { +/** + * The actual payload structure sent to the node /pkp/sign endpoint. + */ +export interface JsonPkpSignRequest extends BaseJsonPkpSignRequest { authSig: AuthSig; - sessionSigs?: any; - authMethods?: AuthMethod[]; } -export type JsonPkpSignRequest = - | WithSessionSigsSigning - | WithAuthSigSigning - | WithAuthMethodSigning; - /** * Struct in rust * ----- @@ -377,7 +361,7 @@ export interface JsonAccsRequest extends MultipleAccessControlConditions { // The authentication signature that proves that the user owns the crypto wallet address that meets the access control conditions authSig?: AuthSig; - sessionSigs?: SessionSig; + sessionSigs?: SessionSigsMap; } /** @@ -412,7 +396,7 @@ export interface SigningAccessControlConditionRequest chain?: string; // The authentication signature that proves that the user owns the crypto wallet address that meets the access control conditions - authSig?: SessionSig; + authSig?: AuthSig; iat?: number; exp?: number; @@ -1005,17 +989,9 @@ export type AuthCallback = (params: AuthCallbackParams) => Promise; * A map of node addresses to the session signature payload * for that node specifically. */ -export type SessionSigsMap = Record; - -export interface SessionSig { - sig: string; - derivedVia: string; - signedMessage: string; - address: string; - algo?: string; -} +export type SessionSigsMap = Record; -export type SessionSigs = Record; +export type SessionSigs = Record; export interface SessionRequestBody { sessionKey: string; From 45f9eed7d639e30493af358ad348e1486092ddf1 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 26 Apr 2024 22:25:31 +0100 Subject: [PATCH 038/263] feat(remove-authSig): 1. Removed authSig and use sessionSigs 2. Moved all parsers/helpers to its own folder with unit tests 3. Updated `ExecuteJsProps` type to `JsonExecutionSdkParams` type and `JsonExecutionRequest` type to nodes 4. --- packages/contracts-sdk/src/lib/auth-utils.ts | 2 +- packages/core/src/lib/lit-core.ts | 1 - .../encryption/src/lib/params-validators.ts | 43 +- .../src/lib/helpers/encode-code.test.ts | 31 + .../src/lib/helpers/encode-code.ts | 17 + .../src/lib/helpers/get-claims-list.test.ts | 89 ++ .../src/lib/helpers/get-claims-list.ts | 30 + .../src/lib/helpers/get-claims.test.ts | 133 +++ .../src/lib/helpers/get-claims.ts | 41 + .../src/lib/helpers/get-signatures.test.ts | 86 ++ .../src/lib/helpers/get-signatures.ts | 251 ++++++ .../src/lib/helpers/normalize-params.test.ts | 100 +++ .../src/lib/helpers/normalize-params.ts | 24 + .../helpers/parse-as-json-or-string.test.ts | 21 + .../lib/helpers/parse-as-json-or-string.ts | 21 + .../lib/helpers/remove-double-quotes.test.ts | 51 ++ .../src/lib/helpers/remove-double-quotes.ts | 20 + .../src/lib/lit-node-client-nodejs.ts | 792 ++++-------------- packages/misc/src/lib/misc.spec.ts | 248 ++++++ packages/misc/src/lib/misc.ts | 67 +- packages/pkp-base/src/lib/pkp-base.ts | 23 +- packages/types/src/lib/ILitNodeClient.ts | 52 +- packages/types/src/lib/interfaces.ts | 189 +++-- 23 files changed, 1516 insertions(+), 816 deletions(-) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/encode-code.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/encode-code.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-claims.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-claims.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.ts diff --git a/packages/contracts-sdk/src/lib/auth-utils.ts b/packages/contracts-sdk/src/lib/auth-utils.ts index 98c55093c8..6e7d379359 100644 --- a/packages/contracts-sdk/src/lib/auth-utils.ts +++ b/packages/contracts-sdk/src/lib/auth-utils.ts @@ -1,4 +1,4 @@ -import { SessionSig, StytchToken } from '@lit-protocol/types'; +import { StytchToken } from '@lit-protocol/types'; import { ethers } from 'ethers'; import * as jose from 'jose'; /** diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 293eebe194..4176bb87a5 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -54,7 +54,6 @@ import type { NodeErrorV3, RejectedNodePromises, SendNodeCommand, - SessionSig, SessionSigsMap, SuccessNodePromises, SupportedJsonRequests, diff --git a/packages/encryption/src/lib/params-validators.ts b/packages/encryption/src/lib/params-validators.ts index 3e687b4cdd..b221a0f685 100644 --- a/packages/encryption/src/lib/params-validators.ts +++ b/packages/encryption/src/lib/params-validators.ts @@ -34,9 +34,10 @@ import { EncryptToJsonProps, EncryptZipRequest, EvmContractConditions, - ExecuteJsProps, GetSignedTokenRequest, + JsonExecutionSdkParams, SessionSigs, + SessionSigsMap, SolRpcConditions, UnifiedAccessControlConditions, } from '@lit-protocol/types'; @@ -71,7 +72,7 @@ export const paramsValidators: Record< string, (params: any) => ParamsValidator[] > = { - executeJs: (params: ExecuteJsProps) => [ + executeJs: (params: JsonExecutionSdkParams) => [ new AuthMaterialValidator('executeJs', params), new ExecuteJsValidator('executeJs', params), new AuthMethodValidator('executeJs', params.authMethods), @@ -379,8 +380,7 @@ class FileValidator implements ParamsValidator { } export interface AuthMaterialValidatorProps { - authSig?: AuthSig; - sessionSigs?: SessionSigs; + sessionSigs?: SessionSigsMap; chain?: string; } @@ -400,14 +400,7 @@ class AuthMaterialValidator implements ParamsValidator { } validate(): IEither { - const { authSig, sessionSigs } = this.authMaterial; - - if (authSig && !is(authSig, 'Object', 'authSig', this.fnName)) - return ELeft({ - message: 'authSig is not an object', - errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, - errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, - }); + const { sessionSigs } = this.authMaterial; if (this.checkIfAuthSigRequiresChainParam) { if (!this.authMaterial.chain) @@ -416,20 +409,6 @@ class AuthMaterialValidator implements ParamsValidator { errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); - - if ( - authSig && - !checkIfAuthSigRequiresChainParam( - authSig, - this.authMaterial.chain, - this.fnName - ) - ) - return ELeft({ - message: 'authSig is not valid', - errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, - errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, - }); } if (sessionSigs && !is(sessionSigs, 'Object', 'sessionSigs', this.fnName)) @@ -439,17 +418,9 @@ class AuthMaterialValidator implements ParamsValidator { errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, }); - if (!sessionSigs && !authSig) - return ELeft({ - message: 'You must pass either authSig or sessionSigs', - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - - // -- validate: if sessionSig and authSig exists - if (sessionSigs && authSig) + if (!sessionSigs) return ELeft({ - message: 'You cannot have both authSig and sessionSigs', + message: 'You must pass in sessionSigs', errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/encode-code.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/encode-code.test.ts new file mode 100644 index 0000000000..9cf408584c --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/encode-code.test.ts @@ -0,0 +1,31 @@ +import { encodeCode } from './encode-code'; + +describe('encodeCode', () => { + it('should encode a string to base64', () => { + const code = 'console.log("Hello, World!")'; + const encodedCode = encodeCode(code); + + expect(encodedCode).toEqual('Y29uc29sZS5sb2coIkhlbGxvLCBXb3JsZCEiKQ=='); + }); + + it('should handle empty string', () => { + const code = ''; + const encodedCode = encodeCode(code); + + expect(encodedCode).toEqual(''); + }); + + it('should handle special characters', () => { + const code = 'const x = 10 + 5 - 3 * 2 / 1;'; + const encodedCode = encodeCode(code); + + expect(encodedCode).toEqual('Y29uc3QgeCA9IDEwICsgNSAtIDMgKiAyIC8gMTs='); + }); + + it('should handle non-ASCII characters', () => { + const code = 'const name = "Jérémy";'; + const encodedCode = encodeCode(code); + + expect(encodedCode).toEqual('Y29uc3QgbmFtZSA9ICJKw6lyw6lteSI7'); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/encode-code.ts b/packages/lit-node-client-nodejs/src/lib/helpers/encode-code.ts new file mode 100644 index 0000000000..1b45f2c58a --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/encode-code.ts @@ -0,0 +1,17 @@ +import { + uint8arrayFromString, + uint8arrayToString, +} from '@lit-protocol/uint8arrays'; + +/** + * Encodes the given code string into base64 format. + * + * @param code - The code string to be encoded. + * @returns The encoded code string in base64 format. + */ +export const encodeCode = (code: string) => { + const _uint8Array = uint8arrayFromString(code, 'utf8'); + const encodedJs = uint8arrayToString(_uint8Array, 'base64'); + + return encodedJs; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.test.ts new file mode 100644 index 0000000000..499034e6a5 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.test.ts @@ -0,0 +1,89 @@ +import { NodeShare } from '@lit-protocol/types'; +import { getClaimsList } from './get-claims-list'; + +describe('getClaimsList', () => { + it('should return an empty array if responseData is empty', () => { + const responseData: NodeShare[] = []; + const result = getClaimsList(responseData); + expect(result).toEqual([]); + }); + + it('should parse the real data correctly', () => { + const responseData = [ + { + success: true, + signedData: {}, + decryptedData: {}, + claimData: { + foo: { + signature: + '36ffccaec30f52730dcc6fa411383dd23233be55da5bce7e9e0161dc88cfd0541a7f18f9dbb37677f660bc812ff6d29c1c3f92cb7245c0e20f97787ff3324ad31c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + response: '', + logs: '', + }, + { + success: true, + signedData: {}, + decryptedData: {}, + claimData: { + foo: { + signature: + 'ac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d070c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce71b', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + response: '', + logs: '', + }, + { + success: true, + signedData: {}, + decryptedData: {}, + claimData: { + foo: { + signature: + 'fd5bad778bd70ece43616c0531b13a70bf9b0a853d38aa7b92560a0070e59e7b619979bc79b1ac2dc6886b44a2bdb402e5804a00d010f415d8cf5c6673540d131c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + response: '', + logs: '', + }, + ] as NodeShare[]; + + const result = getClaimsList(responseData); + + expect(result).toEqual([ + { + foo: { + signature: + '36ffccaec30f52730dcc6fa411383dd23233be55da5bce7e9e0161dc88cfd0541a7f18f9dbb37677f660bc812ff6d29c1c3f92cb7245c0e20f97787ff3324ad31c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + { + foo: { + signature: + 'ac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d070c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce71b', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + { + foo: { + signature: + 'fd5bad778bd70ece43616c0531b13a70bf9b0a853d38aa7b92560a0070e59e7b619979bc79b1ac2dc6886b44a2bdb402e5804a00d010f415d8cf5c6673540d131c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + ]); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.ts new file mode 100644 index 0000000000..64d08fcc8b --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims-list.ts @@ -0,0 +1,30 @@ +import { ClaimsList, NodeShare } from '@lit-protocol/types'; + +/** + * Retrieves a list of claims from the provided response data. + * @param responseData The response data containing the claims. + * @returns An array of claims. + */ +export const getClaimsList = (responseData: NodeShare[]): ClaimsList => { + const claimsList = responseData + .map((r) => { + const { claimData } = r; + if (claimData) { + for (const key of Object.keys(claimData)) { + for (const subkey of Object.keys(claimData[key])) { + if (typeof claimData[key][subkey] == 'string') { + claimData[key][subkey] = claimData[key][subkey].replaceAll( + '"', + '' + ); + } + } + } + return claimData; + } + return null; + }) + .filter((item) => item !== null); + + return claimsList as unknown as ClaimsList; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-claims.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims.test.ts new file mode 100644 index 0000000000..8db4df5596 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims.test.ts @@ -0,0 +1,133 @@ +import { getClaims } from './get-claims'; + +describe('getClaims', () => { + it('should return the correct claims object', () => { + const claims = [ + { + foo: { + signature: + '36ffccaec30f52730dcc6fa411383dd23233be55da5bce7e9e0161dc88cfd0541a7f18f9dbb37677f660bc812ff6d29c1c3f92cb7245c0e20f97787ff3324ad31c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + { + foo: { + signature: + 'ac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d070c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce71b', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + { + foo: { + signature: + 'fd5bad778bd70ece43616c0531b13a70bf9b0a853d38aa7b92560a0070e59e7b619979bc79b1ac2dc6886b44a2bdb402e5804a00d010f415d8cf5c6673540d131c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + ]; + + const expectedClaims = { + foo: { + signatures: [ + { + r: '0x36ffccaec30f52730dcc6fa411383dd23233be55da5bce7e9e0161dc88cfd054', + s: '0x1a7f18f9dbb37677f660bc812ff6d29c1c3f92cb7245c0e20f97787ff3324ad3', + v: 28, + }, + { + r: '0xac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d0', + s: '0x70c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce7', + v: 27, + }, + { + r: '0xfd5bad778bd70ece43616c0531b13a70bf9b0a853d38aa7b92560a0070e59e7b', + s: '0x619979bc79b1ac2dc6886b44a2bdb402e5804a00d010f415d8cf5c6673540d13', + v: 28, + }, + ], + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }; + + const result = getClaims(claims); + + expect(result).toEqual(expectedClaims); + }); + + it('should return the correct claims object with different claims', () => { + ``; + const claims = [ + { + foo: { + signature: + '36ffccaec30f52730dcc6fa411383dd23233be55da5bce7e9e0161dc88cfd0541a7f18f9dbb37677f660bc812ff6d29c1c3f92cb7245c0e20f97787ff3324ad31c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + bar: { + signature: + 'ac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d070c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce71b', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + { + foo: { + signature: + 'fd5bad778bd70ece43616c0531b13a70bf9b0a853d38aa7b92560a0070e59e7b619979bc79b1ac2dc6886b44a2bdb402e5804a00d010f415d8cf5c6673540d131c', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + bar: { + signature: + 'ac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d070c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce71b', + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }, + ]; + + const expectedClaims = { + foo: { + signatures: [ + { + r: '0x36ffccaec30f52730dcc6fa411383dd23233be55da5bce7e9e0161dc88cfd054', + s: '0x1a7f18f9dbb37677f660bc812ff6d29c1c3f92cb7245c0e20f97787ff3324ad3', + v: 28, + }, + { + r: '0xfd5bad778bd70ece43616c0531b13a70bf9b0a853d38aa7b92560a0070e59e7b', + s: '0x619979bc79b1ac2dc6886b44a2bdb402e5804a00d010f415d8cf5c6673540d13', + v: 28, + }, + ], + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + bar: { + signatures: [ + { + r: '0xac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d0', + s: '0x70c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce7', + v: 27, + }, + { + r: '0xac4e1b37a969af3a03331dabb9418d137cec9e8b366ff7cafcf6688ff07b15d0', + s: '0x70c42c8c16b0f945ea03653a0d286f2f59fdef529db38e7c33b65aae4b287ce7', + v: 27, + }, + ], + derivedKeyId: + '22c14f271322473459c456056ffc6e1c0dc1efcb2d15e5be538ad081b224b3d0', + }, + }; + + const result = getClaims(claims); + + expect(result).toEqual(expectedClaims); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-claims.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims.ts new file mode 100644 index 0000000000..8bc984efe4 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-claims.ts @@ -0,0 +1,41 @@ +import { Signature } from '@lit-protocol/types'; +import { ethers } from 'ethers'; + +/** + * Retrieves the claims from an array of objects and organizes them into a record. + * Each claim is associated with its corresponding signatures and derived key ID. + * + * @param claims - An array of objects representing the claims. + * @returns A record where each key represents a claim, and the value is an object containing the claim's signatures and derived key ID. + */ +export const getClaims = ( + claims: any[] +): Record => { + const keys: string[] = Object.keys(claims[0]); + const signatures: Record = {}; + const claimRes: Record< + string, + { signatures: Signature[]; derivedKeyId: string } + > = {}; + for (let i = 0; i < keys.length; i++) { + const claimSet: { signature: string; derivedKeyId: string }[] = claims.map( + (c) => c[keys[i]] + ); + signatures[keys[i]] = []; + claimSet.map((c) => { + const sig = ethers.utils.splitSignature(`0x${c.signature}`); + const convertedSig = { + r: sig.r, + s: sig.s, + v: sig.v, + }; + signatures[keys[i]].push(convertedSig); + }); + + claimRes[keys[i]] = { + signatures: signatures[keys[i]], + derivedKeyId: claimSet[0].derivedKeyId, + }; + } + return claimRes; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts new file mode 100644 index 0000000000..cdd9e82636 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts @@ -0,0 +1,86 @@ +import { initWasmEcdsaSdk } from '@lit-protocol/ecdsa-sdk'; + +import { getSignatures } from './get-signatures'; + +describe('getSignatures', () => { + beforeAll(async () => { + await initWasmEcdsaSdk(); + }); + + it('should return signatures object', () => { + const networkPubKeySet = 'testing'; + const minNodeCount = 1; + const signedData = [ + { + sig: { + sigType: 'K256', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + { + sig: { + sigType: 'K256', + dataSigned: + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4', + signatureShare: + '1301BE04CF3A269709C2BDC29F7EFD1FBB3FC037C00AD2B5BDA8726B74CB5AF4', + shareIndex: 0, + bigR: '0290947D801A421D4A347FFFD386703C97BEF8E8AC83C3AB256ACE09255C37C521', + publicKey: + '04423427A87DEE9420BAC5C38355FE4A8C30EA796D87950C0143B49422D88C8FC70C381CB45300D8AD8A95139FFEEA5F265EFE00B65481BBB97B311C6833B69AE3', + sigName: 'sig', + }, + }, + { + sig: { + sigType: 'K256', + dataSigned: + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4', + signatureShare: + 'F649B4CEAEE015877161AC8F062270200F65EC166C9BD7BF6F877EBB345F2F8F', + shareIndex: 0, + bigR: '0290947D801A421D4A347FFFD386703C97BEF8E8AC83C3AB256ACE09255C37C521', + publicKey: + '04423427A87DEE9420BAC5C38355FE4A8C30EA796D87950C0143B49422D88C8FC70C381CB45300D8AD8A95139FFEEA5F265EFE00B65481BBB97B311C6833B69AE3', + sigName: 'sig', + }, + }, + ]; + const requestId = ''; + + const signatures = getSignatures({ + networkPubKeySet, + minNodeCount, + signedData, + requestId, + }); + + expect(signatures.sig).toHaveProperty('dataSigned'); + expect(signatures.sig).toHaveProperty('publicKey'); + expect(signatures.sig).toHaveProperty('r'); + expect(signatures.sig).toHaveProperty('recid'); + expect(signatures.sig).toHaveProperty('s'); + expect(signatures.sig).toHaveProperty('signature'); + expect(signatures.sig.dataSigned).toBe( + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4' + ); + expect(signatures.sig.publicKey).toBe( + '04423427A87DEE9420BAC5C38355FE4A8C30EA796D87950C0143B49422D88C8FC70C381CB45300D8AD8A95139FFEEA5F265EFE00B65481BBB97B311C6833B69AE3' + ); + expect(signatures.sig.r).toBe( + '90947d801a421d4a347fffd386703c97bef8e8ac83c3ab256ace09255c37c521' + ); + expect(signatures.sig.recid).toBe(0); + expect(signatures.sig.s).toBe( + '094b72d37e1a3c1e7b246a51a5a16d410ff6cf677d5e0a396d5d9299d8f44942' + ); + expect(signatures.sig.signature).toBe( + '0x90947d801a421d4a347fffd386703c97bef8e8ac83c3ab256ace09255c37c521094b72d37e1a3c1e7b246a51a5a16d410ff6cf677d5e0a396d5d9299d8f449421b' + ); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts new file mode 100644 index 0000000000..9a5b1e5bd5 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts @@ -0,0 +1,251 @@ +import { LIT_CURVE, LIT_ERROR } from '@lit-protocol/constants'; +import { combineEcdsaShares } from '@lit-protocol/crypto'; +import { + logErrorWithRequestId, + logWithRequestId, + mostCommonString, + throwError, +} from '@lit-protocol/misc'; +import { SigResponse, SigShare } from '@lit-protocol/types'; +import { joinSignature } from 'ethers/lib/utils'; + +export const getFlattenShare = (share: any): SigShare => { + // flatten the signature object so that the properties of the signature are top level + const flattenObj = Object.entries(share).map(([key, item]) => { + if (item === null || item === undefined) { + return null; + } + + const typedItem = item as SigShare; + + const requiredShareProps = [ + 'sigType', + 'dataSigned', + 'signatureShare', + 'shareIndex', + 'bigR', + 'publicKey', + ]; + + const requiredSessionSigsShareProps = [ + ...requiredShareProps, + 'siweMessage', + ] as const; + + const requiredSignatureShareProps = [ + ...requiredShareProps, + 'sigName', + ] as const; + + const hasProps = (props: any) => { + return [...props].every( + (prop) => + typedItem[prop as keyof SigShare] !== undefined && + typedItem[prop as keyof SigShare] !== null + ); + }; + + if ( + hasProps(requiredSessionSigsShareProps) || + hasProps(requiredSignatureShareProps) + ) { + const bigR = typedItem.bigR ?? typedItem.bigr; + + typedItem.signatureShare = (typedItem.signatureShare ?? '').replaceAll( + '"', + '' + ); + typedItem.bigR = (bigR ?? '').replaceAll('"', ''); + typedItem.publicKey = (typedItem.publicKey ?? '').replaceAll('"', ''); + typedItem.dataSigned = (typedItem.dataSigned ?? '').replaceAll('"', ''); + + return typedItem; + } + + return null; + }); + + // removed all null values and should only have one item + const flattenShare = flattenObj.filter( + (item) => item !== null + )[0] as SigShare; + + if (flattenShare === null || flattenShare === undefined) { + return share; + } + return flattenShare; +}; + +/** + * + * Get signatures from signed data + * + * @param { Array } signedData + * + * @returns { any } + * + */ +export const getSignatures = ({ + networkPubKeySet, + minNodeCount, + signedData, + requestId = '', +}: { + networkPubKeySet: any; + minNodeCount: number; + signedData: any[]; + requestId: string; +}): { sig: SigResponse } => { + const initialKeys = [...new Set(signedData.flatMap((i) => Object.keys(i)))]; + + // processing signature shares for failed or invalid contents. mutates the signedData object. + for (const signatureResponse of signedData) { + for (const sigName of Object.keys(signatureResponse)) { + const requiredFields = ['signatureShare']; + + for (const field of requiredFields) { + if (!signatureResponse[sigName][field]) { + logWithRequestId( + requestId, + `invalid field ${field} in signature share: ${sigName}, continuing with share processing` + ); + // destructive operation on the object to remove invalid shares inline, without a new collection. + delete signatureResponse[sigName]; + } else { + let share = getFlattenShare(signatureResponse[sigName]); + + share = { + sigType: share.sigType, + signatureShare: share.signatureShare, + shareIndex: share.shareIndex, + bigR: share.bigR, + publicKey: share.publicKey, + dataSigned: share.dataSigned, + sigName: share.sigName ? share.sigName : 'sig', + }; + signatureResponse[sigName] = share; + } + } + } + } + + const validatedSignedData = signedData; + + // -- prepare + const signatures: any = {}; + + // get all signature shares names from all node responses. + // use a set to filter duplicates and copy into an array + const allKeys = [ + ...new Set(validatedSignedData.flatMap((i) => Object.keys(i))), + ]; + + if (allKeys.length !== initialKeys.length) { + throwError({ + message: 'total number of valid signatures does not match requested', + errorKind: LIT_ERROR.NO_VALID_SHARES.kind, + errorCode: LIT_ERROR.NO_VALID_SHARES.code, + }); + } + + // -- combine + for (var i = 0; i < allKeys.length; i++) { + // here we use a map filter implementation to find common shares in each node response. + // we then filter out undefined object from the key access. + // currently we are unable to know the total signature count requested by the user. + // but this allows for incomplete sets of signature shares to be aggregated + // and then checked against threshold + const shares = validatedSignedData + .map((r: any) => r[allKeys[i]]) + .filter((r: any) => r !== undefined); + + shares.sort((a: any, b: any) => a.shareIndex - b.shareIndex); + + const sigName = shares[0].sigName; + logWithRequestId( + requestId, + `starting signature combine for sig name: ${sigName}`, + shares + ); + logWithRequestId( + requestId, + `number of shares for ${sigName}:`, + signedData.length + ); + logWithRequestId( + requestId, + `validated length for signature: ${sigName}`, + shares.length + ); + logWithRequestId( + requestId, + 'minimum required shares for threshold:', + minNodeCount + ); + + if (shares.length < minNodeCount) { + logErrorWithRequestId( + requestId, + `not enough nodes to get the signatures. Expected ${minNodeCount}, got ${shares.length}` + ); + + throwError({ + message: `The total number of valid signatures shares ${shares.length} does not meet the threshold of ${minNodeCount}`, + errorKind: LIT_ERROR.NO_VALID_SHARES.kind, + errorCode: LIT_ERROR.NO_VALID_SHARES.code, + requestId, + }); + } + + const sigType = mostCommonString(shares.map((s: any) => s.sigType)); + + // -- validate if this.networkPubKeySet is null + if (networkPubKeySet === null) { + return throwError({ + message: 'networkPubKeySet cannot be null', + errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, + errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, + }); + } + + // -- validate if signature type is ECDSA + if ( + sigType !== LIT_CURVE.EcdsaCaitSith && + sigType !== LIT_CURVE.EcdsaK256 && + sigType !== LIT_CURVE.EcdsaCAITSITHP256 + ) { + return throwError({ + message: `signature type is ${sigType} which is invalid`, + errorKind: LIT_ERROR.UNKNOWN_SIGNATURE_TYPE.kind, + errorCode: LIT_ERROR.UNKNOWN_SIGNATURE_TYPE.name, + }); + } + + const signature = combineEcdsaShares(shares); + + console.log('signature:', signature); + + if (!signature.r) { + throwError({ + message: 'siganture could not be combined', + errorKind: LIT_ERROR.UNKNOWN_SIGNATURE_ERROR.kind, + errorCode: LIT_ERROR.UNKNOWN_SIGNATURE_ERROR.name, + }); + } + + const encodedSig = joinSignature({ + r: '0x' + signature.r, + s: '0x' + signature.s, + v: signature.recid, + }); + + signatures[allKeys[i]] = { + ...signature, + signature: encodedSig, + publicKey: mostCommonString(shares.map((s: any) => s.publicKey)), + dataSigned: mostCommonString(shares.map((s: any) => s.dataSigned)), + }; + } + + return signatures; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.test.ts new file mode 100644 index 0000000000..3c1c6be524 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.test.ts @@ -0,0 +1,100 @@ +import { ethers } from 'ethers'; +import { normalizeJsParams } from './normalize-params'; + +describe('normalizeJsParams', () => { + it('should convert ArrayBuffer to array', () => { + const jsParams = { + key1: new Uint8Array([1, 2, 3]).buffer, + key2: new Uint8Array([4, 5, 6]).buffer, + }; + + const normalizedParams = normalizeJsParams(jsParams); + + expect(normalizedParams.key1).toEqual([1, 2, 3]); + expect(normalizedParams.key2).toEqual([4, 5, 6]); + }); + + it('should not modify non-ArrayBuffer values', () => { + const jsParams = { + key1: [1, 2, 3], + key2: 'test', + key3: { prop: 'value' }, + }; + + const normalizedParams = normalizeJsParams(jsParams); + + expect(normalizedParams.key1).toEqual([1, 2, 3]); + expect(normalizedParams.key2).toEqual('test'); + expect(normalizedParams.key3).toEqual({ prop: 'value' }); + }); + + it('should handle empty object', () => { + const jsParams = {}; + + const normalizedParams = normalizeJsParams(jsParams); + + expect(normalizedParams).toEqual({}); + }); + + it('should handle real world example of jsParams', () => { + const jsParams = { + dataToSign: ethers.utils.arrayify( + ethers.utils.keccak256([1, 2, 3, 4, 5]) + ), + publicKey: + '04940acdc50052416b0458623a99a12cc5717959222bfa5dc0553702b91efcaf7527889af26cfad48ac6c96417a2f06412d22e06a98d856202809743b614403dd5', + }; + + const normalizedParams = normalizeJsParams(jsParams); + expect(normalizedParams.dataToSign).toEqual([ + 125, 135, 197, 234, 117, 247, 55, 139, 183, 1, 228, 4, 197, 6, 57, 22, 26, + 243, 239, 246, 98, 147, 233, 243, 117, 181, 241, 126, 181, 4, 118, 244, + ]); + }); + + it('should handle multiple types', () => { + const jsParams = { + foo: 'bar', + num: 123, + arr: [1, 2, 3], + obj: { + nested: 'value', + }, + uint8Arr: new Uint8Array([1, 2, 3]), + }; + + const normalizedParams = normalizeJsParams(jsParams); + + expect(normalizedParams).toEqual({ + foo: 'bar', + num: 123, + arr: [1, 2, 3], + obj: { + nested: 'value', + }, + uint8Arr: [1, 2, 3], + }); + }); + + it('should recursively convert nested objects', () => { + const jsParams = { + foo: 'bar', + obj: { + nested: { + deep: 'value', + }, + }, + }; + + const normalizedParams = normalizeJsParams(jsParams); + + expect(normalizedParams).toEqual({ + foo: 'bar', + obj: { + nested: { + deep: 'value', + }, + }, + }); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.ts b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.ts new file mode 100644 index 0000000000..753b77116b --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-params.ts @@ -0,0 +1,24 @@ +/** + * Normalize the `jsParams`, convert types before sending to Lit Actions as jsParams, some JS types don't serialize well, so we will convert them before sending to the nodes + * + * It converts both + * + * @param {any} jsParams - The jsParams you are sending to Lit Action + * + * * @returns { object } The jsParams object, but with any incompatible types automatically converted + */ +export const normalizeJsParams = (jsParams: any) => { + for (const key of Object.keys(jsParams)) { + const value = jsParams[key]; + if (ArrayBuffer.isView(value)) { + // Correctly converting ArrayBuffer view to a standard array + jsParams[key] = Array.from( + new Uint8Array(value.buffer, value.byteOffset, value.byteLength) + ); + } else if (value instanceof ArrayBuffer) { + // Correctly converting plain ArrayBuffer to a standard array + jsParams[key] = Array.from(new Uint8Array(value)); + } + } + return jsParams; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.test.ts new file mode 100644 index 0000000000..9311a6a9e3 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.test.ts @@ -0,0 +1,21 @@ +import { parseAsJsonOrString } from './parse-as-json-or-string'; + +describe('parseAsJsonOrString', () => { + it('should parse a valid JSON response', () => { + const responseString = '{"message": "Hello, World!"}'; + const expectedResponse = { message: 'Hello, World!' }; + + const result = parseAsJsonOrString(responseString); + + expect(result).toEqual(expectedResponse); + }); + + it('should return the response as string if parsing fails', () => { + const responseString = 'abcdefg'; + const expectedResponse = 'abcdefg'; + + const result = parseAsJsonOrString(responseString); + + expect(result).toEqual(expectedResponse); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.ts b/packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.ts new file mode 100644 index 0000000000..c980d2fea7 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/parse-as-json-or-string.ts @@ -0,0 +1,21 @@ +import { log } from '@lit-protocol/misc'; + +/** + * Parses a response string into a JS object. + * + * @param responseString - The response string to parse. + * @returns The parsed response object. + */ +export const parseAsJsonOrString = ( + responseString: string +): object | string => { + try { + return JSON.parse(responseString); + } catch (e) { + log( + '[parseResponses] Error parsing response as json. Swallowing and returning as string.', + responseString + ); + return responseString; + } +}; diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.test.ts new file mode 100644 index 0000000000..9bb118bd35 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.test.ts @@ -0,0 +1,51 @@ +import { removeDoubleQuotes } from './remove-double-quotes'; + +describe('removeDoubleQuotes', () => { + it('should remove double quotes from string values in the object', () => { + const obj = { + key1: { + subkey1: '"value1"', + subkey2: '"value2"', + }, + key2: { + subkey3: 'value3"', + }, + key3: { + subkey3: '"""""value3"""""', + }, + }; + + const expectedObj = { + key1: { + subkey1: 'value1', + subkey2: 'value2', + }, + key2: { + subkey3: 'value3', + }, + key3: { + subkey3: 'value3', + }, + }; + + const result = removeDoubleQuotes(obj); + + expect(result).toEqual(expectedObj); + }); + + it('should not modify the object if there are no string values with double quotes', () => { + const obj = { + key1: { + subkey1: 'value1', + subkey2: 'value2', + }, + key2: { + subkey3: 'value3', + }, + }; + + const result = removeDoubleQuotes(obj); + + expect(result).toEqual(obj); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.ts b/packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.ts new file mode 100644 index 0000000000..11109e8ca1 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/remove-double-quotes.ts @@ -0,0 +1,20 @@ +/** + * Sanitise strings in an object by removing double quotes. + * - remove quotes from the signed data eg '"walup"' => 'walup' + * @param obj The object to sanitize + * + * @returns The sanitized object + */ +export const removeDoubleQuotes = (obj: any) => { + for (const key of Object.keys(obj)) { + const value = (obj as any)[key]; + + for (const subkey of Object.keys(value)) { + if (typeof value[subkey] === 'string') { + value[subkey] = value[subkey].replaceAll('"', ''); + } + } + } + + return obj; +}; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 71c4cf444b..9dee40f4da 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -15,7 +15,6 @@ import { createSiweMessageWithCapacityDelegation, createSiweMessageWithRecaps, createSiweMessage, - LitRLIResource, } from '@lit-protocol/auth-helpers'; import { AUTH_METHOD_TYPE_IDS, @@ -28,11 +27,9 @@ import { LOCAL_STORAGE_KEYS, LitNetwork, LIT_CURVE, - SIWE_DELEGATION_URI, } from '@lit-protocol/constants'; import { LitCore, composeLitUrl } from '@lit-protocol/core'; import { - checkSevSnpAttestation, combineEcdsaShares, combineSignatureShares, encrypt, @@ -41,9 +38,9 @@ import { } from '@lit-protocol/crypto'; import { safeParams } from '@lit-protocol/encryption'; import { - convertLitActionsParams, defaultMintClaimCallback, executeWithRetry, + findMostCommonResponse, hexPrefixed, log, logError, @@ -77,7 +74,6 @@ import type { DecryptResponse, EncryptRequest, EncryptResponse, - ExecuteJsProps, ExecuteJsResponse, FormattedMultipleAccs, GetSessionSigsProps, @@ -86,14 +82,12 @@ import type { GetSigningShareForDecryptionRequest, GetWalletSigProps, JsonExecutionRequest, - JsonHandshakeResponse, JsonPkpSignRequest, LitClientSessionManager, LitNodeClientConfig, NodeBlsSigningShare, NodeCommandResponse, NodeLog, - NodeResponse, NodeShare, PKPSignShare, RejectedNodePromises, @@ -114,14 +108,25 @@ import type { GetPkpSessionSigs, CapacityCreditsReq, CapacityCreditsRes, - JsExecutionRequestBody, JsonSignSessionKeyRequestV1, BlsResponseData, SessionKeyCache, JsonPkpSignSdkParams, + JsonExecutionSdkParams, + ExecuteJsNoSigningResponse, + JsonExecutionSdkParamsTargetNode, + JsonExecutionRequestTargetNode, + SigResponse, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; import { normalizeArray } from './helpers/normalize-array'; +import { normalizeJsParams } from './helpers/normalize-params'; +import { encodeCode } from './helpers/encode-code'; +import { removeDoubleQuotes } from './helpers/remove-double-quotes'; +import { parseAsJsonOrString } from './helpers/parse-as-json-or-string'; +import { getFlattenShare, getSignatures } from './helpers/get-signatures'; +import { getClaimsList } from './helpers/get-claims-list'; +import { getClaims } from './helpers/get-claims'; const TEMP_CACHE_PERIOD = 30000; // 30 seconds @@ -143,38 +148,6 @@ export class LitNodeClientNodeJs } } - // ========== STATIC METHODS ========== - static getClaims = ( - claims: any[] - ): Record => { - const keys: string[] = Object.keys(claims[0]); - const signatures: Record = {}; - const claimRes: Record< - string, - { signatures: Signature[]; derivedKeyId: string } - > = {}; - for (let i = 0; i < keys.length; i++) { - const claimSet: { signature: string; derivedKeyId: string }[] = - claims.map((c) => c[keys[i]]); - signatures[keys[i]] = []; - claimSet.map((c) => { - const sig = ethers.utils.splitSignature(`0x${c.signature}`); - const convertedSig = { - r: sig.r, - s: sig.s, - v: sig.v, - }; - signatures[keys[i]].push(convertedSig); - }); - - claimRes[keys[i]] = { - signatures: signatures[keys[i]], - derivedKeyId: claimSet[0].derivedKeyId, - }; - } - return claimRes; - }; - // ========== Rate Limit NFT ========== // TODO: Add support for browser feature/lit-2321-js-sdk-add-browser-support-for-createCapacityDelegationAuthSig @@ -236,43 +209,6 @@ export class LitNodeClientNodeJs // ========== Scoped Class Helpers ========== - /** - * - * Get the request body of the lit action - * - * @param { ExecuteJsProps } params - * - * @returns { JsonExecutionRequest } - * - */ - getLitActionRequestBody = (params: ExecuteJsProps): JsonExecutionRequest => { - const reqBody: JsonExecutionRequest = { - ...(params.authSig && { authSig: params.authSig }), - ...(params.sessionSigs && { sessionSigs: params.sessionSigs }), - ...(params.authMethods && { authMethods: params.authMethods }), - jsParams: convertLitActionsParams(params.jsParams), - // singleNode: params.singleNode ?? false, - targetNodeRange: params.targetNodeRange ?? 0, - }; - - if (params.code) { - const _uint8Array = uint8arrayFromString(params.code, 'utf8'); - const encodedJs = uint8arrayToString(_uint8Array, 'base64'); - - reqBody.code = encodedJs; - } - - if (params.ipfsId) { - reqBody.ipfsId = params.ipfsId; - } - - if (params.authMethods && params.authMethods.length > 0) { - reqBody.authMethods = params.authMethods; - } - - return reqBody; - }; - /** * * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period @@ -286,30 +222,6 @@ export class LitNodeClientNodeJs return { iat, exp }; }; - /** - * - * Parse the response string to JSON - * - * @param { string } responseString - * - * @returns { any } JSON object - * - */ - parseResponses = (responseString: string): any => { - let response: any; - - try { - response = JSON.parse(responseString); - } catch (e) { - log( - 'Error parsing response as json. Swallowing and returning as string.', - responseString - ); - } - - return response; - }; - // ==================== SESSIONS ==================== /** * Try to get the session key in the local storage, @@ -677,74 +589,6 @@ export class LitNodeClientNodeJs }; // ==================== API Calls to Nodes ==================== - /** - * - * Get JS Execution Shares from Nodes - * - * @param { JsonExecutionRequest } params - * - * @returns { Promise } - */ - getJsExecutionShares = async ( - url: string, - params: JsonExecutionRequest, - requestId: string - ): Promise => { - const { code, ipfsId, authSig, jsParams, authMethods } = params; - - logWithRequestId(requestId, 'getJsExecutionShares'); - - // -- execute - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.EXECUTE_JS, - }); - - if (!authSig) { - throw new Error('authSig or sessionSig is required'); - } - const data: JsExecutionRequestBody = { - ...(authSig ? { authSig } : {}), - ...(code ? { code } : {}), - ...(ipfsId ? { ipfsId } : {}), - ...(authMethods ? { authMethods } : {}), - ...(jsParams ? { jsParams } : {}), - }; - - const res = await this.sendCommandToNode({ - url: urlWithPath, - data, - requestId, - }); - logWithRequestId( - requestId, - `response node with url: ${url} from endpoint ${urlWithPath}`, - res - ); - return res; - }; - - getPkpSignExecutionShares = async ( - url: string, - params: any, - requestId: string - ) => { - logWithRequestId(requestId, 'getPkpSigningShares'); - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.PKP_SIGN, - }); - if (!params.authSig) { - throw new Error('authSig is required'); - } - - return await this.sendCommandToNode({ - url: urlWithPath, - data: params, - requestId, - }); - }; - getClaimKeyExecutionShares = async ( url: string, params: any, @@ -946,27 +790,33 @@ export class LitNodeClientNodeJs // ========== Promise Handlers ========== getIpfsId = async ({ dataToHash, - authSig, - debug = false, + sessionSigs, }: { dataToHash: string; - authSig: AuthSig; + sessionSigs: SessionSigsMap; debug?: boolean; }) => { - const laRes = await this.executeJs({ - authSig, + const res = await this.executeJs({ ipfsId: LIT_ACTION_IPFS_HASH, + sessionSigs, authMethods: [], jsParams: { dataToHash, }, - debug, }).catch((e) => { logError('Error getting IPFS ID', e); throw e; }); - const data = JSON.parse(laRes.response).res; + let data; + + if (typeof res.response === 'string') { + try { + data = JSON.parse(res.response).res; + } catch (e) { + data = res.response; + } + } if (!data.success) { logError('Error getting IPFS ID', data.data); @@ -987,23 +837,13 @@ export class LitNodeClientNodeJs * */ runOnTargetedNodes = async ( - params: ExecuteJsProps + params: JsonExecutionSdkParamsTargetNode ): Promise< SuccessNodePromises | RejectedNodePromises > => { - const { - code, - authMethods, - authSig, - jsParams, - debug, - sessionSigs, - targetNodeRange, - } = params; - - log('running runOnTargetedNodes:', targetNodeRange); + log('running runOnTargetedNodes:', params.targetNodeRange); - if (!targetNodeRange) { + if (!params.targetNodeRange) { return throwError({ message: 'targetNodeRange is required', errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, @@ -1013,9 +853,8 @@ export class LitNodeClientNodeJs // determine which node to run on const ipfsId = await this.getIpfsId({ - dataToHash: code!, - authSig: authSig!, - debug, + dataToHash: params.code!, + sessionSigs: params.sessionSigs, }); // select targetNodeRange number of random index of the bootstrapUrls.length @@ -1023,7 +862,7 @@ export class LitNodeClientNodeJs let nodeCounter = 0; - while (randomSelectedNodeIndexes.length < targetNodeRange) { + while (randomSelectedNodeIndexes.length < params.targetNodeRange) { const str = `${nodeCounter}:${ipfsId.toString()}`; const cidBuffer = Buffer.from(str); const hash = sha256(cidBuffer); @@ -1066,19 +905,25 @@ export class LitNodeClientNodeJs log(`running on node ${nodeIndex} at ${url}`); - const reqBody: JsonExecutionRequest = - this.getLitActionRequestBody(params); - // -- choose the right signature - const sigToPassToNode = this.getSessionSigByUrl({ - sessionSigs, + const sessionSig = this.getSessionSigByUrl({ + sessionSigs: params.sessionSigs, url, }); - reqBody.authSig = sigToPassToNode; + const reqBody: JsonExecutionRequestTargetNode = { + ...params, + targetNodeRange: params.targetNodeRange, + authSig: sessionSig, + }; // this return { url: string, data: JsonRequest } - const singleNodePromise = this.getJsExecutionShares(url, reqBody, id); + // const singleNodePromise = this.getJsExecutionShares(url, reqBody, id); + const singleNodePromise = this.sendCommandToNode({ + url: url, + data: params, + requestId: id, + }); nodePromises.push(singleNodePromise); } @@ -1086,7 +931,7 @@ export class LitNodeClientNodeJs const handledPromise = (await this.handleNodePromises( nodePromises, id, - targetNodeRange + params.targetNodeRange )) as SuccessNodePromises | RejectedNodePromises; // -- handle response @@ -1104,71 +949,6 @@ export class LitNodeClientNodeJs ); }; - // ========== Shares Resolvers ========== - _getFlattenShare = (share: any): SigShare => { - // flatten the signature object so that the properties of the signature are top level - const flattenObj = Object.entries(share).map(([key, item]) => { - if (item === null || item === undefined) { - return null; - } - - const typedItem = item as SigShare; - - const requiredShareProps = [ - 'sigType', - 'dataSigned', - 'signatureShare', - 'shareIndex', - 'bigR', - 'publicKey', - ]; - - const requiredSessionSigsShareProps = [ - ...requiredShareProps, - 'siweMessage', - ] as const; - - const requiredSignatureShareProps = [ - ...requiredShareProps, - 'sigName', - ] as const; - - const hasProps = (props: any) => { - return [...props].every( - (prop) => - typedItem[prop as keyof SigShare] !== undefined && - typedItem[prop as keyof SigShare] !== null - ); - }; - - if ( - hasProps(requiredSessionSigsShareProps) || - hasProps(requiredSignatureShareProps) - ) { - const bigR = typedItem.bigR ?? typedItem.bigr; - - typedItem.signatureShare = typedItem.signatureShare.replaceAll('"', ''); - typedItem.bigR = bigR?.replaceAll('"', ''); - typedItem.publicKey = typedItem.publicKey.replaceAll('"', ''); - typedItem.dataSigned = typedItem.dataSigned.replaceAll('"', ''); - - return typedItem; - } - - return null; - }); - - // removed all null values and should only have one item - const flattenShare = flattenObj.filter( - (item) => item !== null - )[0] as SigShare; - - if (flattenShare === null || flattenShare === undefined) { - return share; - } - return flattenShare; - }; - /** * * Get signatures from signed data @@ -1211,7 +991,7 @@ export class LitNodeClientNodeJs const sigShares: SigShare[] = shares.map((s: any, index: number) => { log('Original Share Struct:', s); - const share = this._getFlattenShare(s); + const share = getFlattenShare(s); log('share:', share); @@ -1297,169 +1077,6 @@ export class LitNodeClientNodeJs return signatures; }; - /** - * - * Get signatures from signed data - * - * @param { Array } signedData - * - * @returns { any } - * - */ - getSignatures = (signedData: any[], requestId: string = ''): any => { - const initialKeys = [...new Set(signedData.flatMap((i) => Object.keys(i)))]; - - // processing signature shares for failed or invalid contents. mutates the signedData object. - for (const signatureResponse of signedData) { - for (const sigName of Object.keys(signatureResponse)) { - const requiredFields = ['signatureShare']; - - for (const field of requiredFields) { - if (!signatureResponse[sigName][field]) { - logWithRequestId( - requestId, - `invalid field ${field} in signature share: ${sigName}, continuing with share processing` - ); - // destructive operation on the object to remove invalid shares inline, without a new collection. - delete signatureResponse[sigName]; - } else { - let share = this._getFlattenShare(signatureResponse[sigName]); - - share = { - sigType: share.sigType, - signatureShare: share.signatureShare, - shareIndex: share.shareIndex, - bigR: share.bigR, - publicKey: share.publicKey, - dataSigned: share.dataSigned, - sigName: share.sigName ? share.sigName : 'sig', - }; - signatureResponse[sigName] = share; - } - } - } - } - - const validatedSignedData = signedData; - - // -- prepare - const signatures: any = {}; - - // get all signature shares names from all node responses. - // use a set to filter duplicates and copy into an array - const allKeys = [ - ...new Set(validatedSignedData.flatMap((i) => Object.keys(i))), - ]; - - if (allKeys.length !== initialKeys.length) { - throwError({ - message: 'total number of valid signatures does not match requested', - errorKind: LIT_ERROR.NO_VALID_SHARES.kind, - errorCode: LIT_ERROR.NO_VALID_SHARES.code, - }); - } - - // -- combine - for (var i = 0; i < allKeys.length; i++) { - // here we use a map filter implementation to find common shares in each node response. - // we then filter out undefined object from the key access. - // currently we are unable to know the total signature count requested by the user. - // but this allows for incomplete sets of signature shares to be aggregated - // and then checked against threshold - const shares = validatedSignedData - .map((r: any) => r[allKeys[i]]) - .filter((r: any) => r !== undefined); - - shares.sort((a: any, b: any) => a.shareIndex - b.shareIndex); - - const sigName = shares[0].sigName; - logWithRequestId( - requestId, - `starting signature combine for sig name: ${sigName}`, - shares - ); - logWithRequestId( - requestId, - `number of shares for ${sigName}:`, - signedData.length - ); - logWithRequestId( - requestId, - `validated length for signature: ${sigName}`, - shares.length - ); - logWithRequestId( - requestId, - 'minimum required shares for threshold:', - this.config.minNodeCount - ); - - if (shares.length < this.config.minNodeCount) { - logErrorWithRequestId( - requestId, - `not enough nodes to get the signatures. Expected ${this.config.minNodeCount}, got ${shares.length}` - ); - - throwError({ - message: `The total number of valid signatures shares ${shares.length} does not meet the threshold of ${this.config.minNodeCount}`, - errorKind: LIT_ERROR.NO_VALID_SHARES.kind, - errorCode: LIT_ERROR.NO_VALID_SHARES.code, - requestId, - }); - } - - const sigType = mostCommonString(shares.map((s: any) => s.sigType)); - - // -- validate if this.networkPubKeySet is null - if (this.networkPubKeySet === null) { - throwError({ - message: 'networkPubKeySet cannot be null', - errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, - errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, - }); - return; - } - - // -- validate if signature type is ECDSA - if ( - sigType !== LIT_CURVE.EcdsaCaitSith && - sigType !== LIT_CURVE.EcdsaK256 && - sigType !== LIT_CURVE.EcdsaCAITSITHP256 - ) { - throwError({ - message: `signature type is ${sigType} which is invalid`, - errorKind: LIT_ERROR.UNKNOWN_SIGNATURE_TYPE.kind, - errorCode: LIT_ERROR.UNKNOWN_SIGNATURE_TYPE.name, - }); - return; - } - - const signature = combineEcdsaShares(shares); - if (!signature.r) { - throwError({ - message: 'siganture could not be combined', - errorKind: LIT_ERROR.UNKNOWN_SIGNATURE_ERROR.kind, - errorCode: LIT_ERROR.UNKNOWN_SIGNATURE_ERROR.name, - }); - } - - const encodedSig = joinSignature({ - r: '0x' + signature.r, - s: '0x' + signature.s, - v: signature.recid, - }); - - signatures[allKeys[i]] = { - ...signature, - signature: encodedSig, - publicKey: mostCommonString(shares.map((s: any) => s.publicKey)), - dataSigned: mostCommonString(shares.map((s: any) => s.dataSigned)), - }; - } - - return signatures; - }; - /** * * Get a single signature @@ -1487,54 +1104,29 @@ export class LitNodeClientNodeJs // ========== Scoped Business Logics ========== // Normalize the data to a basic array - public static normalizeParams(params: ExecuteJsProps): ExecuteJsProps { - if (!params.jsParams) { - params.jsParams = {}; - return params; - } - for (const key of Object.keys(params.jsParams)) { - if ( - Array.isArray(params.jsParams[key]) || - ArrayBuffer.isView(params.jsParams[key]) - ) { - const arr = []; - for (let i = 0; i < params.jsParams[key].length; i++) { - arr.push((params.jsParams[key] as Buffer)[i]); - } - params.jsParams[key] = arr; - } - } - return params; - } + // TODO: executeJsWithTargettedNodes + // if (formattedParams.targetNodeRange) { + // // FIXME: we should make this a separate function + // res = await this.runOnTargetedNodes(formattedParams); + // } /** * * Execute JS on the nodes and combine and return any resulting signatures * - * @param { ExecuteJsRequest } params + * @param { JsonExecutionSdkParams } params * * @returns { ExecuteJsResponse } * */ - executeJs = async (params: ExecuteJsProps): Promise => { - // ========== Prepare Params ========== - const { - authMethods, - code, - ipfsId, - authSig, - jsParams, - debug, - sessionSigs, - targetNodeRange, - } = params; - + executeJs = async ( + params: JsonExecutionSdkParams + ): Promise => { // ========== Validate Params ========== - // -- validate: If it's NOT ready if (!this.ready) { const message = - '1 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; + '[executeJs] LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; throwError({ message, @@ -1556,61 +1148,70 @@ export class LitNodeClientNodeJs }); } - // Call the normalizeParams function to normalize the parameters - params = LitNodeClientNodeJs.normalizeParams(params); + // Format the params + const formattedParams: JsonExecutionSdkParams = { + ...params, + jsParams: normalizeJsParams(params.jsParams), + ...(params.code && { code: encodeCode(params.code) }), + }; - let res; - let requestId = ''; - // -- only run on a single node - if (targetNodeRange) { - res = await this.runOnTargetedNodes(params); - } else { - // ========== Prepare Variables ========== - // -- prepare request body - const reqBody: JsonExecutionRequest = - this.getLitActionRequestBody(params); - - // ========== Get Node Promises ========== - - // -- fetch shares from nodes - const wrapper = async ( - requestId: string - ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises((url: string) => { - // -- choose the right signature - const sigToPassToNode = this.getSessionSigByUrl({ - authSig, - sessionSigs, - url, - }); + // ========== Get Node Promises ========== + // Handle promises for commands sent to Lit nodes + const wrapper = async ( + requestId: string + ): Promise | RejectedNodePromises> => { + const nodePromises = this.getNodePromises(async (url: string) => { + // -- choose the right signature + const sessionSig = this.getSessionSigByUrl({ + sessionSigs: formattedParams.sessionSigs, + url, + }); - reqBody.authSig = sigToPassToNode; + const reqBody: JsonExecutionRequest = { + ...formattedParams, + authSig: sessionSig, + }; - const shares = this.getJsExecutionShares(url, reqBody, requestId); - return shares; + const composedUrl = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.EXECUTE_JS, }); - // -- resolve promises - res = await this.handleNodePromises( - nodePromises, + + const sharePromise = await this.sendCommandToNode({ + url: composedUrl, + data: reqBody, requestId, - this.connectedNodes.size - ); - return res; - }; - res = await executeWithRetry< - RejectedNodePromises | SuccessNodePromises - >( - wrapper, - (error: any, requestId: string, isFinal: boolean) => { - logError('an error occured, attempting to retry operation'); - }, - this.config.retryTolerance + }); + + return sharePromise; + }); + + // -- resolve promises + const res = await this.handleNodePromises( + nodePromises, + requestId, + this.connectedNodes.size ); - requestId = res.requestId; - } + return res; + }; // wrapper end + + // ========== Execute with Retry ========== + const res = await executeWithRetry< + RejectedNodePromises | SuccessNodePromises + >( + wrapper, + (error: any, requestId: string, isFinal: boolean) => { + logError('an error occured, attempting to retry operation'); + }, + this.config.retryTolerance + ); + + // ========== Handle Response ========== + const requestId = res.requestId; + // -- case: promises rejected - if (res.success === false) { + if (!res.success) { this._throwNodeError(res as RejectedNodePromises, requestId); } @@ -1623,47 +1224,37 @@ export class LitNodeClientNodeJs JSON.stringify(responseData, null, 2) ); - // -- in the case where we are not signing anything on Lit action and using it as purely serverless function - // we must also check for claim responses as a user may have submitted for a claim and signatures must be aggregated before returning - if ( - responseData[0].success && - Object.keys(responseData[0].signedData).length <= 0 && - Object.keys(responseData[0].claimData).length <= 0 - ) { - return responseData[0] as any as ExecuteJsResponse; + // -- find the responseData that has the most common response + const mostCommonResponse = findMostCommonResponse( + responseData + ) as NodeShare; + + const IS_SUCCESS = mostCommonResponse.success; + const HAS_SIGNED_DATA = + Object.keys(mostCommonResponse.signedData).length > 0; + const HAS_CLAIM_DATA = Object.keys(mostCommonResponse.claimData).length > 0; + + // -- we must also check for claim responses as a user may have submitted for a claim and signatures must be aggregated before returning + if (IS_SUCCESS && !HAS_SIGNED_DATA && !HAS_CLAIM_DATA) { + return mostCommonResponse as unknown as ExecuteJsResponse; } // -- in the case where we are not signing anything on Lit action and using it as purely serverless function - if ( - Object.keys(responseData[0].signedData).length <= 0 && - Object.keys(responseData[0].claimData).length <= 0 - ) { + if (!HAS_SIGNED_DATA && !HAS_CLAIM_DATA) { return { claims: {}, signatures: null, decryptions: [], - response: responseData[0].response, - logs: responseData[0].logs, - }; + response: mostCommonResponse.response, + logs: mostCommonResponse.logs, + } as ExecuteJsNoSigningResponse; } // ========== Extract shares from response data ========== + // -- 1. combine signed data as a list, and get the signatures from it const signedDataList = responseData.map((r) => { - const { signedData } = r; - for (const key of Object.keys(signedData)) { - for (const subkey of Object.keys(signedData[key])) { - //@ts-ignore - if (typeof signedData[key][subkey] === 'string') { - //@ts-ignore - signedData[key][subkey] = signedData[key][subkey].replaceAll( - '"', - '' - ); - } - } - } - return signedData; + return removeDoubleQuotes(r.signedData); }); logWithRequestId( @@ -1671,14 +1262,16 @@ export class LitNodeClientNodeJs 'signatures shares to combine: ', signedDataList ); - const signatures = this.getSignatures(signedDataList, requestId); - // -- 2. combine responses as a string, and get parse it as JSON - let response: string = mostCommonString( - responseData.map((r: NodeResponse) => r.response) - ); + const signatures = getSignatures({ + requestId, + networkPubKeySet: this.networkPubKeySet, + minNodeCount: this.config.minNodeCount, + signedData: signedDataList, + }); - response = this.parseResponses(response); + // -- 2. combine responses as a string, and parse it as JSON if possible + const parsedResponse = parseAsJsonOrString(mostCommonResponse.response); // -- 3. combine logs const mostCommonLogs: string = mostCommonString( @@ -1686,59 +1279,20 @@ export class LitNodeClientNodeJs ); // -- 4. combine claims - const claimsList = responseData - .map((r) => { - const { claimData } = r; - if (claimData) { - for (const key of Object.keys(claimData)) { - for (const subkey of Object.keys(claimData[key])) { - if (typeof claimData[key][subkey] == 'string') { - claimData[key][subkey] = claimData[key][subkey].replaceAll( - '"', - '' - ); - } - } - } - return claimData; - } - return null; - }) - .filter((item) => item !== null); - - // logWithRequestId(requestId, 'claimList:', claimsList); - - let claims = undefined; - - if (claimsList.length > 0) { - claims = LitNodeClientNodeJs.getClaims(claimsList); - } + const claimsList = getClaimsList(responseData); + const claims = claimsList.length > 0 ? getClaims(claimsList) : undefined; // ========== Result ========== const returnVal: ExecuteJsResponse = { claims, signatures, - decryptions: [], // FIXME: Fix if and when we enable decryptions from within a Lit Action. - response, + // decryptions: [], + response: parsedResponse, logs: mostCommonLogs, }; log('returnVal:', returnVal); - // -- case: debug mode - if (debug) { - const allNodeResponses = responseData.map( - (r: NodeResponse) => r.response - ); - const allNodeLogs = responseData.map((r: NodeLog) => r.logs); - - returnVal.debug = { - allNodeResponses, - allNodeLogs, - rawNodeHTTPResponses: responseData, - }; - } - return returnVal; }; @@ -1751,9 +1305,10 @@ export class LitNodeClientNodeJs * @param params.sessionSigs - The session signatures to use * @param params.authMethods - (optional) The auth methods to use */ - pkpSign = async (params: JsonPkpSignSdkParams) => { + pkpSign = async (params: JsonPkpSignSdkParams): Promise => { // -- validate required params const requiredParamKeys = ['toSign', 'pubKey']; + (requiredParamKeys as (keyof JsonPkpSignSdkParams)[]).forEach((key) => { if (!params[key]) { throwError({ @@ -1776,36 +1331,44 @@ export class LitNodeClientNodeJs }); } - // yes, 'key' is in lower case, because this is what the node expects - const pubkey = hexPrefixed(params.pubKey); - - const normalizedToSignArray = normalizeArray(params.toSign); - + // ========== Get Node Promises ========== + // Handle promises for commands sent to Lit nodes const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises((url: string) => { + const nodePromises = this.getNodePromises(async (url: string) => { // -- get the session sig from the url key const sessionSig = this.getSessionSigByUrl({ sessionSigs: params.sessionSigs, url, }); - const hasAuthMethod = - params.authMethods && params.authMethods.length > 0; - const reqBody: JsonPkpSignRequest = { - toSign: normalizedToSignArray, - pubkey: pubkey, + toSign: normalizeArray(params.toSign), + pubkey: hexPrefixed(params.pubKey), authSig: sessionSig, - ...(hasAuthMethod && { - authMethods: params.authMethods, - }), + + // -- optional params + ...(params.authMethods && + params.authMethods.length > 0 && { + authMethods: params.authMethods, + }), }; logWithRequestId(id, 'reqBody:', reqBody); - return this.getPkpSignExecutionShares(url, reqBody, id); + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.PKP_SIGN, + }); + + const sharePromise = await this.sendCommandToNode({ + url: urlWithPath, + data: reqBody, + requestId, + }); + + return sharePromise; }); const res = await this.handleNodePromises( @@ -1814,7 +1377,9 @@ export class LitNodeClientNodeJs this.connectedNodes.size // ECDSA requires responses from all nodes, but only shares from minNodeCount. ); return res; - }; + }; // wrapper end + + // ========== Execute with Retry ========== const res = await executeWithRetry< RejectedNodePromises | SuccessNodePromises >( @@ -1826,6 +1391,8 @@ export class LitNodeClientNodeJs }, this.config.retryTolerance ); + + // ========== Handle Response ========== const requestId = res.requestId; // -- case: promises rejected @@ -1835,6 +1402,7 @@ export class LitNodeClientNodeJs // -- case: promises success (TODO: check the keys of "values") const responseData = (res as SuccessNodePromises).values; + logWithRequestId( requestId, 'responseData', @@ -1882,10 +1450,16 @@ export class LitNodeClientNodeJs }; }); - const signatures = this.getSignatures(signedDataList, requestId); + const signatures = getSignatures({ + requestId, + networkPubKeySet: this.networkPubKeySet, + minNodeCount: this.config.minNodeCount, + signedData: signedDataList, + }); + logWithRequestId(requestId, `signature combination`, signatures); - return signatures.signature; // only a single signature is ever present, so we just return it. + return signatures.sig; // only a single signature is ever present, so we just return it. }; /** diff --git a/packages/misc/src/lib/misc.spec.ts b/packages/misc/src/lib/misc.spec.ts index e3ca2c12b7..5f891f5e8b 100644 --- a/packages/misc/src/lib/misc.spec.ts +++ b/packages/misc/src/lib/misc.spec.ts @@ -239,3 +239,251 @@ describe('utils', () => { expect(res.requestId).toBeDefined(); }); }); +describe('find most common tings', () => { + it('should return the most common string in an array', () => { + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 8]; + + const mostOccured = utilsModule.mostCommonString(arr); + + expect(mostOccured).toBe(8); + }); + + it('should return the last element of the array if every element only appears once', () => { + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + + const mostOccured = utilsModule.mostCommonString(arr); + + expect(mostOccured).toBe(0); + }); + + it('should test real world example of responseData', () => { + const responseData = [ + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"A2022A52D6263F5AD61D1A4E29F2C2545FA6E711A30A35BF3456FD5297E4080A"', + shareIndex: 0, + bigR: '"035938946F745C3A6E8B8F0DF7849B0693AAB779695BA770F76906562F37DD005F"', + publicKey: + '"049C6E2DD71F553A29398FA0A93BBCB411EE442D97D253D9E82F41C8601B19BCD71F37F0A2A0A0F501593153C3FD2C9EC3A2BDFA8E43291B7B0E165A3E104BF0B2"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"35790072188D520CDAA61394BB822C4F9D95CC2FC21CBAF54EBB91FA8734F5FE"', + shareIndex: 0, + bigR: '"035938946F745C3A6E8B8F0DF7849B0693AAB779695BA770F76906562F37DD005F"', + publicKey: + '"049C6E2DD71F553A29398FA0A93BBCB411EE442D97D253D9E82F41C8601B19BCD71F37F0A2A0A0F501593153C3FD2C9EC3A2BDFA8E43291B7B0E165A3E104BF0B2"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"A1676E25812D6812BB24469943A15F68FAD4CC679E0376CE1EDD5E0D64236E7A"', + shareIndex: 0, + bigR: '"035938946F745C3A6E8B8F0DF7849B0693AAB779695BA770F76906562F37DD005F"', + publicKey: + '"049C6E2DD71F553A29398FA0A93BBCB411EE442D97D253D9E82F41C8601B19BCD71F37F0A2A0A0F501593153C3FD2C9EC3A2BDFA8E43291B7B0E165A3E104BF0B2"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + { + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"3E8184B2E3DC4725A711D4DBF8D32288A8AC4F31FD04B8ACB302B9BB3D209122"', + shareIndex: 0, + bigR: '"035938946F745C3A6E8B8F0DF7849B0693AAB779695BA770F76906562F37DD005F"', + publicKey: + '"049C6E2DD71F553A29398FA0A93BBCB411EE442D97D253D9E82F41C8601B19BCD71F37F0A2A0A0F501593153C3FD2C9EC3A2BDFA8E43291B7B0E165A3E104BF0B2"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '', + logs: '', + }, + ]; + + const mostCommonResponse = utilsModule.findMostCommonResponse(responseData); + + expect(mostCommonResponse).toEqual({ + success: true, + signedData: { + sig: { + sigType: 'ECDSA_CAIT_SITH', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"3E8184B2E3DC4725A711D4DBF8D32288A8AC4F31FD04B8ACB302B9BB3D209122"', + shareIndex: 0, + bigR: '"035938946F745C3A6E8B8F0DF7849B0693AAB779695BA770F76906562F37DD005F"', + publicKey: + '"049C6E2DD71F553A29398FA0A93BBCB411EE442D97D253D9E82F41C8601B19BCD71F37F0A2A0A0F501593153C3FD2C9EC3A2BDFA8E43291B7B0E165A3E104BF0B2"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: undefined, + logs: undefined, + }); + }); + it('should return the most common response object', () => { + const responses = [ + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }, + ]; + + const expectedResult = { + key1: 'value1', + key2: 'value2', + key3: 'value3', + }; + + const result = utilsModule.findMostCommonResponse(responses); + + expect(result).toEqual(expectedResult); + }); +}); diff --git a/packages/misc/src/lib/misc.ts b/packages/misc/src/lib/misc.ts index 8852753d41..d5099c8dea 100644 --- a/packages/misc/src/lib/misc.ts +++ b/packages/misc/src/lib/misc.ts @@ -67,6 +67,39 @@ export const mostCommonString = (arr: Array): any => { .pop(); }; +export const findMostCommonResponse = (responses: Array): object => { + const result: { [key: string]: any } = {}; + + // Aggregate all values for each key across all responses + const keys = new Set(responses.flatMap(Object.keys)); + + for (const key of keys) { + const values = responses.map( + (response: { [key: string]: any }) => response[key] + ); + + // Filter out undefined values before processing + const filteredValues = values.filter( + (value) => value !== undefined && value !== '' + ); + + if (filteredValues.length === 0) { + result[key] = undefined; // or set a default value if needed + } else if ( + typeof filteredValues[0] === 'object' && + !Array.isArray(filteredValues[0]) + ) { + // Recursive case for objects + result[key] = findMostCommonResponse(filteredValues); + } else { + // Most common element from filtered values + result[key] = mostCommonString(filteredValues); + } + } + + return result; +}; + export const throwError = (e: NodeClientErrorV0 | NodeClientErrorV1): never => { if (isNodeClientErrorV1(e)) { return throwErrorV1(e); @@ -560,40 +593,6 @@ export const is = ( return true; }; -/** - * Convert types before sending to Lit Actions as jsParams, some JS types don't serialize well, so we will convert them before sending to the nodes - * - * @param { object } params.jsParams The jsParams you are sending - * @returns { object } The jsParams object, but with any incompatible types automatically converted - */ -export const convertLitActionsParams = (jsParams: object): object => { - // -- property - const convertedParams: KV = {}; - - // -- execute - for (const [key, value] of Object.entries(jsParams)) { - const _key: string = key; - const _value: any = value; - - // -- get value type - const varType = getVarType(_value); - - // -- case: Unit8Array - if (varType === 'Uint8Array') { - convertedParams[_key] = Array.from(_value); - // -- case: Object, recurse over any objects - } else if (varType === 'Object') { - convertedParams[_key] = convertLitActionsParams(_value); - } - // -- default - else { - convertedParams[_key] = _value; - } - } - - return convertedParams; -}; - export const isNode = () => { var isNode = false; // @ts-ignore diff --git a/packages/pkp-base/src/lib/pkp-base.ts b/packages/pkp-base/src/lib/pkp-base.ts index 7dccf39971..9bcf6ea0e4 100644 --- a/packages/pkp-base/src/lib/pkp-base.ts +++ b/packages/pkp-base/src/lib/pkp-base.ts @@ -10,11 +10,10 @@ import { AuthenticationProps, - ExecuteJsProps, + JsonExecutionSdkParams, PKPBaseProp, AuthSig, PKPBaseDefaultParams, - GetSessionSigsProps, SessionSigs, RPCUrls, AuthMethod, @@ -22,7 +21,6 @@ import { } from '@lit-protocol/types'; import { LitNodeClient } from '@lit-protocol/lit-node-client'; import { publicKeyConvert } from 'secp256k1'; -import { toString as uint8arrayToString } from 'uint8arrays'; import { executeWithRetry, logError } from '@lit-protocol/misc'; /** @@ -49,6 +47,8 @@ const compressPubKey = (pubKey: string): string => { */ export class PKPBase { rpcs?: RPCUrls; + + // @deprecated controllerAuthSig?: AuthSig; controllerAuthMethods?: AuthMethod[]; controllerSessionSigs?: SessionSigs; @@ -282,11 +282,10 @@ export class PKPBase { this.authContext.getSessionSigsProps )) || this.controllerSessionSigs; - const executeJsArgs: ExecuteJsProps = { + const executeJsArgs: JsonExecutionSdkParams = { ...(this.litActionCode && { code: this.litActionCode }), ...(this.litActionIPFS && { ipfsId: this.litActionIPFS }), sessionSigs: controllerSessionSigs, - authSig: this.controllerAuthSig, authMethods: this.authContext?.authMethods, jsParams: { ...{ @@ -367,14 +366,7 @@ export class PKPBase { try { let sig; - if (this.controllerAuthSig) { - sig = await this.litNodeClient.pkpSign({ - toSign: toSign, - pubKey: this.uncompressedPubKey, - authSig: this.controllerAuthSig as AuthSig, - authMethods: [], - }); - } else if (controllerSessionSigs) { + if (controllerSessionSigs) { sig = await this.litNodeClient.pkpSign({ toSign, pubKey: this.uncompressedPubKey, @@ -386,9 +378,14 @@ export class PKPBase { toSign, pubKey: this.uncompressedPubKey, authMethods: this.authContext.authMethods, + sessionSigs: controllerSessionSigs!, }); } + if (!sig) { + throw new Error('No signature returned'); + } + // pad sigs with 0 if length is odd sig.r = sig.r.length % 2 === 0 ? sig.r : '0' + sig.r; sig.s = sig.s.length % 2 === 0 ? sig.s : '0' + sig.s; diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index e8b12e5755..8ebc666c1e 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -3,12 +3,12 @@ import { DecryptResponse, EncryptRequest, EncryptResponse, - ExecuteJsProps, ExecuteJsResponse, FormattedMultipleAccs, GetSignedTokenRequest, HandshakeWithNode, JsonExecutionRequest, + JsonExecutionSdkParams, JsonHandshakeResponse, LitNodeClientConfig, MultipleAccessControlConditions, @@ -41,15 +41,6 @@ export interface ILitNodeClient { // ========== Scoped Class Helpers ========== - /** - * - * (Browser Only) Get the config from browser local storage and override default config - * - * @returns { void } - * - */ - overrideConfigsFromLocalStorage?(): void; - /** * * Set bootstrapUrls to match the network litNetwork unless it's set to custom @@ -59,17 +50,6 @@ export interface ILitNodeClient { */ setCustomBootstrapUrls(): void; - /** - * - * Get the request body of the lit action - * - * @param { ExecuteJsProps } params - * - * @returns { JsonExecutionRequest } - * - */ - getLitActionRequestBody(params: ExecuteJsProps): JsonExecutionRequest; - /** * * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period @@ -155,27 +135,6 @@ export interface ILitNodeClient { _throwNodeError(res: RejectedNodePromises, requestId: string): void; // ========== Shares Resolvers ========== - /** - * - * Get signatures from signed data - * - * @param { Array } signedData - * - * @returns { any } - * - */ - getSignatures(signedData: any[], requestId: string): any; - - /** - * - * Parse the response string to JSON - * - * @param { string } responseString - * - * @returns { any } JSON object - * - */ - parseResponses(responseString: string): any; /** * @@ -199,11 +158,6 @@ export interface ILitNodeClient { * * @returns { Promise } */ - getJsExecutionShares( - url: string, - params: JsonExecutionRequest, - requestId: string - ): Promise; /** * Get Signing Shares for Token containing Access Control Condition @@ -260,7 +214,9 @@ export interface ILitNodeClient { * @returns { ExecuteJsResponse } * */ - executeJs(params: ExecuteJsProps): Promise; + executeJs( + params: JsonExecutionSdkParams + ): Promise; /** * diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 67f1c4da2e..e77658645e 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -214,50 +214,21 @@ export interface ClaimKeyResponse { /** * Struct in rust * ----- - pub struct JsonExecutionRequest { - pub code: Option, - pub ipfs_id: Option, - pub auth_sig: AuthSigItem, - pub js_params: Option, +pub struct JsonExecutionRequest { + pub auth_sig: AuthSigItem, + #[serde(default = "default_epoch")] + pub epoch: u64, + + pub ipfs_id: Option, + pub code: Option, + pub js_params: Option, + pub auth_methods: Option>, } */ -export interface BaseJsonExecutionRequest { - // // the authSig to use to authorize the user with the nodes - // authSig?: AuthSig; - - // An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. - jsParams?: any; - - // JS code to run on the nodes - code?: string; - - // The IPFS ID of some JS code to run on the nodes - ipfsId?: string; - - // // the session signatures to use to authorize the user with the nodes - // sessionSigs?: any; - - // whether to run this on a single node or many - targetNodeRange?: number; - - // auth methods to resolve - authMethods?: AuthMethod[]; -} - -export type JsonExecutionRequest = {} & BaseJsonExecutionRequest; - -export interface JsExecutionRequestBody { - authSig?: AuthSig; - code?: string; - ipfsId?: string; - authMethods?: AuthMethod[]; - jsParams?: any; -} export interface BaseJsonPkpSignRequest { - toSign: ArrayLike; - pubkey: string; // yes, pub"key" is lower case in the node. authMethods?: AuthMethod[]; + toSign: ArrayLike; } /** @@ -267,6 +238,7 @@ export interface BaseJsonPkpSignRequest { export interface JsonPkpSignSdkParams extends BaseJsonPkpSignRequest { pubKey: string; sessionSigs: SessionSigsMap; + authMethods?: AuthMethod[]; } /** @@ -274,6 +246,11 @@ export interface JsonPkpSignSdkParams extends BaseJsonPkpSignRequest { */ export interface JsonPkpSignRequest extends BaseJsonPkpSignRequest { authSig: AuthSig; + + /** + * note that 'key' is in lower case, because this is what the node expects + */ + pubkey: string; } /** @@ -297,7 +274,7 @@ export interface JsonSignSessionKeyRequestV1 { sessionKey: string; authMethods: AuthMethod[]; pkpPublicKey?: string; - authSig?: AuthSig; + // authSig?: AuthSig; siweMessage: string; curveType: 'BLS' | 'ECDSA'; code?: string; @@ -441,10 +418,48 @@ export interface JsonEncryptionRetrieveRequest extends JsonAccsRequest { toDecrypt: string; } -export type ExecuteJsProps = JsonExecutionRequest & { - // A boolean that defines if debug info will be returned or not. - debug?: boolean; -}; +export interface JsonExecutionSdkParamsTargetNode + extends JsonExecutionSdkParams { + targetNodeRange: number; +} + +export interface JsonExecutionSdkParams { + // An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. + jsParams?: any; + + // JS code to run on the nodes + code?: string; + + // The IPFS ID of some JS code to run on the nodes + ipfsId?: string; + + // the session signatures to use to authorize the user with the nodes + sessionSigs?: any; + + // whether to run this on a single node or many + // targetNodeRange?: number; + + // auth methods to resolve + authMethods?: AuthMethod[]; +} + +export interface JsonExecutionRequestTargetNode extends JsonExecutionRequest { + targetNodeRange: number; +} + +export interface JsonExecutionRequest { + authSig: AuthSig; + + /** + * auto-filled before sending each command to the node, but + * in the rust struct, this type is required. + */ + // epoch: number; + ipfsId?: string; + code?: string; + jsParams?: any; + authMethods?: AuthMethod[]; +} export interface EncryptRequestBase extends MultipleAccessControlConditions { // The chain name of the chain that this contract is deployed on. See LIT_CHAINS for currently supported chains. @@ -508,27 +523,34 @@ export interface SignConditionECDSA { exp: number; } +export interface SigResponse { + r: string; + s: string; + recid: number; + signature: string; // 0x... + publicKey: string; // pkp public key + dataSigned: string; +} + +export interface ExecuteJsResponseBase { + signatures: + | { + sig: SigResponse; + } + | any; +} + /** * * An object containing the resulting signatures. Each signature comes with the public key and the data signed. * */ -export interface ExecuteJsResponse { +export interface ExecuteJsResponse extends ExecuteJsResponseBase { success?: boolean; - signatures: - | { - sig: { - r: string; - s: string; - recid: number; - signature: string; // 0x... - publicKey: string; // pkp public key - dataSigned: string; - }; - } - | any; - decryptions: any[]; - response: string; + + // FIXME: Fix if and when we enable decryptions from within a Lit Action. + // decryptions: any[]; + response: string | object; logs: string; claims?: Record; debug?: { @@ -538,6 +560,13 @@ export interface ExecuteJsResponse { }; } +export interface ExecuteJsNoSigningResponse extends ExecuteJsResponseBase { + claims: {}; + decryptions: []; + response: any; + logs: string; +} + export interface LitNodePromise {} export interface SendNodeCommand { @@ -545,16 +574,31 @@ export interface SendNodeCommand { data: any; requestId: string; } - +export interface SigShare { + sigType: + | 'BLS' + | 'K256' + | 'ECDSA_CAIT_SITH' // Legacy alias of K256 + | 'EcdsaCaitSithP256'; + + signatureShare: string; + shareIndex?: number; + bigr?: string; // backward compatibility + bigR?: string; + publicKey: string; + dataSigned?: string; + siweMessage?: string; + sigName?: string; +} export interface NodeShare { claimData: any; shareIndex: any; unsignedJwt: any; - signedData: any; + signedData: SigShare; decryptedData: any; response: any; logs: any; - success?: any; + success?: boolean | ''; } export interface PKPSignShare { @@ -640,18 +684,6 @@ export interface NodeClientErrorV1 { requestId?: string; } -export interface SigShare { - sigType: any; - signatureShare: any; - shareIndex: any; - bigr?: string; - bigR?: string; - publicKey: any; - dataSigned: any; - siweMessage?: string; - sigName?: string; -} - export interface SignedData { signedData: any; } @@ -1663,3 +1695,12 @@ export type SessionKeyCache = { value: SessionKeyPair; timestamp: number; }; + +export interface SignatureData { + signature: string; + derivedKeyId: string; +} + +export type ClaimsList = { + [key: string]: SignatureData; +}[]; From 63e3b54978007ce7504311080e2ee6d617723905 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 26 Apr 2024 23:54:09 +0100 Subject: [PATCH 039/263] fix(tinny): set default MAX_ATTEMPT = 1 --- local-tests/setup/tinny-environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 0bc59fbe51..1e44718275 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -14,7 +14,7 @@ export class TinnyEnvironment { * Environment variables used in the process. */ public processEnvs: ProcessEnvs = { - MAX_ATTEMPTS: parseInt(process.env['MAX_ATTEMPTS']) || 3, + MAX_ATTEMPTS: parseInt(process.env['MAX_ATTEMPTS']) || 1, NETWORK: (process.env['NETWORK'] as LIT_TESTNET) || LIT_TESTNET.LOCALCHAIN, DEBUG: Boolean(process.env['DEBUG']) || false, REQUEST_PER_KILOSECOND: From e4c3e7967aa383ee5f7da9253917926881a08bdb Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 26 Apr 2024 23:54:27 +0100 Subject: [PATCH 040/263] fix(executeJs): jsParam is optional --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 9dee40f4da..794222395d 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1151,7 +1151,7 @@ export class LitNodeClientNodeJs // Format the params const formattedParams: JsonExecutionSdkParams = { ...params, - jsParams: normalizeJsParams(params.jsParams), + ...(params.jsParams && { jsParams: normalizeJsParams(params.jsParams) }), ...(params.code && { code: encodeCode(params.code) }), }; From e01daaa7b9a9c2067211af9ce98480d3c7d18856 Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 27 Apr 2024 01:54:57 +0100 Subject: [PATCH 041/263] fix: node promises. now `pkpSign` & `executeJs` work! --- .../constants/src/lib/constants/endpoints.ts | 8 ++-- .../src/lib/helpers/get-signatures.ts | 2 +- .../src/lib/lit-node-client-nodejs.ts | 46 ++++++++++++------- packages/types/src/lib/interfaces.ts | 2 +- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/packages/constants/src/lib/constants/endpoints.ts b/packages/constants/src/lib/constants/endpoints.ts index 7dd1e36911..2ee56cdf5e 100644 --- a/packages/constants/src/lib/constants/endpoints.ts +++ b/packages/constants/src/lib/constants/endpoints.ts @@ -11,22 +11,22 @@ export const LIT_ENDPOINT = { }, SIGN_SESSION_KEY: { path: '/web/sign_session_key', - // version: LIT_ENDPOINT_VERSION.V1, + version: LIT_ENDPOINT_VERSION.V1, // FIXME: Change this to V1 once the new version is deployed to all public networks - version: LIT_ENDPOINT_VERSION.V0, + // version: LIT_ENDPOINT_VERSION.V0, envName: 'SIGN_SESSION_KEY', }, EXECUTE_JS: { path: '/web/execute', // FIXME: Change this to V1 once the new version is deployed to all public networks - version: LIT_ENDPOINT_VERSION.V0, + version: LIT_ENDPOINT_VERSION.V1, envName: 'EXECUTE_JS', }, PKP_SIGN: { path: '/web/pkp/sign', // version: LIT_ENDPOINT_VERSION.V1, - version: LIT_ENDPOINT_VERSION.V0, + version: LIT_ENDPOINT_VERSION.V1, envName: 'PKP_SIGN', }, PKP_CLAIM: { diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts index 9a5b1e5bd5..2b41980ac3 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts @@ -95,7 +95,7 @@ export const getSignatures = ({ minNodeCount: number; signedData: any[]; requestId: string; -}): { sig: SigResponse } => { +}): { signature: SigResponse } => { const initialKeys = [...new Set(signedData.flatMap((i) => Object.keys(i)))]; // processing signature shares for failed or invalid contents. mutates the signedData object. diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 794222395d..aa386e01c9 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1172,18 +1172,12 @@ export class LitNodeClientNodeJs authSig: sessionSig, }; - const composedUrl = composeLitUrl({ + const urlWithPath = composeLitUrl({ url, endpoint: LIT_ENDPOINT.EXECUTE_JS, }); - const sharePromise = await this.sendCommandToNode({ - url: composedUrl, - data: reqBody, - requestId, - }); - - return sharePromise; + return this.generatePromise(urlWithPath, reqBody, requestId); }); // -- resolve promises @@ -1296,6 +1290,30 @@ export class LitNodeClientNodeJs return returnVal; }; + sharePromise = async (func: any) => { + return await func(); + }; + + /** + * Generates a promise by sending a command to the Lit node + * + * @param url - The URL to send the command to. + * @param params - The parameters to include in the command. + * @param requestId - The ID of the request. + * @returns A promise that resolves with the response from the server. + */ + generatePromise = async ( + url: string, + params: any, + requestId: string + ): Promise => { + return await this.sendCommandToNode({ + url, + data: params, + requestId, + }); + }; + /** * Use PKP to sign * @@ -1336,7 +1354,7 @@ export class LitNodeClientNodeJs const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises(async (url: string) => { + const nodePromises = this.getNodePromises((url: string) => { // -- get the session sig from the url key const sessionSig = this.getSessionSigByUrl({ sessionSigs: params.sessionSigs, @@ -1362,13 +1380,7 @@ export class LitNodeClientNodeJs endpoint: LIT_ENDPOINT.PKP_SIGN, }); - const sharePromise = await this.sendCommandToNode({ - url: urlWithPath, - data: reqBody, - requestId, - }); - - return sharePromise; + return this.generatePromise(urlWithPath, reqBody, id); }); const res = await this.handleNodePromises( @@ -1459,7 +1471,7 @@ export class LitNodeClientNodeJs logWithRequestId(requestId, `signature combination`, signatures); - return signatures.sig; // only a single signature is ever present, so we just return it. + return signatures.signature; // only a single signature is ever present, so we just return it. }; /** diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index e77658645e..fd74318ea3 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -528,7 +528,7 @@ export interface SigResponse { s: string; recid: number; signature: string; // 0x... - publicKey: string; // pkp public key + publicKey: string; // pkp public key (no 0x prefix) dataSigned: string; } From e2adf7da27f49201b994dcd7417142a7cd3a65c2 Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 27 Apr 2024 02:37:08 +0100 Subject: [PATCH 042/263] feat: add pkp sign response parser as its own helper function and unit test --- .../src/lib/helpers/get-signatures.test.ts | 6 +- .../src/lib/helpers/get-signatures.ts | 20 +- .../helpers/parse-pkp-sign-response.test.ts | 230 ++++++++++++++++++ .../lib/helpers/parse-pkp-sign-response.ts | 65 +++++ .../src/lib/lit-node-client-nodejs.ts | 42 +--- packages/types/src/lib/interfaces.ts | 10 + 6 files changed, 324 insertions(+), 49 deletions(-) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.ts diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts index cdd9e82636..9b555d9257 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.test.ts @@ -1,6 +1,7 @@ import { initWasmEcdsaSdk } from '@lit-protocol/ecdsa-sdk'; import { getSignatures } from './get-signatures'; +import { SigResponse } from '@lit-protocol/types'; describe('getSignatures', () => { beforeAll(async () => { @@ -53,14 +54,15 @@ describe('getSignatures', () => { ]; const requestId = ''; - const signatures = getSignatures({ + const signatures = getSignatures<{ sig: SigResponse }>({ networkPubKeySet, minNodeCount, signedData, requestId, }); - expect(signatures.sig).toHaveProperty('dataSigned'); + console.log('signatures:', signatures.sig); + expect(signatures.sig).toHaveProperty('publicKey'); expect(signatures.sig).toHaveProperty('r'); expect(signatures.sig).toHaveProperty('recid'); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts index 2b41980ac3..d549f33a82 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-signatures.ts @@ -77,15 +77,21 @@ export const getFlattenShare = (share: any): SigShare => { }; /** + * Retrieves and combines signature shares from multiple nodes to generate the final signatures. * - * Get signatures from signed data + * @template T - The type of the final signatures. For `executeJs` endpoint, it returns as `signature`, and for `pkpSign` endpoint, it returns as `sig`. + * @param {any} params.networkPubKeySet - The public key set of the network. + * @param {number} params.minNodeCount - The threshold number of nodes + * @param {any[]} params.signedData - The array of signature shares from each node. + * @param {string} [params.requestId=''] - The optional request ID for logging purposes. + * @returns {T | { signature: SigResponse; sig: SigResponse }} - The final signatures or an object containing the final signatures. * - * @param { Array } signedData - * - * @returns { any } + * @example * + * executeJs: getSignatures<{ signature: SigResponse }> + * pkpSign: getSignatures<{ sig: SigResponse }> */ -export const getSignatures = ({ +export const getSignatures = ({ networkPubKeySet, minNodeCount, signedData, @@ -95,7 +101,7 @@ export const getSignatures = ({ minNodeCount: number; signedData: any[]; requestId: string; -}): { signature: SigResponse } => { +}): T | { signature: SigResponse; sig: SigResponse } => { const initialKeys = [...new Set(signedData.flatMap((i) => Object.keys(i)))]; // processing signature shares for failed or invalid contents. mutates the signedData object. @@ -223,8 +229,6 @@ export const getSignatures = ({ const signature = combineEcdsaShares(shares); - console.log('signature:', signature); - if (!signature.r) { throwError({ message: 'siganture could not be combined', diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.test.ts new file mode 100644 index 0000000000..267863e607 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.test.ts @@ -0,0 +1,230 @@ +import { + cleanStringValues, + parsePkpSignResponse, + convertKeysToCamelCase, + snakeToCamel, +} from './parse-pkp-sign-response'; + +describe('parsePkpSignResponse', () => { + it('should parse PKP sign response correctly', () => { + const responseData = [ + { + success: true, + signedData: [ + 125, 135, 197, 234, 117, 247, 55, 139, 183, 1, 228, 4, 197, 6, 57, 22, + 26, 243, 239, 246, 98, 147, 233, 243, 117, 181, 241, 126, 181, 4, 118, + 244, + ], + signatureShare: { + digest: 'fail', + result: 'fail', + share_index: 0, + signature_share: '', + big_r: '', + public_key: '', + sig_type: '', + }, + }, + { + success: true, + signedData: [ + 125, 135, 197, 234, 117, 247, 55, 139, 183, 1, 228, 4, 197, 6, 57, 22, + 26, 243, 239, 246, 98, 147, 233, 243, 117, 181, 241, 126, 181, 4, 118, + 244, + ], + signatureShare: { + digest: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + result: 'success', + share_index: 0, + signature_share: + '"3ED0A844FAE40DF6210A6B2EACB9426E52E8339E243E697E33CF14E0CDE2B827"', + big_r: + '"0332188F0918B7DEBB0CC846B00B0AAD9300308260C2DAD25A85FDECA671C36B1B"', + public_key: + '"04156D7E068BF5ED014057B8B6365BF89053D567D38EC24030C699B94065F2D39B4D45F463464F1A138D7149D1C0EF41ACF9B8826050B9E3DCC847DE2127BDB726"', + sig_type: 'K256', + }, + }, + { + success: true, + signedData: [ + 125, 135, 197, 234, 117, 247, 55, 139, 183, 1, 228, 4, 197, 6, 57, 22, + 26, 243, 239, 246, 98, 147, 233, 243, 117, 181, 241, 126, 181, 4, 118, + 244, + ], + signatureShare: { + digest: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + result: 'success', + share_index: 0, + signature_share: + '"B1AA643E88F8937B71CE2D43DCB73E0180AC96D1E39ECC579F0EC9635F37D4CB"', + big_r: + '"0332188F0918B7DEBB0CC846B00B0AAD9300308260C2DAD25A85FDECA671C36B1B"', + public_key: + '"04156D7E068BF5ED014057B8B6365BF89053D567D38EC24030C699B94065F2D39B4D45F463464F1A138D7149D1C0EF41ACF9B8826050B9E3DCC847DE2127BDB726"', + sig_type: 'K256', + }, + }, + ]; + + const expectedOutput = [ + { + signature: { + digest: 'fail', + shareIndex: 0, + signatureShare: '', + bigR: '', + publicKey: '', + sigType: '', + dataSigned: 'fail', + }, + }, + { + signature: { + digest: + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4', + shareIndex: 0, + signatureShare: + '3ED0A844FAE40DF6210A6B2EACB9426E52E8339E243E697E33CF14E0CDE2B827', + bigR: '0332188F0918B7DEBB0CC846B00B0AAD9300308260C2DAD25A85FDECA671C36B1B', + publicKey: + '04156D7E068BF5ED014057B8B6365BF89053D567D38EC24030C699B94065F2D39B4D45F463464F1A138D7149D1C0EF41ACF9B8826050B9E3DCC847DE2127BDB726', + sigType: 'K256', + dataSigned: + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4', + }, + }, + { + signature: { + digest: + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4', + shareIndex: 0, + signatureShare: + 'B1AA643E88F8937B71CE2D43DCB73E0180AC96D1E39ECC579F0EC9635F37D4CB', + bigR: '0332188F0918B7DEBB0CC846B00B0AAD9300308260C2DAD25A85FDECA671C36B1B', + publicKey: + '04156D7E068BF5ED014057B8B6365BF89053D567D38EC24030C699B94065F2D39B4D45F463464F1A138D7149D1C0EF41ACF9B8826050B9E3DCC847DE2127BDB726', + sigType: 'K256', + dataSigned: + '7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4', + }, + }, + ]; + + const output = parsePkpSignResponse(responseData); + + expect(output).toEqual(expectedOutput); + }); +}); + +describe('cleanStringValues', () => { + it('should remove double quotes from string values in an object', () => { + const input = { + name: '"Josh"', + age: 18, + city: '"New York"', + }; + + const expectedOutput = { + name: 'Josh', + age: 18, + city: 'New York', + }; + + const output = cleanStringValues(input); + + expect(output).toEqual(expectedOutput); + }); + + it('should not modify non-string values in an object', () => { + const input = { + name: 'John', + age: 25, + city: 'New York', + }; + + const expectedOutput = { + name: 'John', + age: 25, + city: 'New York', + }; + + const output = cleanStringValues(input); + + expect(output).toEqual(expectedOutput); + }); +}); + +describe('convertKeysToCamelCase', () => { + it('should convert keys to camel case', () => { + const input = { + first_name: 'John', + last_name: 'Doe', + age: 25, + city_name: 'New York', + }; + + const expectedOutput = { + firstName: 'John', + lastName: 'Doe', + age: 25, + cityName: 'New York', + }; + + const output = convertKeysToCamelCase(input); + + expect(output).toEqual(expectedOutput); + }); + + it('should not modify keys that are already in camel case', () => { + const input = { + firstName: 'John', + lastName: 'Doe', + age: 25, + cityName: 'New York', + }; + + const expectedOutput = { + firstName: 'John', + lastName: 'Doe', + age: 25, + cityName: 'New York', + }; + + const output = convertKeysToCamelCase(input); + + expect(output).toEqual(expectedOutput); + }); +}); + +describe('snakeToCamel', () => { + it('should convert snake case to camel case', () => { + const input = 'hello_world'; + const expectedOutput = 'helloWorld'; + const output = snakeToCamel(input); + expect(output).toEqual(expectedOutput); + }); + + it('should convert multiple snake case words to camel case', () => { + const input = 'hello_world_example'; + const expectedOutput = 'helloWorldExample'; + const output = snakeToCamel(input); + expect(output).toEqual(expectedOutput); + }); + + it('should not modify camel case words', () => { + const input = 'helloWorld'; + const expectedOutput = 'helloWorld'; + const output = snakeToCamel(input); + expect(output).toEqual(expectedOutput); + }); + + it('should not modify words without underscores', () => { + const input = 'hello'; + const expectedOutput = 'hello'; + const output = snakeToCamel(input); + expect(output).toEqual(expectedOutput); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.ts b/packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.ts new file mode 100644 index 0000000000..02619392b9 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/parse-pkp-sign-response.ts @@ -0,0 +1,65 @@ +import { PKPSignShare, PkpSignedData } from '@lit-protocol/types'; + +/** + * Converts a snake_case string to camelCase. + * @param s The snake_case string to convert. + * @returns The camelCase version of the input string. + * + * @example + * snakeToCamel('hello_world') // 'helloWorld' + */ +export const snakeToCamel = (s: string): string => + s.replace(/(_\w)/g, (m) => m[1].toUpperCase()); + +/** + * Converts the keys of an object from snake_case to camelCase. + * + * @param obj - The object whose keys need to be converted. + * @returns The object with keys converted to camelCase. + */ +export const convertKeysToCamelCase = (obj: { [key: string]: any }): any => + Object.keys(obj).reduce( + (acc, key) => ({ + ...acc, + [snakeToCamel(key)]: obj[key], + }), + {} + ); + +/** + * Removes double quotes from string values in an object. + * @param obj - The object to clean string values from. + * @returns A new object with string values cleaned. + */ +export const cleanStringValues = (obj: { [key: string]: any }): any => + Object.keys(obj).reduce( + (acc, key) => ({ + ...acc, + [key]: + typeof obj[key] === 'string' ? obj[key].replace(/"/g, '') : obj[key], + }), + {} + ); + +/** + * Parses the PKP sign response data and transforms it into a standardised format. + * @param responseData - The response data containing PKP sign shares. + * @returns An array of objects with the signature data. + */ +export const parsePkpSignResponse = ( + responseData: PKPSignShare[] +): { signature: PkpSignedData }[] => + responseData.map(({ signatureShare }) => { + // Remove 'result' key if it exists + delete signatureShare.result; + + const camelCaseShare = convertKeysToCamelCase(signatureShare); + const cleanedShare = cleanStringValues(camelCaseShare); + + // Change 'dataSigned' from 'digest' + if (cleanedShare.digest) { + cleanedShare.dataSigned = cleanedShare.digest; + } + + return { signature: cleanedShare }; + }); diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index aa386e01c9..c565749f64 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -127,6 +127,7 @@ import { parseAsJsonOrString } from './helpers/parse-as-json-or-string'; import { getFlattenShare, getSignatures } from './helpers/get-signatures'; import { getClaimsList } from './helpers/get-claims-list'; import { getClaims } from './helpers/get-claims'; +import { parsePkpSignResponse } from './helpers/parse-pkp-sign-response'; const TEMP_CACHE_PERIOD = 30000; // 30 seconds @@ -1423,46 +1424,9 @@ export class LitNodeClientNodeJs // ========== Extract shares from response data ========== // -- 1. combine signed data as a list, and get the signatures from it - const signedDataList = responseData.map((r) => { - // add the signed data to the signature share - delete r.signatureShare.result; - - // nodes do not camel case the response from /web/pkp/sign. - const snakeToCamel = (s: string) => - s.replace(/(_\w)/g, (k) => k[1].toUpperCase()); - //@ts-ignore - const convertShare: any = (share: any) => { - const keys = Object.keys(share); - let convertedShare = {}; - for (const key of keys) { - convertedShare = Object.defineProperty( - convertedShare, - snakeToCamel(key), - Object.getOwnPropertyDescriptor(share, key) as PropertyDecorator - ); - } + const signedDataList = parsePkpSignResponse(responseData); - return convertedShare; - }; - const convertedShare: SigShare = convertShare(r.signatureShare); - const keys = Object.keys(convertedShare); - for (const key of keys) { - //@ts-ignore - if (typeof convertedShare[key] === 'string') { - //@ts-ignore - convertedShare[key] = convertedShare[key] - .replace('"', '') - .replace('"', ''); - } - } - //@ts-ignore - convertedShare.dataSigned = convertedShare.digest; - return { - signature: convertedShare, - }; - }); - - const signatures = getSignatures({ + const signatures = getSignatures<{ signature: SigResponse }>({ requestId, networkPubKeySet: this.networkPubKeySet, minNodeCount: this.config.minNodeCount, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index fd74318ea3..a71fe17d88 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -590,6 +590,16 @@ export interface SigShare { siweMessage?: string; sigName?: string; } + +export interface PkpSignedData { + digest: string; + shareIndex: number; + signatureShare: string; + bigR: string; + publicKey: string; + sigType: string; + dataSigned: string; +} export interface NodeShare { claimData: any; shareIndex: any; From 1b9dd2c4471a139d3e8a040a25f6618c588c6791 Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 27 Apr 2024 02:39:08 +0100 Subject: [PATCH 043/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/444#discussion_r1581347652 --- local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts | 2 +- .../tests/testUseEoaSessionSigsToEncryptDecryptString.ts | 2 +- local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts | 2 +- local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts | 2 +- .../tests/testUsePkpSessionSigsToEncryptDecryptString.ts | 2 +- local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts | 2 +- ...alidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts | 2 +- ...idLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts | 2 +- ...ValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts | 2 +- packages/auth-helpers/src/lib/resources.ts | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts index 57af5ec840..fdb1cf6e04 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts @@ -57,7 +57,7 @@ export const testUseEoaSessionSigsToEncryptDecryptFile = async ( } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts index 840a8e0a9c..12f01ef681 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts @@ -53,7 +53,7 @@ export const testUseEoaSessionSigsToEncryptDecryptString = async ( } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts index de5dff56c7..84fd945da2 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts @@ -55,7 +55,7 @@ export const testUseEoaSessionSigsToEncryptDecryptZip = async ( } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts index 6200661671..c19e856401 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts @@ -58,7 +58,7 @@ export const testUsePkpSessionSigsToEncryptDecryptFile = async ( } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts index daaf80e1d6..0b172e2935 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts @@ -51,7 +51,7 @@ export const testUsePkpSessionSigsToEncryptDecryptString = async ( } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts index 26c7e8afb0..1f2b380a88 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts @@ -56,7 +56,7 @@ export const testUsePkpSessionSigsToEncryptDecryptZip = async ( } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts index 2b3f765f8c..1f101e7d10 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts @@ -60,7 +60,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile = } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts index cf72950d3e..ce4b8cf6a4 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts @@ -55,7 +55,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts index c9a25bddd1..a5ef2bea35 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts @@ -58,7 +58,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip = } const accsResourceString = - await LitAccessControlConditionResource.composeLitActionResourceString( + await LitAccessControlConditionResource.generateLitActionResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/packages/auth-helpers/src/lib/resources.ts b/packages/auth-helpers/src/lib/resources.ts index cda889d7ee..6d2f3aad4d 100644 --- a/packages/auth-helpers/src/lib/resources.ts +++ b/packages/auth-helpers/src/lib/resources.ts @@ -53,7 +53,7 @@ export class LitAccessControlConditionResource * @param {string} dataToEncryptHash - The hash of the data to encrypt. * @returns {Promise} The composed resource string in the format 'hashedAccs/dataToEncryptHash'. */ - public static async composeLitActionResourceString( + public static async generateLitActionResourceString( accs: AccessControlConditions, dataToEncryptHash: string ): Promise { From 500967cc81abed93939b72760e1339ba4aa8a3e3 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 14:46:14 +0100 Subject: [PATCH 044/263] chore: remove unused function --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index c565749f64..37c1433ab5 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1291,10 +1291,6 @@ export class LitNodeClientNodeJs return returnVal; }; - sharePromise = async (func: any) => { - return await func(); - }; - /** * Generates a promise by sending a command to the Lit node * From 993dd5278eeafef6868be6ac71b33d291cb584ab Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 17:52:54 +0100 Subject: [PATCH 045/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581134420 https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581134540 https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581134620 --- packages/auth-helpers/src/lib/siwe/create-siwe-message.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts index 5d3f82d67b..d1e55ff2a4 100644 --- a/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts +++ b/packages/auth-helpers/src/lib/siwe/create-siwe-message.ts @@ -14,7 +14,7 @@ import { /** * Creates a SIWE - * @param params - The parameters for creating the SIWE message. + * @param { BaseSiweMessage } params - The parameters for creating the SIWE message. * @returns A promise that resolves to the created SIWE message as a string. * @throws An error if the walletAddress parameter is missing. */ @@ -80,7 +80,7 @@ export const createSiweMessage = async ( /** * Creates a SIWE message with recaps added to it. * - * @param params - The parameters for creating the SIWE message with recaps. + * @param { WithRecap } params - The parameters for creating the SIWE message with recaps. * @returns A Promise that resolves to a string representing the SIWE message. */ export const createSiweMessageWithRecaps = async ( @@ -93,7 +93,7 @@ export const createSiweMessageWithRecaps = async ( /** * Creates a SIWE message with capacity delegation. - * @param params - The parameters for creating the SIWE message. + * @param { WithCapacityDelegation } params - The parameters for creating the SIWE message. * @returns A Promise that resolves to the created SIWE message. * @throws An error if litNodeClient is not provided. */ From 8a7756888e42fd7eee863b636fd21b85e300347b Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 18:00:56 +0100 Subject: [PATCH 046/263] fix: add a check on the bls handler: https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581153397 --- .../src/lib/helpers/handle-bls-response.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts index f35ff19f50..5801f79fa8 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts @@ -19,6 +19,10 @@ export function handleBlsResponseData( })); log(`[handleBlsResponseData] signatureShares:`, signatureShares); + if (!signatureShares || signatureShares.length <= 0) { + throw new Error('[handleBlsResponseData] No signature shares provided'); + } + const signedDataList = responseData.map((s) => s.dataSigned); log(`[handleBlsResponseData] signedDataList:`, signedDataList); From 82041949d28641654fc6d285b592f76038a52b6f Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 18:10:23 +0100 Subject: [PATCH 047/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1583421309 --- .../src/lib/lit-node-client-nodejs.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index ea1affe089..897bb531a6 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -11,7 +11,7 @@ import { LitResourceAbilityRequest, decode, RecapSessionCapabilityObject, - craftAuthSig, + generateAuthSig, createSiweMessageWithCapacityDelegation, createSiweMessageWithRecaps, createSiweMessage, @@ -219,7 +219,7 @@ export class LitNodeClientNodeJs capacityTokenId: params.capacityTokenId, }); - const authSig = await craftAuthSig({ + const authSig = await generateAuthSig({ signer: params.dAppOwnerWallet, toSign: siweMessage, }); @@ -2685,9 +2685,7 @@ export class LitNodeClientNodeJs ); log(`[signSessionKey] sigType:`, sigType); - const signatureShares = blsSignedData.map((s) => ({ - ProofOfPossession: s.signatureShare.ProofOfPossession, - })); + const signatureShares = handleBlsResponseData(blsSignedData); log(`[signSessionKey] signatureShares:`, signatureShares); From e6c960ae7aed91016b532cd88633f0c6c774afd5 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 18:11:24 +0100 Subject: [PATCH 048/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581235202 --- .../src/lib/lit-node-client-nodejs.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 897bb531a6..e994399e17 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -174,6 +174,11 @@ export class LitNodeClientNodeJs createCapacityDelegationAuthSig = async ( params: CapacityCreditsReq ): Promise => { + // -- validate + if (!params.dAppOwnerWallet) { + throw new Error('dAppOwnerWallet must exist'); + } + // Useful log for debugging if (!params.delegateeAddresses || params.delegateeAddresses.length === 0) { log( @@ -192,11 +197,6 @@ export class LitNodeClientNodeJs await this.connect(); } - // -- validate - if (!params.dAppOwnerWallet) { - throw new Error('dAppOwnerWallet must exist'); - } - const nonce = await this.getLatestBlockhash(); const siweMessage = await createSiweMessageWithCapacityDelegation({ From 198a30ab193e728776f9b3dd22f5f86a4d033bf4 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 18:28:03 +0100 Subject: [PATCH 049/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581237390 --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index e994399e17..9ee51f6f20 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -182,7 +182,7 @@ export class LitNodeClientNodeJs // Useful log for debugging if (!params.delegateeAddresses || params.delegateeAddresses.length === 0) { log( - `[createCapacityDelegationAuthSig] No delegatee addresses provided. It means that the capability will not restrict access based on delegatee list, but it may still enforce other restrictions such as usage limits (uses) and specific NFT IDs (nft_id).` + `[createCapacityDelegationAuthSig] 'delegateeAddresses' is an empty array. It means that no body can use it. However, if the 'delegateeAddresses' field is omitted, It means that the capability will not restrict access based on delegatee list, but it may still enforce other restrictions such as usage limits (uses) and specific NFT IDs (nft_id).` ); } From 6f28d978c818fbf688b5ca53fc896eaeb3748779 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 18:29:19 +0100 Subject: [PATCH 050/263] fix: let `createSiweMessge` do the defaulting https://github.com/LIT-Protocol/js-sdk/pull/436#discussion_r1581246400 --- .../src/lib/lit-node-client-nodejs.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 9ee51f6f20..3931758435 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -204,17 +204,12 @@ export class LitNodeClientNodeJs litNodeClient: this, walletAddress: dAppOwnerWalletAddress, nonce: nonce, - - // -- default configuration for recap object capability - expiration: - params.expiration ?? new Date(Date.now() + 1000 * 60 * 7).toISOString(), - domain: params.domain ?? 'example.com', - statement: - params.statement ?? - 'This is a test statement. You can put anything you want here.', + expiration: params.expiration, + domain: params.domain, + statement: params.statement, // -- capacity delegation specific configuration - uses: params.uses ?? '1', + uses: params.uses, delegateeAddresses: params.delegateeAddresses, capacityTokenId: params.capacityTokenId, }); From e30165e298ff708161ccf343f4a2a357843467ab Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 14:42:07 +0100 Subject: [PATCH 051/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/444#discussion_r1583857180 --- packages/constants/src/lib/constants/endpoints.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/constants/src/lib/constants/endpoints.ts b/packages/constants/src/lib/constants/endpoints.ts index 2ee56cdf5e..fc97194bad 100644 --- a/packages/constants/src/lib/constants/endpoints.ts +++ b/packages/constants/src/lib/constants/endpoints.ts @@ -12,20 +12,15 @@ export const LIT_ENDPOINT = { SIGN_SESSION_KEY: { path: '/web/sign_session_key', version: LIT_ENDPOINT_VERSION.V1, - - // FIXME: Change this to V1 once the new version is deployed to all public networks - // version: LIT_ENDPOINT_VERSION.V0, envName: 'SIGN_SESSION_KEY', }, EXECUTE_JS: { path: '/web/execute', - // FIXME: Change this to V1 once the new version is deployed to all public networks version: LIT_ENDPOINT_VERSION.V1, envName: 'EXECUTE_JS', }, PKP_SIGN: { path: '/web/pkp/sign', - // version: LIT_ENDPOINT_VERSION.V1, version: LIT_ENDPOINT_VERSION.V1, envName: 'PKP_SIGN', }, From 3b661139cc07d44fe2484914adb5fcbbe83f8316 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 14:45:13 +0100 Subject: [PATCH 052/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/444#discussion_r1583859603 --- .../encryption/src/lib/params-validators.ts | 2 +- packages/types/src/lib/interfaces.ts | 24 +++++-------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/packages/encryption/src/lib/params-validators.ts b/packages/encryption/src/lib/params-validators.ts index b221a0f685..aae0f8d82e 100644 --- a/packages/encryption/src/lib/params-validators.ts +++ b/packages/encryption/src/lib/params-validators.ts @@ -380,7 +380,7 @@ class FileValidator implements ParamsValidator { } export interface AuthMaterialValidatorProps { - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; chain?: string; } diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index a71fe17d88..0904310625 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -364,7 +364,7 @@ export interface JsonSigningRetrieveRequest extends JsonAccsRequest { export interface GetSignedTokenRequest extends SigningAccessControlConditionRequest { - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; } export interface SigningAccessControlConditionRequest @@ -434,7 +434,7 @@ export interface JsonExecutionSdkParams { ipfsId?: string; // the session signatures to use to authorize the user with the nodes - sessionSigs?: any; + sessionSigs: any; // whether to run this on a single node or many // targetNodeRange?: number; @@ -465,11 +465,8 @@ export interface EncryptRequestBase extends MultipleAccessControlConditions { // The chain name of the chain that this contract is deployed on. See LIT_CHAINS for currently supported chains. chain: Chain; - // The authSig of the user. Returned via the checkAndSignAuthMessage function - authSig?: AuthSig; - // the session signatures to use to authorize the user with the nodes - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; } export interface EncryptRequest extends EncryptRequestBase { @@ -820,11 +817,8 @@ export interface EncryptToJsonPayload extends EncryptRequestBase { } export interface DecryptFromJsonProps { - // The authSig of the user. Returned via the checkAndSignAuthMessage function - authSig?: AuthSig; - // the session signatures to use to authorize the user with the nodes - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; // An instance of LitNodeClient that is already connected litNodeClient: ILitNodeClient; @@ -834,11 +828,8 @@ export interface DecryptFromJsonProps { export interface EncryptFileAndZipWithMetadataProps extends MultipleAccessControlConditions { - // The authSig of the user. Returned via the checkAndSignAuthMessage function - authSig?: AuthSig; - // the session signatures to use to authorize the user with the nodes - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; // The chain name of the chain that this contract is deployed on. See LIT_CHAINS for currently supported chains. chain: string; @@ -854,11 +845,8 @@ export interface EncryptFileAndZipWithMetadataProps } export interface DecryptZipFileWithMetadataProps { - // The authSig of the user. Returned via the checkAndSignAuthMessage function - authSig?: AuthSig; - // the session signatures to use to authorize the user with the nodes - sessionSigs?: SessionSigsMap; + sessionSigs: SessionSigsMap; // The zip file blob with metadata inside it and the encrypted asset file: File | Blob; From 65e5f21defe6bfaecf25fddc7f7aa1aff1812144 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 14:55:31 +0100 Subject: [PATCH 053/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/444#discussion_r1583884147 --- .../src/lib/lit-node-client-nodejs.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 37c1433ab5..76cbd0ca2c 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1224,18 +1224,17 @@ export class LitNodeClientNodeJs responseData ) as NodeShare; - const IS_SUCCESS = mostCommonResponse.success; - const HAS_SIGNED_DATA = - Object.keys(mostCommonResponse.signedData).length > 0; - const HAS_CLAIM_DATA = Object.keys(mostCommonResponse.claimData).length > 0; + const isSuccess = mostCommonResponse.success; + const hasSignedData = Object.keys(mostCommonResponse.signedData).length > 0; + const hasClaimData = Object.keys(mostCommonResponse.claimData).length > 0; // -- we must also check for claim responses as a user may have submitted for a claim and signatures must be aggregated before returning - if (IS_SUCCESS && !HAS_SIGNED_DATA && !HAS_CLAIM_DATA) { + if (isSuccess && !hasSignedData && !hasClaimData) { return mostCommonResponse as unknown as ExecuteJsResponse; } // -- in the case where we are not signing anything on Lit action and using it as purely serverless function - if (!HAS_SIGNED_DATA && !HAS_CLAIM_DATA) { + if (!hasSignedData && !hasClaimData) { return { claims: {}, signatures: null, @@ -1666,8 +1665,7 @@ export class LitNodeClientNodeJs * */ decrypt = async (params: DecryptRequest): Promise => { - const { authSig, sessionSigs, chain, ciphertext, dataToEncryptHash } = - params; + const { sessionSigs, chain, ciphertext, dataToEncryptHash } = params; // ========== Validate Params ========== // -- validate if it's ready @@ -1753,7 +1751,7 @@ export class LitNodeClientNodeJs ): Promise | RejectedNodePromises> => { const nodePromises = this.getNodePromises((url: string) => { // -- if session key is available, use it - const authSigToSend = sessionSigs ? sessionSigs[url] : authSig; + const authSigToSend = sessionSigs[url]; return this.getSigningShareForDecryption( url, From ffa6555849e42d84ef8269f7789fb93993d14763 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 15:07:51 +0100 Subject: [PATCH 054/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/444#discussion_r1584821049 --- .../src/lib/helpers/normalize-array.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts index 2da12ecbe7..ba07bbd725 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/normalize-array.ts @@ -8,8 +8,10 @@ */ export const normalizeArray = (toSign: ArrayLike) => { const arr = []; - for (let i = 0; i < toSign.length; i++) { - arr.push((toSign as Buffer)[i]); + // Casting ArrayLike to Uint8Array for better compatibility and avoiding Node-specific types + const uint8Array = new Uint8Array(toSign); + for (let i = 0; i < uint8Array.length; i++) { + arr.push(uint8Array[i]); } return arr; }; From 9c4077b6facd91ebb78f2cec3a8a58ec84e44dc8 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 15:48:40 +0100 Subject: [PATCH 055/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583772635 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit decriptedFile: Uint8Array(11) [ 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100 ] ✔ 1. testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile - Passed (5459.23 ms) --- ...dLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts index 2b3f765f8c..1ab330cabf 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts @@ -6,6 +6,7 @@ import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; import { log } from '@lit-protocol/misc'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; /** * Test Commands: @@ -28,13 +29,13 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile = userAddress: alice.authMethodOwnedPkp.ethAddress, }); - const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); const encryptRes = await LitJsSdk.encryptString( { accessControlConditions: accs, chain: 'ethereum', - sessionSigs: pkpSessionSigs, + sessionSigs: litActionSessionSigs, dataToEncrypt: 'Hello world', }, devEnv.litNodeClient as unknown as ILitNodeClient From dce95813ca76748925e79a9f52e45853b97e89f4 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 15:52:11 +0100 Subject: [PATCH 056/263] fix: misleading function name --- local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts | 2 +- .../tests/testUseEoaSessionSigsToEncryptDecryptString.ts | 2 +- local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts | 2 +- local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts | 2 +- .../tests/testUsePkpSessionSigsToEncryptDecryptString.ts | 2 +- local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts | 2 +- ...alidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts | 2 +- ...idLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts | 2 +- ...ValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts | 2 +- packages/auth-helpers/src/lib/resources.ts | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts index fdb1cf6e04..3f2ebfe90c 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts @@ -57,7 +57,7 @@ export const testUseEoaSessionSigsToEncryptDecryptFile = async ( } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts index 12f01ef681..5b63ca962c 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts @@ -53,7 +53,7 @@ export const testUseEoaSessionSigsToEncryptDecryptString = async ( } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts index 84fd945da2..2e3fa881b8 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts @@ -55,7 +55,7 @@ export const testUseEoaSessionSigsToEncryptDecryptZip = async ( } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts index c19e856401..fbe9af30ef 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts @@ -58,7 +58,7 @@ export const testUsePkpSessionSigsToEncryptDecryptFile = async ( } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts index 0b172e2935..a04c8a682c 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts @@ -51,7 +51,7 @@ export const testUsePkpSessionSigsToEncryptDecryptString = async ( } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts index 1f2b380a88..4554d54ef2 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts @@ -56,7 +56,7 @@ export const testUsePkpSessionSigsToEncryptDecryptZip = async ( } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts index 1f101e7d10..3fc8c35ac3 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts @@ -60,7 +60,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile = } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts index ce4b8cf6a4..fde1ce5e39 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts @@ -55,7 +55,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts index a5ef2bea35..1e2576865d 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts @@ -58,7 +58,7 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip = } const accsResourceString = - await LitAccessControlConditionResource.generateLitActionResourceString( + await LitAccessControlConditionResource.generateResourceString( accs, encryptRes.dataToEncryptHash ); diff --git a/packages/auth-helpers/src/lib/resources.ts b/packages/auth-helpers/src/lib/resources.ts index 6d2f3aad4d..11d82184fa 100644 --- a/packages/auth-helpers/src/lib/resources.ts +++ b/packages/auth-helpers/src/lib/resources.ts @@ -53,7 +53,7 @@ export class LitAccessControlConditionResource * @param {string} dataToEncryptHash - The hash of the data to encrypt. * @returns {Promise} The composed resource string in the format 'hashedAccs/dataToEncryptHash'. */ - public static async generateLitActionResourceString( + public static async generateResourceString( accs: AccessControlConditions, dataToEncryptHash: string ): Promise { From e01e07628aa5fc778fa6926d87431831688ec8fd Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 15:55:39 +0100 Subject: [PATCH 057/263] fix: only BLS https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583793731 --- packages/types/src/lib/interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 8ffafc8abd..8c98f5d542 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -315,7 +315,7 @@ export interface JsonSignSessionKeyRequestV1 { pkpPublicKey?: string; authSig?: AuthSig; siweMessage: string; - curveType: 'BLS' | 'ECDSA'; + curveType: 'BLS'; code?: string; litActionIpfsId?: string; jsParams?: any; From bcad173c3abf5a61e16517456a55c6995fd8363a Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:21:53 +0100 Subject: [PATCH 058/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583794540 --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 54f77b9d0e..cb38ec80f5 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2520,7 +2520,6 @@ export class LitNodeClientNodeJs sessionKey: sessionKeyUri, authMethods: params.authMethods, ...(params?.pkpPublicKey && { pkpPublicKey: params.pkpPublicKey }), - ...(params?.authSig && { authSig: params.authSig }), siweMessage: siweMessage, curveType: LIT_CURVE.BLS, From 451e0e77fcd23e96879b83cf5b55b773d20cb79e Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:22:57 +0100 Subject: [PATCH 059/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583794866 --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index cb38ec80f5..611750b753 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -702,7 +702,7 @@ export class LitNodeClientNodeJs throw new Error('authSig or sessionSig is required'); } const data: JsExecutionRequestBody = { - ...(authSig ? { authSig } : {}), + authSig, ...(code ? { code } : {}), ...(ipfsId ? { ipfsId } : {}), ...(authMethods ? { authMethods } : {}), From d428bad579f01511a106851bda5b6eb6f1dea589 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:25:41 +0100 Subject: [PATCH 060/263] chore: added note https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583795896 --- packages/types/src/lib/interfaces.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 8c98f5d542..46f1d72cec 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -244,6 +244,11 @@ export interface BaseJsonExecutionRequest { authMethods?: AuthMethod[]; } +/** + * FIXME: We should create a separate interface for JsExecutionRequestBody + * a body that the SDK accepts, and another one the node actually accepts. + * + */ export interface WithAuthSig extends BaseJsonExecutionRequest { authSig: AuthSig; sessionSigs?: any; @@ -257,7 +262,7 @@ export interface WithSessionSigs extends BaseJsonExecutionRequest { export type JsonExecutionRequest = WithAuthSig | WithSessionSigs; export interface JsExecutionRequestBody { - authSig?: AuthSig; + authSig: AuthSig; code?: string; ipfsId?: string; authMethods?: AuthMethod[]; @@ -313,7 +318,6 @@ export interface JsonSignSessionKeyRequestV1 { sessionKey: string; authMethods: AuthMethod[]; pkpPublicKey?: string; - authSig?: AuthSig; siweMessage: string; curveType: 'BLS'; code?: string; From eaf014b147458c8368ae6d1dcdefbee209fbda8b Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 15:20:01 +0100 Subject: [PATCH 061/263] fix: improve readability --- .../src/lib/providers/BaseProvider.ts | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts index f4f2b84eef..d898c3d3b5 100644 --- a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts +++ b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts @@ -161,40 +161,43 @@ export abstract class BaseProvider { let response: SignSessionKeyResponse; + // common data for the signSessionKey function call + const commonData = { + sessionKey: params.sessionSigsParams.sessionKey, + statement: authCallbackParams.statement, + pkpPublicKey: params.pkpPublicKey, + expiration: authCallbackParams.expiration, + resources: authCallbackParams.resources, + chainId: chainId, + ...(params.resourceAbilityRequests && { + resourceAbilityRequests: params.resourceAbilityRequests, + }), + }; + + // prepare auth-specific data based on the authentication method + let authSpecificData = {}; + if (params.authMethod.authMethodType === AuthMethodType.EthWallet) { - const authSig = JSON.parse(params.authMethod.accessToken); - response = await nodeClient.signSessionKey({ - statement: authCallbackParams.statement, - sessionKey: params.sessionSigsParams.sessionKey, + authSpecificData = { + authSig: JSON.parse(params.authMethod.accessToken), authMethods: [], - authSig: authSig, - pkpPublicKey: params.pkpPublicKey, - expiration: authCallbackParams.expiration, - resources: authCallbackParams.resources, - chainId, - - // optional - ...(params.resourceAbilityRequests && { - resourceAbilityRequests: params.resourceAbilityRequests, - }), - }); + }; } else { - response = await nodeClient.signSessionKey({ - sessionKey: params.sessionSigsParams.sessionKey, - statement: authCallbackParams.statement, + authSpecificData = { authMethods: [params.authMethod], - pkpPublicKey: params.pkpPublicKey, - expiration: authCallbackParams.expiration, - resources: authCallbackParams.resources, - chainId, - - // optional - ...(params.resourceAbilityRequests && { - resourceAbilityRequests: params.resourceAbilityRequests, - }), - }); + }; } + // Merge the common and auth-specific data + response = await nodeClient.signSessionKey({ + // default + authMethods: [], + + // override + ...commonData, + ...authSpecificData, + }); + return response.authSig; }; } From 660759f5f001bc25767c9679d76df83d223ba707 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 15:49:30 +0100 Subject: [PATCH 062/263] fix: pass-in session key in base provider --- packages/lit-auth-client/src/lib/providers/BaseProvider.ts | 6 +++++- packages/types/src/lib/interfaces.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts index d898c3d3b5..dc0e6a3a69 100644 --- a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts +++ b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts @@ -142,6 +142,10 @@ export abstract class BaseProvider { let authNeededCallback = params.sessionSigsParams.authNeededCallback; + // If no session key is provided, generate a new session key from the LitNodeClient + const sessionKey = + params.sessionSigsParams.sessionKey || this.litNodeClient.getSessionKey(); + // If no authNeededCallback is provided, create one that uses the provided PKP and auth method // to sign a session key and return an auth sig if (!authNeededCallback) { @@ -163,7 +167,7 @@ export abstract class BaseProvider { // common data for the signSessionKey function call const commonData = { - sessionKey: params.sessionSigsParams.sessionKey, + sessionKey: sessionKey, statement: authCallbackParams.statement, pkpPublicKey: params.pkpPublicKey, expiration: authCallbackParams.expiration, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 46f1d72cec..6592c62cd6 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1471,7 +1471,7 @@ export interface BaseProviderSessionSigsParams { /** * Lit Node Client to use. If not provided, will use an existing Lit Node Client or create a new one */ - litNodeClient?: any; + litNodeClient?: ILitNodeClient; resourceAbilityRequests?: LitResourceAbilityRequest[]; } From f30a10a6a8ca12ac307052005d40a8e3ee0218eb Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 15:20:01 +0100 Subject: [PATCH 063/263] feat: cherry-pick ee7011a --- packages/lit-auth-client/src/lib/providers/BaseProvider.ts | 2 +- packages/types/src/lib/interfaces.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts index dc0e6a3a69..2e471462ad 100644 --- a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts +++ b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts @@ -167,7 +167,7 @@ export abstract class BaseProvider { // common data for the signSessionKey function call const commonData = { - sessionKey: sessionKey, + sessionKey: params.sessionSigsParams.sessionKey, statement: authCallbackParams.statement, pkpPublicKey: params.pkpPublicKey, expiration: authCallbackParams.expiration, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 6592c62cd6..7fa4a13cfa 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -247,7 +247,7 @@ export interface BaseJsonExecutionRequest { /** * FIXME: We should create a separate interface for JsExecutionRequestBody * a body that the SDK accepts, and another one the node actually accepts. - * + * */ export interface WithAuthSig extends BaseJsonExecutionRequest { authSig: AuthSig; From 8b92666a0a750f9e0959c030f22dcb7ffe66bafd Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 15:49:30 +0100 Subject: [PATCH 064/263] fix: pass-in session key in base provider --- packages/lit-auth-client/src/lib/providers/BaseProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts index 2e471462ad..dc0e6a3a69 100644 --- a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts +++ b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts @@ -167,7 +167,7 @@ export abstract class BaseProvider { // common data for the signSessionKey function call const commonData = { - sessionKey: params.sessionSigsParams.sessionKey, + sessionKey: sessionKey, statement: authCallbackParams.statement, pkpPublicKey: params.pkpPublicKey, expiration: authCallbackParams.expiration, From b4a53dbb9d9bc0006701122249146dfd8c220ea5 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 17:34:44 +0100 Subject: [PATCH 065/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/446#discussion_r1583307218 --- .../src/lib/providers/BaseProvider.ts | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts index dc0e6a3a69..43e2eaed0d 100644 --- a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts +++ b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts @@ -178,30 +178,21 @@ export abstract class BaseProvider { }), }; - // prepare auth-specific data based on the authentication method - let authSpecificData = {}; - if (params.authMethod.authMethodType === AuthMethodType.EthWallet) { - authSpecificData = { - authSig: JSON.parse(params.authMethod.accessToken), + const authSig = JSON.parse(params.authMethod.accessToken); + + response = await nodeClient.signSessionKey({ + ...commonData, + authSig: authSig, authMethods: [], - }; + }); } else { - authSpecificData = { + response = await nodeClient.signSessionKey({ + ...commonData, authMethods: [params.authMethod], - }; + }); } - // Merge the common and auth-specific data - response = await nodeClient.signSessionKey({ - // default - authMethods: [], - - // override - ...commonData, - ...authSpecificData, - }); - return response.authSig; }; } From 1c1727549c1ba2ff4cd23b6ada66b3f7731b3c0c Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 29 Apr 2024 19:06:43 +0100 Subject: [PATCH 066/263] feat: merge https://github.com/LIT-Protocol/js-sdk/pull/446 --- packages/lit-auth-client/src/lib/providers/BaseProvider.ts | 1 + packages/types/src/lib/interfaces.ts | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts index 43e2eaed0d..62effb7c5a 100644 --- a/packages/lit-auth-client/src/lib/providers/BaseProvider.ts +++ b/packages/lit-auth-client/src/lib/providers/BaseProvider.ts @@ -200,6 +200,7 @@ export abstract class BaseProvider { // Generate session sigs with the given session params const sessionSigs = await this.litNodeClient.getSessionSigs({ ...params.sessionSigsParams, + sessionKey, authNeededCallback, }); diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 7fa4a13cfa..183a59936a 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -987,8 +987,11 @@ export interface GetSessionSigsProps extends LitCustomAuth { */ authNeededCallback?: AuthCallback; - // The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. - sessionKey?: any; + /** + * The serialized session key pair to sign. + * If not provided, a session key pair will be fetched from localStorge or generated. + */ + sessionKey?: SessionKeyPair; /** * @deprecated - use capabilityAuthSigs instead From 8a8694a166be4a86beb8bad3ee3aee83253301c9 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:32:02 +0100 Subject: [PATCH 067/263] fix: remove TEMP_CACHE --- .../src/lib/lit-node-client-nodejs.ts | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 611750b753..d0ec39193b 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -117,15 +117,9 @@ import type { JsExecutionRequestBody, JsonSignSessionKeyRequestV1, BlsResponseData, - SessionKeyCache, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; -const TEMP_CACHE_PERIOD = 30000; // 30 seconds - -// Global cache variable -let sessionKeyCache: SessionKeyCache | null = null; - export class LitNodeClientNodeJs extends LitCore implements LitClientSessionManager, ILitNodeClient @@ -327,15 +321,6 @@ export class LitNodeClientNodeJs `Storage key "${storageKey}" is missing. Not a problem. Contiune...` ); - // Check if a valid session key exists in cache - if ( - sessionKeyCache && - Date.now() - sessionKeyCache.timestamp < TEMP_CACHE_PERIOD - ) { - log(`[getSessionKey] Returning session key from cache.`); - return sessionKeyCache.value; - } - // Generate new one const newSessionKey = generateSessionKeyPair(); @@ -346,14 +331,6 @@ export class LitNodeClientNodeJs log( `[getSessionKey] Localstorage not available.Not a problem.Contiune...` ); - - // Store in cache - sessionKeyCache = { - value: newSessionKey, - timestamp: Date.now(), - }; - - log(`[getSessionKey] newSessionKey set to cache: `, sessionKeyCache); } return newSessionKey; From 3b7de4561cf00f2ec009ad49232a571b992a3d75 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:33:35 +0100 Subject: [PATCH 068/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583803745 --- .../src/lib/lit-node-client-nodejs.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d0ec39193b..1b46b6beb8 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -173,6 +173,11 @@ export class LitNodeClientNodeJs createCapacityDelegationAuthSig = async ( params: CapacityCreditsReq ): Promise => { + // -- validate + if (!params.dAppOwnerWallet) { + throw new Error('dAppOwnerWallet must exist'); + } + // Useful log for debugging if (!params.delegateeAddresses || params.delegateeAddresses.length === 0) { log( @@ -191,11 +196,6 @@ export class LitNodeClientNodeJs await this.connect(); } - // -- validate - if (!params.dAppOwnerWallet) { - throw new Error('dAppOwnerWallet must exist'); - } - const nonce = await this.getLatestBlockhash(); const siweMessage = await createSiweMessageWithCapacityDelegation({ From e424dafc8e174f4c7edee963e68a9393476fab21 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:38:09 +0100 Subject: [PATCH 069/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583813538 --- .../src/lib/lit-node-client-nodejs.ts | 105 +++++++----------- 1 file changed, 39 insertions(+), 66 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 1b46b6beb8..e5cb4c89f4 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2622,26 +2622,15 @@ export class LitNodeClientNodeJs } // each of this field cannot be empty - let requiredFields = - curveType === LIT_CURVE.BLS - ? [ - 'signatureShare', - 'curveType', - 'shareIndex', - 'siweMessage', - 'dataSigned', - 'blsRootPubkey', - 'result', - ] - : [ - 'sigType', - 'dataSigned', - 'signatureShare', - 'bigr', - 'publicKey', - 'sigName', - 'siweMessage', - ]; + let requiredFields = [ + 'signatureShare', + 'curveType', + 'shareIndex', + 'siweMessage', + 'dataSigned', + 'blsRootPubkey', + 'result', + ]; // check if all required fields are present for (const field of requiredFields) { @@ -2688,59 +2677,43 @@ export class LitNodeClientNodeJs let signatures: any; - if (curveType === LIT_CURVE.BLS) { - const blsSignedData: BlsResponseData[] = - validatedSignedDataList as BlsResponseData[]; + const blsSignedData: BlsResponseData[] = + validatedSignedDataList as BlsResponseData[]; - const sigType = mostCommonString( - blsSignedData.map((s: any) => s.sigType) - ); - log(`[signSessionKey] sigType:`, sigType); + const sigType = mostCommonString(blsSignedData.map((s: any) => s.sigType)); + log(`[signSessionKey] sigType:`, sigType); - const signatureShares = blsSignedData.map((s) => ({ - ProofOfPossession: s.signatureShare.ProofOfPossession, - })); + const signatureShares = blsSignedData.map((s) => ({ + ProofOfPossession: s.signatureShare.ProofOfPossession, + })); - log(`[signSessionKey] signatureShares:`, signatureShares); + log(`[signSessionKey] signatureShares:`, signatureShares); - const blsCombinedSignature = blsSdk.combine_signature_shares( - signatureShares.map((s) => JSON.stringify(s)) - ); + const blsCombinedSignature = blsSdk.combine_signature_shares( + signatureShares.map((s) => JSON.stringify(s)) + ); - log(`[signSessionKey] blsCombinedSignature:`, blsCombinedSignature); + log(`[signSessionKey] blsCombinedSignature:`, blsCombinedSignature); - const publicKey = params.pkpPublicKey.startsWith('0x') - ? params.pkpPublicKey.slice(2) - : params.pkpPublicKey; + const publicKey = params.pkpPublicKey.startsWith('0x') + ? params.pkpPublicKey.slice(2) + : params.pkpPublicKey; - const dataSigned = mostCommonString( - blsSignedData.map((s: any) => s.dataSigned) - ); - const siweMessage = mostCommonString( - blsSignedData.map((s: any) => s.siweMessage) - ); - signatures = { - sessionSig: { - signature: blsCombinedSignature, - publicKey, - dataSigned, - siweMessage, - }, - }; - } else { - // Shape: [signSessionKey] signatures: { - // sessionSig: { - // r: "xx", - // s: "yy", - // recid: 1, - // signature: "0x...", - // publicKey: "04e...", - // dataSigned: "7c1...", - // siweMessage: "litprotocol.com wants you to sign in with your Ethereum account:\n0xd69969c6a2E56C928d63F12325fe1d9D47115C91\n\nLit Protocol PKP session signature Some custom statement. I further authorize the stated URI to perform the following actions on my behalf: (1) 'Threshold': 'Signing' for 'lit-pkp://*'.\n\nURI: lit:session:95ff87b5d2210c382ccfcba6bdb16ceb217da9726c91d0fdda5eb888f087488f\nVersion: 1\nChain ID: 1\nNonce: 0x337906a8c2a6da52d438495fc1b0145ed5632ec32ffa1dda1064f43775b3a802\nIssued At: 2024-04-09T17:58:47Z\nExpiration Time: 2024-04-10T17:59:13.420Z\nResources:\n- urn:recap:eyJhdHQiOnt9LCJwcmYiOltdfQ\n- urn:recap:eyJhdHQiOnsibGl0LXBrcDovLyoiOnsiVGhyZXNob2xkL1NpZ25pbmciOlt7fV19fSwicHJmIjpbXX0", - // }, - // } - signatures = this.getSessionSignatures(validatedSignedDataList); - } + const dataSigned = mostCommonString( + blsSignedData.map((s: any) => s.dataSigned) + ); + const mostCommonSiweMessage = mostCommonString( + blsSignedData.map((s: any) => s.siweMessage) + ); + + signatures = { + sessionSig: { + signature: blsCombinedSignature, + publicKey, + dataSigned, + siweMessage: mostCommonSiweMessage, + }, + }; log('[signSessionKey] signatures:', signatures); From 6e0e4ef5cb798930acffa7d1ebcc69d3aca65135 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 30 Apr 2024 16:43:20 +0100 Subject: [PATCH 070/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/440#discussion_r1583811484 --- .../src/lib/lit-node-client-nodejs.ts | 24 +++++++------------ packages/types/src/lib/interfaces.ts | 3 --- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index e5cb4c89f4..a16009a720 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2427,23 +2427,15 @@ export class LitNodeClientNodeJs params.expiration || new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(); - let sessionKeyUri: string; - - // This allow the user to provide a sessionKeyUri directly without using the session key pair - if (params?.sessionKeyUri) { - sessionKeyUri = params.sessionKeyUri; - log(`[signSessionKey] sessionKeyUri found in params:`, sessionKeyUri); - } else { - // Try to get it from local storage, if not generates one~ - let sessionKey: SessionKeyPair = - params.sessionKey ?? this.getSessionKey(); - sessionKeyUri = LIT_SESSION_KEY_URI + sessionKey.publicKey; + // Try to get it from local storage, if not generates one~ + const sessionKey: SessionKeyPair = + params.sessionKey ?? this.getSessionKey(); + const sessionKeyUri = LIT_SESSION_KEY_URI + sessionKey.publicKey; - log( - `[signSessionKey] sessionKeyUri is not found in params, generating a new one`, - sessionKeyUri - ); - } + log( + `[signSessionKey] sessionKeyUri is not found in params, generating a new one`, + sessionKeyUri + ); if (!sessionKeyUri) { throw new Error( diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 183a59936a..af995db29c 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -929,9 +929,6 @@ export interface SignSessionKeyProp { resourceAbilityRequests?: LitResourceAbilityRequest[]; - // -- as part of auth unification - sessionKeyUri?: string; - litActionCode?: string; jsParams?: { From 7bc363dd3fb4aa76650cbe9a89fd5aa2a30552fb Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 1 May 2024 16:48:51 +0100 Subject: [PATCH 071/263] fix: remove authSig (need to fix `decryptToString` and `decryptToFile` return types --- packages/encryption/src/lib/encryption.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/encryption/src/lib/encryption.ts b/packages/encryption/src/lib/encryption.ts index 3e7e29bcd2..2fa80a33af 100644 --- a/packages/encryption/src/lib/encryption.ts +++ b/packages/encryption/src/lib/encryption.ts @@ -126,7 +126,7 @@ export async function decryptFromJson( ? ReturnType : never > { - const { authSig, sessionSigs, parsedJsonData, litNodeClient } = params; + const { sessionSigs, parsedJsonData, litNodeClient } = params; // -- validate const paramsIsSafe = safeParams({ @@ -153,7 +153,6 @@ export async function decryptFromJson( ciphertext: parsedJsonData.ciphertext, dataToEncryptHash: parsedJsonData.dataToEncryptHash, chain: parsedJsonData.chain, - authSig, sessionSigs, }, litNodeClient @@ -169,7 +168,6 @@ export async function decryptFromJson( ciphertext: parsedJsonData.ciphertext, dataToEncryptHash: parsedJsonData.dataToEncryptHash, chain: parsedJsonData.chain, - authSig, sessionSigs, }, litNodeClient @@ -444,7 +442,6 @@ export const encryptFileAndZipWithMetadata = async ( params: EncryptFileAndZipWithMetadataProps ): Promise => { const { - authSig, sessionSigs, accessControlConditions, evmContractConditions, @@ -460,7 +457,6 @@ export const encryptFileAndZipWithMetadata = async ( const paramsIsSafe = safeParams({ functionName: 'encryptFileAndZipWithMetadata', params: { - authSig, sessionSigs, accessControlConditions, evmContractConditions, @@ -545,13 +541,12 @@ export const encryptFileAndZipWithMetadata = async ( export const decryptZipFileWithMetadata = async ( params: DecryptZipFileWithMetadataProps ): Promise => { - const { authSig, sessionSigs, file, litNodeClient } = params; + const { sessionSigs, file, litNodeClient } = params; // -- validate const paramsIsSafe = safeParams({ functionName: 'decryptZipFileWithMetadata', params: { - authSig, sessionSigs, file, litNodeClient, From 917625feb19b2c2c95444689ccd6db020f5453c1 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 1 May 2024 23:04:12 +0100 Subject: [PATCH 072/263] fix(cc-siwe): 'uses' should be optional --- packages/auth-helpers/src/lib/siwe/siwe-helper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth-helpers/src/lib/siwe/siwe-helper.ts b/packages/auth-helpers/src/lib/siwe/siwe-helper.ts index e34b438c7f..020c4f005e 100644 --- a/packages/auth-helpers/src/lib/siwe/siwe-helper.ts +++ b/packages/auth-helpers/src/lib/siwe/siwe-helper.ts @@ -38,7 +38,7 @@ export const createCapacityCreditsResourceData = ( ), } : {}), - uses: params.uses!.toString() || '1', + ...(params.uses ? { uses: params.uses.toString() } : { uses: '1' }), }; }; From fedd3172d847feacbba07810929dbeb75fff7df5 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 1 May 2024 23:06:12 +0100 Subject: [PATCH 073/263] feat: add removeHexPrefix helper --- packages/misc/src/lib/misc.spec.ts | 17 +++++++++++++++++ packages/misc/src/lib/misc.ts | 25 ++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/packages/misc/src/lib/misc.spec.ts b/packages/misc/src/lib/misc.spec.ts index 9bd57b0981..c4c0870c6d 100644 --- a/packages/misc/src/lib/misc.spec.ts +++ b/packages/misc/src/lib/misc.spec.ts @@ -271,3 +271,20 @@ describe('double escaped JSON string', () => { ); }); }); +it('should remove hex prefix from a string', () => { + const input = '0xabcdef'; + const expectedOutput = 'abcdef'; + + const result = utilsModule.removeHexPrefix(input); + + expect(result).toBe(expectedOutput); +}); + +it('should not remove hex prefix if it is not present', () => { + const input = 'abcdef'; + const expectedOutput = 'abcdef'; + + const result = utilsModule.removeHexPrefix(input); + + expect(result).toBe(expectedOutput); +}); diff --git a/packages/misc/src/lib/misc.ts b/packages/misc/src/lib/misc.ts index d5099c8dea..1456dd4c4b 100644 --- a/packages/misc/src/lib/misc.ts +++ b/packages/misc/src/lib/misc.ts @@ -699,12 +699,31 @@ export const defaultMintClaimCallback: MintCallback< } }; -export const hexPrefixed = (str: string) => { +/** + * Adds a '0x' prefix to a string if it doesn't already have one. + * @param str - The input string. + * @returns The input string with a '0x' prefix. + */ +export const hexPrefixed = (str: string): `0x${string}` => { + if (str.startsWith('0x')) { + return str as `0x${string}`; + } + + return ('0x' + str) as `0x${string}`; +}; + +/** + * Removes the '0x' prefix from a hexadecimal string if it exists. + * + * @param str - The input string. + * @returns The input string with the '0x' prefix removed, if present. + */ +export const removeHexPrefix = (str: string) => { if (str.startsWith('0x')) { - return str; + return str.slice(2); } - return '0x' + str; + return str; }; /** From 4181066e38270a448f3a6de3bf5163aa0f97a7dc Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 1 May 2024 23:13:14 +0100 Subject: [PATCH 074/263] fix: 1. sessionKey to be passed to the callbacks 2. Replace `any` promise type to `NodeCommandResponse` 3. Rename `handleBlsResponse` to `getBlsSignatures` 4. Use JsDoc instead in `AuthCallbackParams` interface --- ...nse.spec.ts => get-bls-signatures.test.ts} | 21 +++- .../src/lib/helpers/get-bls-signatures.ts | 32 +++++ .../src/lib/helpers/handle-bls-response.ts | 30 ----- .../src/lib/lit-node-client-nodejs.ts | 112 +++++++----------- packages/types/src/lib/interfaces.ts | 36 ++++-- 5 files changed, 113 insertions(+), 118 deletions(-) rename packages/lit-node-client-nodejs/src/lib/helpers/{handle-bls-response.spec.ts => get-bls-signatures.test.ts} (88%) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.ts delete mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.test.ts similarity index 88% rename from packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts rename to packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.test.ts index 79a0a227ab..b08c9ebf8a 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.spec.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.test.ts @@ -1,6 +1,6 @@ -import { handleBlsResponseData } from './handle-bls-response'; +import { getBlsSignatures } from './get-bls-signatures'; -describe('handleBlsResponseData', () => { +describe('getBlsSignatures', () => { it('should return an array of signed data', () => { const responseData = [ { @@ -50,12 +50,21 @@ describe('handleBlsResponseData', () => { }, ] as any; - const result = handleBlsResponseData(responseData); + const result = getBlsSignatures(responseData); expect(result).toEqual([ - 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', - 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', - 'b2efe867176b9212fd6acd39a33004a17e03d5a931250c700e31af95e2e7e4d5', + { + ProofOfPossession: + '01b191b1d281857a95d2fd189683db366ab1088723338c1805daa4650459e9fcaebaa57b58108c284d233404dd5f2e58f208aafb87d981098aba3fe850980184a4b29643a21107b03f1d928646245b57af3745a81418989e0b6aad9bd1f192723c', + }, + { + ProofOfPossession: + '038178034edcd5b48da4e2af6eb0891ece41389aa6119c80546d3fa00b5d2ba87eaec327b18d8013714b486246807498c8198e70cf8e917b1a5f1d8d0846787172521d41994de95bd641bdc1d9ccee9b459ceeb03f156cf357a4ff8faf5d2e167d', + }, + { + ProofOfPossession: + '0292a026325a166398b85b53f3a7a34d147c5337e189d75c33c0f227f7926c839b408dfcc5d242a8685a81c68e0ccedc080c051219161dbc37f06627259b19d15120ab2f710075a44b1dcef18d511bb99b6625c8f575d2688c6b5b01ba6bf448c9', + }, ]); }); }); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.ts new file mode 100644 index 0000000000..5ba4cfa069 --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-bls-signatures.ts @@ -0,0 +1,32 @@ +import { log } from '@lit-protocol/misc'; +import { BlsResponseData, BlsSignatureShare } from '@lit-protocol/types'; + +/** + * Get the BLS signatures from the response data. + * @param responseData - The response data from BLS signature scheme. + * @returns An array of BLS signatures. + * @throws Error if no data is provided. + */ +export function getBlsSignatures( + responseData: BlsResponseData[] +): BlsSignatureShare[] { + if (!responseData) { + throw new Error('[getBlsSignatures] No data provided'); + } + + const signatureShares = responseData.map((s) => ({ + ProofOfPossession: s.signatureShare.ProofOfPossession, + })); + log(`[getBlsSignatures] signatureShares:`, signatureShares); + + if (!signatureShares || signatureShares.length <= 0) { + throw new Error('[getBlsSignatures] No signature shares provided'); + } + + return signatureShares; + + // const signedDataList = responseData.map((s) => s.dataSigned); + // log(`[getBlsSignatures] signedDataList:`, signedDataList); + + // return signedDataList; +} diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts b/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts deleted file mode 100644 index 5801f79fa8..0000000000 --- a/packages/lit-node-client-nodejs/src/lib/helpers/handle-bls-response.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { log } from '@lit-protocol/misc'; -import { BlsResponseData } from '@lit-protocol/types'; - -/** - * Handles the response data from BLS signature scheme. - * @param responseData - The response data from BLS signature scheme. - * @returns An array of signed data. - * @throws Error if no data is provided. - */ -export function handleBlsResponseData( - responseData: BlsResponseData[] -): string[] { - if (!responseData) { - throw new Error('[handleBlsResponseData] No data provided'); - } - - const signatureShares = responseData.map((s) => ({ - ProofOfPossession: s.signatureShare.ProofOfPossession, - })); - log(`[handleBlsResponseData] signatureShares:`, signatureShares); - - if (!signatureShares || signatureShares.length <= 0) { - throw new Error('[handleBlsResponseData] No signature shares provided'); - } - - const signedDataList = responseData.map((s) => s.dataSigned); - log(`[handleBlsResponseData] signedDataList:`, signedDataList); - - return signedDataList; -} diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 5d949e5e3e..5f928e309a 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1,7 +1,7 @@ import { computeAddress } from '@ethersproject/transactions'; import { BigNumber, ethers } from 'ethers'; import { joinSignature, sha256 } from 'ethers/lib/utils'; -import * as siwe from 'siwe'; +import { SiweMessage } from 'siwe'; import { canonicalAccessControlConditionFormatter } from '@lit-protocol/access-control-conditions'; import { @@ -48,6 +48,7 @@ import { logWithRequestId, mostCommonString, normalizeAndStringify, + removeHexPrefix, throwError, } from '@lit-protocol/misc'; import { @@ -128,7 +129,7 @@ import { getClaimsList } from './helpers/get-claims-list'; import { getClaims } from './helpers/get-claims'; import { normalizeArray } from './helpers/normalize-array'; import { parsePkpSignResponse } from './helpers/parse-pkp-sign-response'; -import { handleBlsResponseData } from './helpers/handle-bls-response'; +import { getBlsSignatures } from './helpers/get-bls-signatures'; export class LitNodeClientNodeJs extends LitCore @@ -345,6 +346,7 @@ export class LitNodeClientNodeJs litActionCode, ipfsId, jsParams, + sessionKey, }: GetWalletSigProps): Promise => { let walletSig: AuthSig; @@ -382,6 +384,7 @@ export class LitNodeClientNodeJs ...(switchChain && { switchChain }), expiration, uri: sessionKeyUri, + sessionKey: sessionKey, nonce, // for recap @@ -513,7 +516,7 @@ export class LitNodeClientNodeJs sessionKeyUri: any; resourceAbilityRequests: LitResourceAbilityRequest[]; }): Promise => { - const authSigSiweMessage = new siwe.SiweMessage(authSig.signedMessage); + const authSigSiweMessage = new SiweMessage(authSig.signedMessage); try { await authSigSiweMessage.validate(authSig.sig); @@ -1276,7 +1279,7 @@ export class LitNodeClientNodeJs url: string, params: any, requestId: string - ): Promise => { + ): Promise => { return await this.sendCommandToNode({ url, data: params, @@ -2098,7 +2101,7 @@ export class LitNodeClientNodeJs return {} as SignSessionKeyResponse; } - const responseData = res.values; + const responseData: BlsResponseData[] = res.values; logWithRequestId( requestId, '[signSessionKey] responseData', @@ -2116,15 +2119,7 @@ export class LitNodeClientNodeJs log(`[signSessionKey] curveType is "${curveType}"`); - let signedDataList: any[] = []; - - if (curveType === LIT_CURVE.BLS) { - signedDataList = handleBlsResponseData(responseData); - } else { - signedDataList = responseData.map( - (r: any) => (r as SignedData).signedData - ); - } + let signedDataList = responseData.map((s) => s.dataSigned); if (signedDataList.length <= 0) { const err = `[signSessionKey] signedDataList is empty.`; @@ -2139,16 +2134,8 @@ export class LitNodeClientNodeJs ); // -- checking if we have enough shares - const validatedSignedDataList = signedDataList - .map((signedData: any) => { - const sessionSig = signedData['sessionSig'] ?? signedData; - - // add backwards compatibility for `sigType` field - // For more context: Previously, the field was called `sigType` but it was changed to `curveType` because we are now using BLS instead of ECDSA. - if (sessionSig['curveType'] && !sessionSig['sigType']) { - sessionSig['sigType'] = sessionSig['curveType']; - } - + const validatedSignedDataList = responseData + .map((data: BlsResponseData) => { // each of this field cannot be empty let requiredFields = [ 'signatureShare', @@ -2162,7 +2149,9 @@ export class LitNodeClientNodeJs // check if all required fields are present for (const field of requiredFields) { - if (!sessionSig[field] || sessionSig[field] === '') { + const key: keyof BlsResponseData = field as keyof BlsResponseData; + + if (!data[key] || data[key] === '') { log( `[signSessionKey] Invalid signed data. "${field}" is missing. Not a problem, we only need ${this.config.minNodeCount} nodes to sign the session key.` ); @@ -2170,15 +2159,13 @@ export class LitNodeClientNodeJs } } - if (curveType === LIT_CURVE.BLS) { - if (!sessionSig.signatureShare.ProofOfPossession) { - const err = `[signSessionKey] Invalid signed data. "ProofOfPossession" is missing.`; - log(err); - throw new Error(err); - } + if (!data.signatureShare.ProofOfPossession) { + const err = `[signSessionKey] Invalid signed data. "ProofOfPossession" is missing.`; + log(err); + throw new Error(err); } - return signedData; + return data; }) .filter((item) => item !== null); @@ -2203,15 +2190,13 @@ export class LitNodeClientNodeJs ); } - let signatures: any; - const blsSignedData: BlsResponseData[] = validatedSignedDataList as BlsResponseData[]; - const sigType = mostCommonString(blsSignedData.map((s: any) => s.sigType)); + const sigType = mostCommonString(blsSignedData.map((s) => s.curveType)); log(`[signSessionKey] sigType:`, sigType); - const signatureShares = handleBlsResponseData(blsSignedData); + const signatureShares = getBlsSignatures(blsSignedData); log(`[signSessionKey] signatureShares:`, signatureShares); @@ -2221,58 +2206,38 @@ export class LitNodeClientNodeJs log(`[signSessionKey] blsCombinedSignature:`, blsCombinedSignature); - const publicKey = params.pkpPublicKey.startsWith('0x') - ? params.pkpPublicKey.slice(2) - : params.pkpPublicKey; + const publicKey = removeHexPrefix(params.pkpPublicKey); + log(`[signSessionKey] publicKey:`, publicKey); const dataSigned = mostCommonString( blsSignedData.map((s: any) => s.dataSigned) ); + log(`[signSessionKey] dataSigned:`, dataSigned); + const mostCommonSiweMessage = mostCommonString( blsSignedData.map((s: any) => s.siweMessage) ); - signatures = { - sessionSig: { - signature: blsCombinedSignature, - publicKey, - dataSigned, - siweMessage: mostCommonSiweMessage, - }, - }; - - log('[signSessionKey] signatures:', signatures); + log(`[signSessionKey] mostCommonSiweMessage:`, mostCommonSiweMessage); - const { sessionSig } = signatures; - - const signedMessage = normalizeAndStringify(sessionSig.siweMessage); + const signedMessage = normalizeAndStringify(mostCommonSiweMessage); log(`[signSessionKey] signedMessage:`, signedMessage); - if (curveType === LIT_CURVE.BLS) { - return { - authSig: { - sig: JSON.stringify({ - ProofOfPossession: sessionSig.signature, - }), - algo: 'LIT_BLS', - derivedVia: 'lit.bls', - signedMessage, - address: computeAddress('0x' + sessionSig.publicKey), - }, - pkpPublicKey: sessionSig.publicKey, - }; - } - - return { + const signSessionKeyRes: SignSessionKeyResponse = { authSig: { - sig: sessionSig.signature, - derivedVia: 'web3.eth.personal.sign via Lit PKP', + sig: JSON.stringify({ + ProofOfPossession: blsCombinedSignature, + }), + algo: 'LIT_BLS', + derivedVia: 'lit.bls', signedMessage, - address: computeAddress('0x' + sessionSig.publicKey), + address: computeAddress(hexPrefixed(publicKey)), }, - pkpPublicKey: sessionSig.publicKey, + pkpPublicKey: publicKey, }; + + return signSessionKeyRes; }; #isSuccessNodePromises = (res: any): res is SuccessNodePromises => { @@ -2364,6 +2329,7 @@ export class LitNodeClientNodeJs sessionCapabilityObject, switchChain: params.switchChain, expiration: expiration, + sessionKey: sessionKey, sessionKeyUri: sessionKeyUri, nonce, @@ -2395,6 +2361,7 @@ export class LitNodeClientNodeJs resources: [sessionCapabilityObject.encodeAsSiweResource()], switchChain: params.switchChain, expiration, + sessionKey: sessionKey, uri: sessionKeyUri, nonce, resourceAbilityRequests: params.resourceAbilityRequests, @@ -2511,6 +2478,7 @@ export class LitNodeClientNodeJs } const response = await this.signSessionKey({ + sessionKey: props.sessionKey, statement: props.statement || 'Some custom statement.', authMethods: [...params.authMethods], pkpPublicKey: params.pkpPublicKey, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 2f1789bb01..19675e3128 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -43,21 +43,34 @@ export interface AuthSig { export type CosmosWalletType = 'keplr' | 'leap'; export interface AuthCallbackParams { - // The chain you want to use. Find the supported list of chains here: https://developer.litprotocol.com/docs/supportedChains + /** + * The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. + */ + sessionKey?: SessionKeyPair; + + /** + * The chain you want to use. Find the supported list of chains here: https://developer.litprotocol.com/docs/supportedChains + */ chain: Chain; - // The statement that describes what the user is signing. If the auth callback - // is for signing a SIWE message, you MUST add this statement to the end of the SIWE - // statement. + /** + * The statement that describes what the user is signing. If the auth callback is for signing a SIWE message, you MUST add this statement to the end of the SIWE statement. + */ statement?: string; - // The blockhash that the nodes return during the handshake + /** + * The blockhash that the nodes return during the handshake + */ nonce: string; - // Optional and only used with EVM chains. A list of resources to be passed to Sign In with Ethereum. These resources will be part of the Sign in with Ethereum signed message presented to the user. + /** + * Optional and only used with EVM chains. A list of resources to be passed to Sign In with Ethereum. These resources will be part of the Sign in with Ethereum signed message presented to the user. + */ resources?: string[]; - // Optional and only used with EVM chains right now. Set to true by default. Whether or not to ask Metamask or the user's wallet to switch chains before signing. This may be desired if you're going to have the user send a txn on that chain. On the other hand, if all you care about is the user's wallet signature, then you probably don't want to make them switch chains for no reason. Pass false here to disable this chain switching behavior. + /** + * Optional and only used with EVM chains right now. Set to true by default. Whether or not to ask Metamask or the user's wallet to switch chains before signing. This may be desired if you're going to have the user send a txn on that chain. On the other hand, if all you care about is the user's wallet signature, then you probably don't want to make them switch chains for no reason. Pass false here to disable this chain switching behavior. + */ switchChain?: boolean; // --- Following for Session Auth --- @@ -65,9 +78,11 @@ export interface AuthCallbackParams { uri?: string; - // Cosmos wallet type, to support mutliple popular cosmos wallets - // Keplr & Cypher -> window.keplr - // Leap -> window.leap + /** + * Cosmos wallet type, to support mutliple popular cosmos wallets + * Keplr & Cypher -> window.keplr + * Leap -> window.leap + */ cosmosWalletType?: CosmosWalletType; /** @@ -1072,6 +1087,7 @@ export interface GetWalletSigProps extends LitCustomAuth { sessionCapabilityObject: ISessionCapabilityObject; switchChain?: boolean; expiration: string; + sessionKey: SessionKeyPair; sessionKeyUri: string; nonce: string; resourceAbilityRequests?: LitResourceAbilityRequest[]; From 83db155eea8d5578464f92b5110ecb46be4aecf2 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 1 May 2024 23:25:44 +0100 Subject: [PATCH 075/263] Published version 6.0.0-alpha.1@cayenne https://www.npmjs.com/package/@lit-protocol/lit-node-client/v/6.0.0-alpha.1 --- lerna.json | 2 +- .../access-control-conditions/package.json | 4 ++-- packages/auth-browser/package.json | 4 ++-- packages/auth-helpers/package.json | 4 ++-- packages/bls-sdk/package.json | 4 ++-- packages/constants/package.json | 4 ++-- .../src/lib/constants/autogen_internal.ts | 18 ++++++++++++++++-- packages/constants/src/lib/version.ts | 2 +- packages/contracts-sdk/package.json | 4 ++-- packages/core/package.json | 4 ++-- packages/crypto/package.json | 4 ++-- packages/ecdsa-sdk/package.json | 4 ++-- packages/encryption/package.json | 4 ++-- packages/lit-auth-client/package.json | 4 ++-- packages/lit-node-client-nodejs/package.json | 4 ++-- packages/lit-node-client/package.json | 4 ++-- packages/logger/package.json | 4 ++-- packages/misc-browser/package.json | 4 ++-- packages/misc/package.json | 4 ++-- packages/nacl/package.json | 4 ++-- packages/pkp-base/package.json | 4 ++-- packages/pkp-client/package.json | 4 ++-- packages/pkp-cosmos/package.json | 4 ++-- packages/pkp-ethers/package.json | 4 ++-- packages/pkp-sui/package.json | 4 ++-- packages/pkp-walletconnect/package.json | 4 ++-- packages/sev-snp-utils-sdk/package.json | 4 ++-- packages/types/package.json | 4 ++-- packages/uint8arrays/package.json | 4 ++-- 29 files changed, 70 insertions(+), 56 deletions(-) diff --git a/lerna.json b/lerna.json index 200b235601..ea99d3dbed 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "useNx": true, "useWorkspaces": true, - "version": "5.0.0" + "version": "6.0.0-alpha.1" } diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index fcf662dcf1..867f3ea362 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 990cbb8e2c..0dd92f6441 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -30,7 +30,7 @@ "tags": [ "browser" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 71f7376a39..300f3f80c2 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 925e1e3405..2be81894f8 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/package.json b/packages/constants/package.json index 513adaf1a5..a7420c1e05 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/src/lib/constants/autogen_internal.ts b/packages/constants/src/lib/constants/autogen_internal.ts index a7ba16f7be..98f0e489a0 100644 --- a/packages/constants/src/lib/constants/autogen_internal.ts +++ b/packages/constants/src/lib/constants/autogen_internal.ts @@ -1,5 +1,12 @@ // This file is auto-generated by tools/scripts/gen-internal-dev.mjs -export const INTERNAL_DEV = []; +export const INTERNAL_DEV = [ + 'https://167.114.17.201:443', + 'https://64.131.85.106:443', + 'https://167.114.17.202:443', + 'https://199.115.117.113:443', + 'https://167.114.17.203:443', + 'https://108.62.0.105:443', +]; export const INTERNAL_MIN_NODE_COUNT = 2; @@ -7,7 +14,14 @@ export const INTERNAL_DEFAULT_CONFIG = { alertWhenUnauthorized: false, minNodeCount: 2, debug: true, - bootstrapUrls: [], + bootstrapUrls: [ + 'https://167.114.17.201:443', + 'https://64.131.85.106:443', + 'https://167.114.17.202:443', + 'https://199.115.117.113:443', + 'https://167.114.17.203:443', + 'https://108.62.0.105:443', + ], litNetwork: 'internalDev', connectTimeout: 20000, }; diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index 56b7f45436..5a6c12d616 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = '5.0.0'; +export const version = '6.0.0-alpha.1'; diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 4c7957b91f..3a8f4b5889 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -32,7 +32,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 16315209ab..d99c2b2ef3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/core", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 531874b629..016cca9105 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index f74bbdd8a4..b58823787b 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 350d10aa5f..d2fab11731 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index fc5cba086b..b9a7990769 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/lit-auth-client", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 55a1af340c..1e85f9dd29 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -24,7 +24,7 @@ "tags": [ "nodejs" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index e830f38b86..b3dc3ba059 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/logger/package.json b/packages/logger/package.json index 92749cbcca..c199ce3293 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/logger", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "tags": [ "universal" @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 5e8f4090e3..34eb65c61d 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -21,7 +21,7 @@ "tags": [ "browser" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc/package.json b/packages/misc/package.json index 64fb19f03c..25917a6a3b 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/nacl/package.json b/packages/nacl/package.json index c441d8e1d4..089d70fe07 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -21,7 +21,7 @@ "access": "public", "directory": "../../dist/packages/nacl" }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 2c06530b86..72b5e19323 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-base", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 166ee38217..d09180a573 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-client", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 973dc862b6..8e3cdd1dd9 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-cosmos", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 5935b60701..12253d0f23 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index bf6fa526b1..727e238775 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-sui", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index b0eeb46af6..ce3b4a0c77 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-walletconnect", - "version": "5.0.0", + "version": "6.0.0-alpha.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 47504bca7b..af3aad5136 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/types/package.json b/packages/types/package.json index fc63e7af0a..daf515d3eb 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -23,7 +23,7 @@ "buildOptions": { "genReact": false }, - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 4049e70a1a..42d20158f1 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "5.0.0", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file From 4330d82261b8790c2ed3e9a689891476dd4123e3 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 01:31:29 +0100 Subject: [PATCH 076/263] fix: add `tslib` peer dependency, otherwise recap won't work ``` /node_modules/tslib/tslib.js:250 return privateMap.get(receiver); ^ TypeError: privateMap.get is not a function ``` --- packages/lit-node-client/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index b3dc3ba059..a4053f0697 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -21,6 +21,9 @@ "tags": [ "universal" ], + "peerDependencies": { + "tslib": "^2.3.0" + }, "browser": { "crypto": false, "stream": false @@ -28,4 +31,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} From c5b3bf114b9ca376c0dd88eef4982e70ef3aa853 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 02:15:20 +0100 Subject: [PATCH 077/263] feat: add ResourceAbilityRequestBuilder --- packages/auth-helpers/src/index.ts | 1 + .../src/lib/recap/resource-builder.spec.ts | 73 ++++++++++++++++ .../src/lib/recap/resource-builder.ts | 87 +++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 packages/auth-helpers/src/lib/recap/resource-builder.spec.ts create mode 100644 packages/auth-helpers/src/lib/recap/resource-builder.ts diff --git a/packages/auth-helpers/src/index.ts b/packages/auth-helpers/src/index.ts index 6f47917e46..151c2d8ba7 100644 --- a/packages/auth-helpers/src/index.ts +++ b/packages/auth-helpers/src/index.ts @@ -3,3 +3,4 @@ export * from './lib/session-capability-object'; export * from './lib/resources'; export * from './lib/siwe'; export * from './lib/recap/recap-session-capability-object'; +export * from './lib/recap/resource-builder' \ No newline at end of file diff --git a/packages/auth-helpers/src/lib/recap/resource-builder.spec.ts b/packages/auth-helpers/src/lib/recap/resource-builder.spec.ts new file mode 100644 index 0000000000..8c77239b31 --- /dev/null +++ b/packages/auth-helpers/src/lib/recap/resource-builder.spec.ts @@ -0,0 +1,73 @@ +import { LitAbility } from '../models'; +import { + LitAccessControlConditionResource, + LitActionResource, + LitPKPResource, + LitRLIResource, +} from '../resources'; +import { ResourceAbilityRequestBuilder } from './resource-builder'; + +describe('ResourceAbilityRequestBuilder', () => { + let builder: ResourceAbilityRequestBuilder; + + beforeEach(() => { + builder = new ResourceAbilityRequestBuilder(); + }); + + it('should build an array of resource ability requests', () => { + const resourceId1 = '123'; + const resourceId2 = '456'; + builder + .addPKPSigningRequest(resourceId1) + .addLitActionExecutionRequest(resourceId2); + + const requests = builder.build(); + expect(JSON.stringify(requests)).toBe( + JSON.stringify([ + { + resource: new LitPKPResource('123'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('456'), + ability: LitAbility.LitActionExecution, + }, + ]) + ); + }); + + it('should build an array of resource ability requests with all types', () => { + builder + .addPKPSigningRequest('123') // PKP Signing + .addLitActionExecutionRequest('456') // Lit Action Execution + .addAccessControlConditionSigningRequest('789') // ACC Signing + .addAccessControlConditionDecryptionRequest('abc') // ACC Decryption + .addRateLimitIncreaseAuthRequest('def'); // RLI Authentication + + const requests = builder.build(); + expect(JSON.stringify(requests)).toBe( + JSON.stringify([ + { + resource: new LitPKPResource('123'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('456'), + ability: LitAbility.LitActionExecution, + }, + { + resource: new LitAccessControlConditionResource('789'), + ability: LitAbility.AccessControlConditionSigning, + }, + { + resource: new LitAccessControlConditionResource('abc'), + ability: LitAbility.AccessControlConditionDecryption, + }, + { + resource: new LitRLIResource('def'), + ability: LitAbility.RateLimitIncreaseAuth, + }, + ]) + ); + }); +}); diff --git a/packages/auth-helpers/src/lib/recap/resource-builder.ts b/packages/auth-helpers/src/lib/recap/resource-builder.ts new file mode 100644 index 0000000000..021dcd94d5 --- /dev/null +++ b/packages/auth-helpers/src/lib/recap/resource-builder.ts @@ -0,0 +1,87 @@ +import { ILitResource, LitAbility } from '../models'; +import { + LitAccessControlConditionResource, + LitActionResource, + LitPKPResource, + LitRLIResource, +} from '../resources'; + +/** + * Lit resrouce ability request builder for creating resource ability requests. + */ +export class ResourceAbilityRequestBuilder { + private requests: Array<{ resource: ILitResource; ability: LitAbility }> = []; + + /** + * Adds a PKP signing request to the builder. + * @param resourceId - The ID of the resource. + * @returns The builder instance. + */ + addPKPSigningRequest(resourceId: string): this { + this.requests.push({ + resource: new LitPKPResource(resourceId), + ability: LitAbility.PKPSigning, + }); + return this; + } + + /** + * Adds a Lit action execution request to the builder. + * @param resourceId - The ID of the resource. + * @returns The builder instance. + */ + addLitActionExecutionRequest(resourceId: string): this { + this.requests.push({ + resource: new LitActionResource(resourceId), + ability: LitAbility.LitActionExecution, + }); + return this; + } + + /** + * Adds an access control condition signing request to the builder. + * @param resourceId - The ID of the resource. + * @returns The builder instance. + */ + addAccessControlConditionSigningRequest(resourceId: string): this { + this.requests.push({ + resource: new LitAccessControlConditionResource(resourceId), + ability: LitAbility.AccessControlConditionSigning, + }); + return this; + } + + /** + * Adds an access control condition decryption request to the builder. + * @param resourceId - The ID of the resource. + * @returns The builder instance. + */ + addAccessControlConditionDecryptionRequest(resourceId: string): this { + this.requests.push({ + resource: new LitAccessControlConditionResource(resourceId), + ability: LitAbility.AccessControlConditionDecryption, + }); + return this; + } + + /** + * Adds a rate limit increase authentication request to the builder. + * @param resourceId - The ID of the resource. + * @returns The builder instance. + */ + addRateLimitIncreaseAuthRequest(resourceId: string): this { + this.requests.push({ + resource: new LitRLIResource(resourceId), + ability: LitAbility.RateLimitIncreaseAuth, + }); + return this; + } + + /** + * Builds the array of resource ability requests. + * @returns The array of resource ability requests. + */ + build(): Array<{ resource: ILitResource; ability: LitAbility }> { + return this.requests; + } +} From 989fa79ac0742785bb0ec2483037a8e792627c91 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 02:27:38 +0100 Subject: [PATCH 078/263] chore: pretty pretty lint --- packages/auth-helpers/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth-helpers/src/index.ts b/packages/auth-helpers/src/index.ts index 151c2d8ba7..d38b77d852 100644 --- a/packages/auth-helpers/src/index.ts +++ b/packages/auth-helpers/src/index.ts @@ -3,4 +3,4 @@ export * from './lib/session-capability-object'; export * from './lib/resources'; export * from './lib/siwe'; export * from './lib/recap/recap-session-capability-object'; -export * from './lib/recap/resource-builder' \ No newline at end of file +export * from './lib/recap/resource-builder'; From c3bae627087bb06e54fdcd41bc1c7fcaf637cb5a Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 05:47:28 +0100 Subject: [PATCH 079/263] fix: match file name to function name --- .../src/lib/{craft-auth-sig.ts => generate-auth-sig.ts} | 3 +++ 1 file changed, 3 insertions(+) rename packages/auth-helpers/src/lib/{craft-auth-sig.ts => generate-auth-sig.ts} (94%) diff --git a/packages/auth-helpers/src/lib/craft-auth-sig.ts b/packages/auth-helpers/src/lib/generate-auth-sig.ts similarity index 94% rename from packages/auth-helpers/src/lib/craft-auth-sig.ts rename to packages/auth-helpers/src/lib/generate-auth-sig.ts index e1fee7fe27..d6b05b87e9 100644 --- a/packages/auth-helpers/src/lib/craft-auth-sig.ts +++ b/packages/auth-helpers/src/lib/generate-auth-sig.ts @@ -35,6 +35,9 @@ export const generateAuthSig = async ({ address = await signer.getAddress(); } + // checksum the address + address = ethers.utils.getAddress(address); + // If address is still not available, throw an error if (!address) { throw new Error('address is required'); From 86650528ce53aef8efdca5084d916d5c65593c8e Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 13:00:35 +0100 Subject: [PATCH 080/263] fix: auth-sig helper filename --- packages/auth-helpers/src/index.ts | 2 +- packages/auth-helpers/src/lib/generate-auth-sig.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/auth-helpers/src/index.ts b/packages/auth-helpers/src/index.ts index 7d809648a1..eebf63d5fb 100644 --- a/packages/auth-helpers/src/index.ts +++ b/packages/auth-helpers/src/index.ts @@ -5,4 +5,4 @@ export * from './lib/siwe/siwe-helper'; export * from './lib/recap/recap-session-capability-object'; export * from './lib/siwe/create-siwe-message'; export * from './lib/siwe/siwe-helper'; -export * from './lib/craft-auth-sig'; +export * from './lib/generate-auth-sig'; diff --git a/packages/auth-helpers/src/lib/generate-auth-sig.ts b/packages/auth-helpers/src/lib/generate-auth-sig.ts index d6b05b87e9..9123d713cd 100644 --- a/packages/auth-helpers/src/lib/generate-auth-sig.ts +++ b/packages/auth-helpers/src/lib/generate-auth-sig.ts @@ -6,7 +6,8 @@ import { ethers } from 'ethers'; * * For more context: * We are only using authSig to generate session sigs. In a newer version, we will stop accepting - * authSig all together from the node and will only accept session sigs. + * authSig all together from the node and will only accept session sigs. The address being + * used here will be checksummed. * * @param signer the signer must have a "signMessage" method * @param toSign - the message to sign From c2f5a7289133eaf94bdceba651415ab30db81d4b Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 16:34:24 +0100 Subject: [PATCH 081/263] chore: improve JsDocs --- .../src/lib/lit-node-client-nodejs.ts | 27 +++++--- .../src/lib/lit-node-client.ts | 13 ++++ packages/types/src/lib/interfaces.ts | 62 +++++++++++++------ 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 5f928e309a..c743d1aa9f 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -100,7 +100,6 @@ import type { SignSessionKeyProp, SignSessionKeyResponse, Signature, - SignedData, SigningAccessControlConditionRequest, SuccessNodePromises, ValidateAndSignECDSA, @@ -301,15 +300,7 @@ export class LitNodeClientNodeJs // backward compatibility async generateSessionCapabilityObjectWithWildcards( litResources: ILitResource[] - // rateLimitAuthSig?: AuthSig ): Promise { - // if (rateLimitAuthSig) { - // return await LitNodeClientNodeJs.generateSessionCapabilityObjectWithWildcards( - // litResources, - // rateLimitAuthSig - // ); - // } - return await LitNodeClientNodeJs.generateSessionCapabilityObjectWithWildcards( litResources ); @@ -2295,6 +2286,24 @@ export class LitNodeClientNodeJs * be sure to call disconnectWeb3 to clear auth signatures stored in local storage * * @param { GetSessionSigsProps } params + * + * @example + * + * ```ts + * import { LitPKPResource, LitActionResource } from "@lit-protocol/auth-helpers"; +import { LitAbility } from "@lit-protocol/types"; + +const resourceAbilityRequests = [ + { + resource: new LitPKPResource("*"), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource("*"), + ability: LitAbility.LitActionExecution, + }, + ]; + * ``` */ getSessionSigs = async ( params: GetSessionSigsProps diff --git a/packages/lit-node-client/src/lib/lit-node-client.ts b/packages/lit-node-client/src/lib/lit-node-client.ts index f74f0db0de..7d84a9c697 100644 --- a/packages/lit-node-client/src/lib/lit-node-client.ts +++ b/packages/lit-node-client/src/lib/lit-node-client.ts @@ -5,6 +5,19 @@ import { isNode, log } from '@lit-protocol/misc'; import { getStorageItem } from '@lit-protocol/misc-browser'; import { CustomNetwork, LitNodeClientConfig } from '@lit-protocol/types'; +/** + * You can find all these available networks in the `constants` package + * + * @example + * + * ``` + * import { LitNetwork } from '@lit-protocol/constants'; + * + * const litNodeClient = new LitNodeClient({ + litNetwork: LitNetwork.Habanero, + }); + * ``` + */ export class LitNodeClient extends LitNodeClientNodeJs { constructor(args: LitNodeClientConfig | CustomNetwork) { super({ diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 19675e3128..4179923e29 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -474,22 +474,29 @@ export interface JsonExecutionSdkParamsTargetNode } export interface JsonExecutionSdkParams { - // An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. + /** + * An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. + */ jsParams?: any; - // JS code to run on the nodes + /** + * JS code to run on the nodes + */ code?: string; - // The IPFS ID of some JS code to run on the nodes + /** + * The IPFS ID of some JS code to run on the nodes + */ ipfsId?: string; - // the session signatures to use to authorize the user with the nodes + /** + * the session signatures to use to authorize the user with the nodes + */ sessionSigs: any; - // whether to run this on a single node or many - // targetNodeRange?: number; - - // auth methods to resolve + /** + * auth methods to resolve + */ authMethods?: AuthMethod[]; } @@ -959,38 +966,57 @@ export interface AuthMethod { // pub siwe_message: String, // } export interface SignSessionKeyProp { - // The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. + /** + * The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. + */ sessionKey?: SessionKeyPair; - // The statement text to place at the end of the SIWE statement field. + /** + * The statement text to place at the end of the SIWE statement field. + */ statement?: string; - // The auth methods to use to sign the session key + /** + * The auth methods to use to sign the session key + */ authMethods: AuthMethod[]; - // The public key of the PKP + /** + * The public key of the PKP + */ pkpPublicKey?: string; - // The auth sig of the user. Returned via the checkAndSignAuthMessage function + /** + * The auth sig of the user. Returned via the checkAndSignAuthMessage function + */ authSig?: AuthSig; - // The siwe message - // siweMessage: string; - - // When this session signature will expire. The user will have to reauthenticate after this time using whatever auth method you set up. This means you will have to call this signSessionKey function again to get a new session signature. This is a RFC3339 timestamp. The default is 24 hours from now. + /** + * When this session signature will expire. The user will have to reauthenticate after this time using whatever auth method you set up. This means you will have to call this signSessionKey function again to get a new session signature. This is a RFC3339 timestamp. The default is 24 hours from now. */ expiration?: string; resources: any; chainId?: number; - //domain param is required, when calling from environment that doesn't have the 'location' object. i.e. NodeJs server. + /** + * domain param is required, when calling from environment that doesn't have the 'location' object. i.e. NodeJs server. + */ domain?: string; + /** + * A LIT resource ability is a combination of a LIT resource and a LIT ability. + */ resourceAbilityRequests?: LitResourceAbilityRequest[]; + /** + * The js code to run on the nodes + */ litActionCode?: string; + /** + * The params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. + */ jsParams?: { [key: string]: any; publicKey: string; From a8d09d603fd1d150672defe382df7017018c8901 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 16:49:25 +0100 Subject: [PATCH 082/263] docs(capacityCredits): better jsDoc --- packages/types/src/lib/interfaces.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 4179923e29..ec807425c1 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1718,8 +1718,25 @@ export interface CapacityDelegationRequest { export interface CapacityCreditsReq { dAppOwnerWallet: SignerLike; + + /** + * 1. Provided with values: Scopes the delegation to specific NFTs identified by the IDs in the array. The function will only consider the NFTs whose IDs are listed. + * 2. NOT Provided: All NFTs owned by the user are considered eligible under the delegation. The delegation applies universally to all NFTs the user owns. + */ capacityTokenId?: string; + + /** + * 1. Provided: Restricts the use of the delegation to the addresses listed in the array. Only users whose addresses are included can utilize the delegated capabilities. + * 2. NOT Provided: The delegation is universally applicable to anyone. There are no restrictions on who can use the delegated capabilities. + * 3. Empty Array: No one is allowed to use the delegated capabilities since there are no valid user addresses specified. + */ delegateeAddresses?: string[]; + + /** + * 1. Provided: Sets a limit on the number of times the delegation can be used. The function enforces this limit and prevents use beyond it. + * 2. NOT Provided: There is no limit on the number of times the delegation can be used. + * 3. Empty Array: Theoretically, an empty value for uses would mean no uses are possible, effectively disabling the delegation, but typically this scenario should either not be allowed by schema/logic or treated as zero, which also disables the delegation. + */ uses?: string; domain?: string; expiration?: string; From 01e3b4cda5b4b7dc9ca098ea52187c62bcbda0a1 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 2 May 2024 22:28:19 +0100 Subject: [PATCH 083/263] docs: add jsdocs --- .../src/lib/recap/resource-builder.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/auth-helpers/src/lib/recap/resource-builder.ts b/packages/auth-helpers/src/lib/recap/resource-builder.ts index 021dcd94d5..d13b97b871 100644 --- a/packages/auth-helpers/src/lib/recap/resource-builder.ts +++ b/packages/auth-helpers/src/lib/recap/resource-builder.ts @@ -8,6 +8,21 @@ import { /** * Lit resrouce ability request builder for creating resource ability requests. + * + * @example + * import { ResourceAbilityRequestBuilder } from '@lit-protocol/auth-helpers'; + +const builder = new ResourceAbilityRequestBuilder(); + +builder + .addPKPSigningRequest('*') // PKP Signing + .addLitActionExecutionRequest('*') // Lit Action Execution + .addAccessControlConditionSigningRequest('*') // ACC Signing + .addAccessControlConditionDecryptionRequest('*') // ACC Decryption + .addRateLimitIncreaseAuthRequest('*'); // RLI Authentication + +const requests = builder.build(); + */ export class ResourceAbilityRequestBuilder { private requests: Array<{ resource: ILitResource; ability: LitAbility }> = []; From 0164e6622492105c6d9f84beb96e420d0a6fbc7e Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 3 May 2024 16:09:17 +0100 Subject: [PATCH 084/263] feat: cayenne remappings --- .../constants/src/lib/constants/constants.ts | 11 +++++-- packages/core/src/lib/lit-core.ts | 29 +++++++++++++++++-- .../src/lib/lit-node-client-nodejs.ts | 23 ++++++++++++--- packages/misc/src/lib/misc.spec.ts | 11 ++++++- packages/misc/src/lib/misc.ts | 23 +++++++++++++++ 5 files changed, 86 insertions(+), 11 deletions(-) diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 042d6d8c8d..e16e1526e8 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -729,6 +729,11 @@ export const SYMM_KEY_ALGO_PARAMS = { length: 256, }; +/** + * Default node URL for Cayenne network + */ +export const CAYENNE_URL = 'https://cayenne.litgateway.com'; + /** * Default node URLs for each LIT network * Note: Dynamic networks such as Habanero have no default node URLS; they are always @@ -739,9 +744,9 @@ export const LIT_NETWORKS: { [key in LitNetwork]: string[] } & { internalDev: string[]; } = { [LitNetwork.Cayenne]: [ - 'https://cayenne.litgateway.com:7370', - 'https://cayenne.litgateway.com:7371', - 'https://cayenne.litgateway.com:7372', + `${CAYENNE_URL}:7370'`, + `${CAYENNE_URL}:7371'`, + `${CAYENNE_URL}:7372'`, ], [LitNetwork.Manzano]: [], [LitNetwork.Habanero]: [], diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 4176bb87a5..f59e2cd970 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -23,12 +23,14 @@ import { StakingStates, version, LIT_ENDPOINT, + CAYENNE_URL, } from '@lit-protocol/constants'; import { LitContracts } from '@lit-protocol/contracts-sdk'; import { checkSevSnpAttestation, computeHDPubKey } from '@lit-protocol/crypto'; import { bootstrapLogManager, executeWithRetry, + getIpAddress, isBrowser, isNode, log, @@ -259,13 +261,34 @@ export class LitCore { this.config.litNetwork ); + const minNodeCount = ( + await LitContracts.getMinNodeCount(this.config.litNetwork) + ).toNumber(); + + const bootstrapUrls = await LitContracts.getValidators( + this.config.litNetwork + ); + + /** + * FIXME: We need this reformatting because the Cayenne network is not able to handle the node address as a URL. + * from: https://cayenne.litgateway.com + * to: http://207.244.70.36:7474 + */ + const remappedBootstrapUrls = await Promise.all( + bootstrapUrls.map(async (url) => { + const rootDomain = CAYENNE_URL.replace('https://', ''); + const ipAddress = await getIpAddress(rootDomain); + return `http://${ipAddress}:${new URL(url).port}`; + }) + ); + // If the network is cayenne it is a centralized testnet, so we use a static config // This is due to staking contracts holding local ip / port contexts which are innacurate to the ip / port exposed to the world - this.config.bootstrapUrls = LIT_NETWORKS.cayenne; + this.config.bootstrapUrls = remappedBootstrapUrls; this.config.minNodeCount = - LIT_NETWORKS.cayenne.length == 2 + remappedBootstrapUrls.length == 2 ? 2 - : (LIT_NETWORKS.cayenne.length * 2) / 3; + : (remappedBootstrapUrls.length * 2) / 3; /** * Here we are checking if a custom network defined with no node urls (bootstrap urls) defined diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index c743d1aa9f..0c01bad592 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2418,10 +2418,25 @@ const resourceAbilityRequests = [ const signatures: SessionSigsMap = {}; this.connectedNodes.forEach((nodeAddress: string) => { - const toSign: SessionSigningTemplate = { - ...signingTemplate, - nodeAddress, - }; + let toSign: SessionSigningTemplate; + + // FIXME: We need this reformatting because the Cayenne network is not able to handle the node address as a URL. + // We are converting back + // from: http://207.244.70.36:7474 + // to: 127.0.0.1:7474 + if (this.config.litNetwork === LitNetwork.Cayenne) { + const url = new URL(nodeAddress); + const newNodeAddress = `127.0.0.1:${url.port}`; + toSign = { + ...signingTemplate, + nodeAddress: newNodeAddress, + }; + } else { + toSign = { + ...signingTemplate, + nodeAddress, + }; + } const signedMessage = JSON.stringify(toSign); diff --git a/packages/misc/src/lib/misc.spec.ts b/packages/misc/src/lib/misc.spec.ts index c4c0870c6d..5cf4edeb09 100644 --- a/packages/misc/src/lib/misc.spec.ts +++ b/packages/misc/src/lib/misc.spec.ts @@ -4,7 +4,7 @@ global.TextEncoder = TextEncoder; // @ts-ignore global.TextDecoder = TextDecoder; -import { LitErrorKind, LIT_ERROR } from '@lit-protocol/constants'; +import { LitErrorKind, LIT_ERROR, CAYENNE_URL } from '@lit-protocol/constants'; import * as utilsModule from './misc'; describe('utils', () => { @@ -288,3 +288,12 @@ it('should not remove hex prefix if it is not present', () => { expect(result).toBe(expectedOutput); }); + +it('should get ip address', async () => { + // polyfill fetch + const fetch = require('node-fetch'); + global.fetch = fetch; + + const ipAddres = await utilsModule.getIpAddress('cayenne.litgateway.com'); + expect(ipAddres).toBe('1'); +}); diff --git a/packages/misc/src/lib/misc.ts b/packages/misc/src/lib/misc.ts index 1456dd4c4b..223ae1df6d 100644 --- a/packages/misc/src/lib/misc.ts +++ b/packages/misc/src/lib/misc.ts @@ -915,3 +915,26 @@ export function normalizeAndStringify(input: string): string { return normalizeAndStringify(unescaped); } } + +/** + * Retrieves the IP address associated with a given domain. + * @param domain - The domain for which to retrieve the IP address. + * @returns A Promise that resolves to the IP address. + * @throws If no IP address is found or if the domain name is invalid. + */ +export async function getIpAddress(domain: string): Promise { + const apiURL = `https://dns.google/resolve?name=${domain}&type=A`; + + try { + const response = await fetch(apiURL); + const data = await response.json(); + + if (data.Answer && data.Answer.length > 0) { + return data.Answer[0].data; + } else { + throw new Error('No IP Address found or bad domain name'); + } + } catch (error: any) { + throw new Error(error); + } +} From d5925ad06dee013912c6206909baf09e6548945d Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 3 May 2024 18:24:58 +0100 Subject: [PATCH 085/263] chore: add comment --- packages/constants/src/lib/constants/constants.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index e16e1526e8..2a534af674 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -743,6 +743,8 @@ export const LIT_NETWORKS: { [key in LitNetwork]: string[] } & { localhost: string[]; internalDev: string[]; } = { + + // FIXME: Reviewers! These are not used in this branch, scroll down to see remapping logic [LitNetwork.Cayenne]: [ `${CAYENNE_URL}:7370'`, `${CAYENNE_URL}:7371'`, From 45276bd054c1419205b4501906bc28c27015453c Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 3 May 2024 22:38:36 +0100 Subject: [PATCH 086/263] feat: add litActionIpfsId to param --- .../get-lit-action-session-sigs.ts | 44 ++++++++++ local-tests/test.ts | 4 + ...eGeneratedSessionSigsToExecuteJsSigning.ts | 6 +- ...eGeneratedSessionSigsToExecuteJsSigning.ts | 81 +++++++++++++++++++ ...onIpfsCodeGeneratedSessionSigsToPkpSign.ts | 62 ++++++++++++++ .../src/lib/lit-node-client-nodejs.ts | 3 + packages/types/src/lib/interfaces.ts | 9 ++- 7 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts create mode 100644 local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts diff --git a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts index 1ccca73331..4036a5ed05 100644 --- a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts +++ b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts @@ -21,6 +21,8 @@ const INVALID_SESSION_SIG_LIT_ACTION_CODE = ` })(); `; +export const VALID_IPFS_ID = 'QmNZQXmY2VijUPfNrkC6zWykBnEniDouAeUpFi9r6aaqNz'; + export const getLitActionSessionSigs = async ( devEnv: TinnyEnvironment, alice: TinnyPerson, @@ -65,6 +67,48 @@ export const getLitActionSessionSigs = async ( return litActionSessionSigs; }; +export const getLitActionSessionSigsUsingIpfsId = async ( + devEnv: TinnyEnvironment, + alice: TinnyPerson, + resourceAbilityRequests?: LitResourceAbilityRequest[] +) => { + if (devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano) { + console.warn( + 'Manzano network detected. Adding capacityDelegationAuthSig to litActionSessionSigs' + ); + } + + // Use default resourceAbilityRequests if not provided + const _resourceAbilityRequests = resourceAbilityRequests || [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ]; + + const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: alice.authMethodOwnedPkp.publicKey, + authMethods: [alice.authMethod], + resourceAbilityRequests: _resourceAbilityRequests, + litActionIpfsId: VALID_IPFS_ID, + jsParams: { + publicKey: alice.authMethodOwnedPkp.publicKey, + sigName: 'unified-auth-sig', + }, + + // -- only add this for manzano network + ...(devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano + ? { capacityDelegationAuthSig: devEnv.superCapacityDelegationAuthSig } + : {}), + }); + + return litActionSessionSigs; +}; + export const getInvalidLitActionSessionSigs = async ( devEnv: TinnyEnvironment, alice: TinnyPerson diff --git a/local-tests/test.ts b/local-tests/test.ts index 24afa4b0f2..b709a40eca 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -10,6 +10,7 @@ import { testUsePkpSessionSigsToExecuteJsSigning } from './tests/testUsePkpSessi import { testUsePkpSessionSigsToPkpSign } from './tests/testUsePkpSessionSigsToPkpSign'; import { testUseValidLitActionCodeGeneratedSessionSigsToPkpSign } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign'; import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning'; +import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning } from './tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning'; import { testUseEoaSessionSigsToExecuteJsSigningInParallel } from './tests/testUseEoaSessionSigsToExecuteJsSigningInParallel'; import { testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs } from './tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs'; import { testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign } from './tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign'; @@ -42,6 +43,7 @@ import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse } import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog'; import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile'; import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip'; +import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign } from './tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -89,6 +91,8 @@ import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip } from }; const litActionSessionSigsTests = { + testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign, + testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning, testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning, testUseValidLitActionCodeGeneratedSessionSigsToPkpSign, testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel, diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts index 345eebf948..f0f11326a4 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts @@ -8,14 +8,14 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; /** * Test Commands: - * ❌ NOT AVAILABLE IN CAYENNE + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning * ❌ NOT AVAILABLE IN HABANERO * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - devEnv.setUnavailable(LIT_TESTNET.MANZANO); + // devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + // devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice, [ diff --git a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts new file mode 100644 index 0000000000..8afaf6eafe --- /dev/null +++ b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts @@ -0,0 +1,81 @@ +import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; +import { log } from '@lit-protocol/misc'; +import { LitAbility } from '@lit-protocol/types'; +import { getLitActionSessionSigsUsingIpfsId } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning + * ❌ NOT AVAILABLE IN HABANERO + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning + */ +export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning = + async (devEnv: TinnyEnvironment) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigsUsingIpfsId( + devEnv, + alice, + [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ] + ); + + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.authMethodOwnedPkp.publicKey, + }, + }); + + // -- Expected output: + // { + // claims: {}, + // signatures: { + // sig: { + // r: "6d5ce6f948ff763939c204fc0f1b750fa0267ed567ed59581082d0cbf283feef", + // s: "4957ece75c60388500c4b7aa38a5fbafb7c20427db181aff7806af54c16ee145", + // recid: 1, + // signature: "0x6d5ce6f948ff763939c204fc0f1b750fa0267ed567ed59581082d0cbf283feef4957ece75c60388500c4b7aa38a5fbafb7c20427db181aff7806af54c16ee1451c", + // publicKey: "04D10D941B04491FDC99B048E2252A69137333254C482511D6CCDD401C080AF4F51BF65D9AE2413FCE066E326D7F0CED9C139DD9BA2D1C6334FD8C14CA4DD7F3D0", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // }, + // }, + // decryptions: [], + // response: undefined, + // logs: "", + // } + + // -- assertions + if (!res.signatures.sig.r) { + throw new Error(`Expected "r" in res.signatures.sig`); + } + if (!res.signatures.sig.s) { + throw new Error(`Expected "s" in res.signatures.sig`); + } + + if (!res.signatures.sig.dataSigned) { + throw new Error(`Expected "dataSigned" in res.signatures.sig`); + } + + if (!res.signatures.sig.publicKey) { + throw new Error(`Expected "publicKey" in res.signatures.sig`); + } + + log('✅ res:', res); + }; diff --git a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts new file mode 100644 index 0000000000..89b57df1dc --- /dev/null +++ b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts @@ -0,0 +1,62 @@ +import { log } from '@lit-protocol/misc'; +import { getLitActionSessionSigsUsingIpfsId } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign + * ❌ NOT AVAILABLE IN HABANERO + * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign + * + **/ +export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign = + async (devEnv: TinnyEnvironment) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigsUsingIpfsId( + devEnv, + alice + ); + + const res = await devEnv.litNodeClient.pkpSign({ + toSign: alice.loveLetter, + pubKey: alice.authMethodOwnedPkp.publicKey, + sessionSigs: litActionSessionSigs, + }); + + // -- Expected output: + // { + // r: "ab2cef959db920d56f001c3b05637ee49af4c4441f2867ea067c413594a4c87b", + // s: "4bf11e17b4bb618aa6ed75cbf0406e6babfd953c5b201da697077c5fbf5b542e", + // recid: 1, + // signature: "0xab2cef959db920d56f001c3b05637ee49af4c4441f2867ea067c413594a4c87b4bf11e17b4bb618aa6ed75cbf0406e6babfd953c5b201da697077c5fbf5b542e1c", + // publicKey: "04400AD53C2F8BA11EBC69F05D1076D5BEE4EAE668CD66BABADE2E0770F756FDEEFC2C1D20F9A698EA3FEC6E9C944FF9FAFC2DC339B8E9392AFB9CC8AE75C5E5EC", + // dataSigned: "7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4", + // } + + // -- assertions + // r, s, dataSigned, and public key should be present + if (!res.r) { + throw new Error(`Expected "r" in res`); + } + if (!res.s) { + throw new Error(`Expected "s" in res`); + } + if (!res.dataSigned) { + throw new Error(`Expected "dataSigned" in res`); + } + if (!res.publicKey) { + throw new Error(`Expected "publicKey" in res`); + } + + // signature must start with 0x + if (!res.signature.startsWith('0x')) { + throw new Error(`Expected "signature" to start with 0x`); + } + + // recid must be parseable as a number + if (isNaN(res.recid)) { + throw new Error(`Expected "recid" to be parseable as a number`); + } + + log('✅ res:', res); + }; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 0c01bad592..c4da901bfd 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2035,6 +2035,9 @@ export class LitNodeClientNodeJs curveType: LIT_CURVE.BLS, // -- custom auths + ...(params?.litActionIpfsId && { + litActionIpfsId: params.litActionIpfsId, + }), ...(params?.litActionCode && { code: params.litActionCode }), ...(params?.jsParams && { jsParams: params.jsParams }), ...(this.currentEpochNumber && { epoch: this.currentEpochNumber }), diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index ec807425c1..7e7cc29856 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -292,10 +292,12 @@ export interface JsonSignSessionKeyRequestV1 { // authSig?: AuthSig; siweMessage: string; curveType: 'BLS'; + epoch?: number; + + // custom auth params code?: string; litActionIpfsId?: string; jsParams?: any; - epoch?: number; } // [ @@ -1009,6 +1011,10 @@ export interface SignSessionKeyProp { */ resourceAbilityRequests?: LitResourceAbilityRequest[]; + /** + * The js code on ipfs + */ + litActionIpfsId?: string; /** * The js code to run on the nodes */ @@ -1776,6 +1782,7 @@ export interface SignerLike { export interface GetPkpSessionSigs extends GetSessionSigsProps { pkpPublicKey: string; authMethods: AuthMethod[]; + litActionIpfsId?: string; litActionCode?: string; jsParams?: { publicKey?: string; From c2b6473b388b700c7f2e1896d9ce59e82be72134 Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 00:06:43 +0100 Subject: [PATCH 087/263] feat: ipfs session sigs & test cases --- .../get-lit-action-session-sigs.ts | 33 ++++++++++++++++++- local-tests/test.ts | 14 ++++++-- ...validLitActionCodeToGenerateSessionSigs.ts | 2 +- ...dLitActionIpfsCodeToGenerateSessionSigs.ts | 33 +++++++++++++++++++ ...eGeneratedSessionSigsToExecuteJsSigning.ts | 1 + ...onIpfsCodeGeneratedSessionSigsToPkpSign.ts | 17 +++++++--- .../src/lib/lit-node-client-nodejs.ts | 16 +++++---- packages/types/src/lib/interfaces.ts | 6 ++-- 8 files changed, 104 insertions(+), 18 deletions(-) create mode 100644 local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts diff --git a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts index 4036a5ed05..1f7138a133 100644 --- a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts +++ b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts @@ -21,7 +21,15 @@ const INVALID_SESSION_SIG_LIT_ACTION_CODE = ` })(); `; -export const VALID_IPFS_ID = 'QmNZQXmY2VijUPfNrkC6zWykBnEniDouAeUpFi9r6aaqNz'; +/** + * https://cloudflare-ipfs.com/ipfs/QmRf5K7PVi5TWXiJdw7YYtcgpgRY6ufXGr9yYnxBLvLjDp + */ +export const VALID_IPFS_ID = 'QmRf5K7PVi5TWXiJdw7YYtcgpgRY6ufXGr9yYnxBLvLjDp'; + +/** + * https://cloudflare-ipfs.com/ipfs/QmR6WDLHvPf6yQwLcCzqJJGXEuXoJGTjdEaF5unXuPSxK9 + */ +export const INVALID_IPFS_ID = 'QmR6WDLHvPf6yQwLcCzqJJGXEuXoJGTjdEaF5unXuPSxK9'; export const getLitActionSessionSigs = async ( devEnv: TinnyEnvironment, @@ -133,3 +141,26 @@ export const getInvalidLitActionSessionSigs = async ( return litActionSessionSigs; }; + +export const getInvalidLitActionIpfsSessionSigs = async ( + devEnv: TinnyEnvironment, + alice: TinnyPerson +) => { + const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: alice.authMethodOwnedPkp.publicKey, + authMethods: [alice.authMethod], + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + ], + litActionIpfsId: INVALID_IPFS_ID, + jsParams: { + publicKey: alice.authMethodOwnedPkp.publicKey, + sigName: 'unified-auth-sig', + }, + }); + + return litActionSessionSigs; +}; diff --git a/local-tests/test.ts b/local-tests/test.ts index b709a40eca..a589f46a85 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -44,6 +44,7 @@ import { testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog } fr import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile'; import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip'; import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign } from './tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign'; +import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -91,8 +92,6 @@ import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign } from './te }; const litActionSessionSigsTests = { - testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign, - testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning, testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning, testUseValidLitActionCodeGeneratedSessionSigsToPkpSign, testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel, @@ -103,6 +102,16 @@ import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign } from './te testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString, testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile, testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip, + + // -- invalid cases + testUseInvalidLitActionIpfsCodeToGenerateSessionSigs, + }; + + const litActionIpfsIdSessionSigsTests = { + testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign, + testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning, + + // -- invalid cases testUseInvalidLitActionCodeToGenerateSessionSigs, }; @@ -123,6 +132,7 @@ import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign } from './te ...eoaSessionSigsTests, ...pkpSessionSigsTests, ...litActionSessionSigsTests, + ...litActionIpfsIdSessionSigsTests, ...capacityDelegationTests, }, devEnv, diff --git a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts index 791b64047e..9fa7098585 100644 --- a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts +++ b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts @@ -1,4 +1,3 @@ -import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; import { getInvalidLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; @@ -20,6 +19,7 @@ export const testUseInvalidLitActionCodeToGenerateSessionSigs = async ( try { await getInvalidLitActionSessionSigs(devEnv, alice); } catch (e: any) { + console.log('❌ This error is expected', e); if ( e.message === 'There was an error getting the signing shares from the nodes' diff --git a/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts new file mode 100644 index 0000000000..174ca5f137 --- /dev/null +++ b/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts @@ -0,0 +1,33 @@ +import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { getInvalidLitActionIpfsSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testUseInvalidLitActionIpfsCodeToGenerateSessionSigs + * ❌ NOT AVAILABLE IN MANZANO + * ✅ NETWORK=localchain yarn test:local --filter=testUseInvalidLitActionIpfsCodeToGenerateSessionSigs + */ +export const testUseInvalidLitActionIpfsCodeToGenerateSessionSigs = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + try { + await getInvalidLitActionIpfsSessionSigs(devEnv, alice); + } catch (e: any) { + console.log('❌ THIS IS EXPECTED: ', e); + + if ( + e.message === + 'There was an error getting the signing shares from the nodes.' + ) { + console.log( + '✅ testUseInvalidLitActionIpfsCodeToGenerateSessionSigs is expected to have an error' + ); + } else { + throw e; + } + } +}; diff --git a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts index 8afaf6eafe..ef8516f5ad 100644 --- a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts +++ b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning.ts @@ -42,6 +42,7 @@ export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToExecuteJsSigning publicKey: alice.authMethodOwnedPkp.publicKey, }, }); + console.log('✅ res:', res); // -- Expected output: // { diff --git a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts index 89b57df1dc..2658da354d 100644 --- a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts @@ -12,10 +12,17 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign = async (devEnv: TinnyEnvironment) => { const alice = await devEnv.createRandomPerson(); - const litActionSessionSigs = await getLitActionSessionSigsUsingIpfsId( - devEnv, - alice - ); + let litActionSessionSigs; + + try { + litActionSessionSigs = await getLitActionSessionSigsUsingIpfsId( + devEnv, + alice + ); + } catch (e: any) { + console.log('❌ This error is NOT expected:', e); + throw new Error(e); + } const res = await devEnv.litNodeClient.pkpSign({ toSign: alice.loveLetter, @@ -23,6 +30,8 @@ export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign = sessionSigs: litActionSessionSigs, }); + console.log("✅ res:", res); + // -- Expected output: // { // r: "ab2cef959db920d56f001c3b05637ee49af4c4441f2867ea067c413594a4c87b", diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index c4da901bfd..a68df33d7d 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -335,7 +335,7 @@ export class LitNodeClientNodeJs nonce, resourceAbilityRequests, litActionCode, - ipfsId, + litActionIpfsId, jsParams, sessionKey, }: GetWalletSigProps): Promise => { @@ -383,7 +383,7 @@ export class LitNodeClientNodeJs // for lit action custom auth ...(litActionCode && { litActionCode }), - ...(ipfsId && { ipfsId }), + ...(litActionIpfsId && { litActionIpfsId }), ...(jsParams && { jsParams }), }; @@ -2350,7 +2350,9 @@ const resourceAbilityRequests = [ // -- optional fields ...(params.litActionCode && { litActionCode: params.litActionCode }), - ...(params.ipfsId && { ipfsId: params.ipfsId }), + ...(params.litActionIpfsId && { + litActionIpfsId: params.litActionIpfsId, + }), ...(params.jsParams && { jsParams: params.jsParams }), }); @@ -2498,9 +2500,9 @@ const resourceAbilityRequests = [ } // lit action code and ipfs id cannot exist at the same time - if (props.litActionCode && props.ipfsId) { + if (props.litActionCode && props.litActionIpfsId) { throw new Error( - '[getPkpSessionSigs/callback]litActionCode and ipfsId cannot exist at the same time' + '[getPkpSessionSigs/callback]litActionCode and litActionIpfsId cannot exist at the same time' ); } @@ -2518,7 +2520,9 @@ const resourceAbilityRequests = [ // -- optional fields ...(props.litActionCode && { litActionCode: props.litActionCode }), - ...(props.ipfsId && { ipfsId: props.ipfsId }), + ...(props.litActionIpfsId && { + litActionIpfsId: props.litActionIpfsId, + }), ...(props.jsParams && { jsParams: props.jsParams }), }); diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 7e7cc29856..ef8f605ca3 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -93,7 +93,7 @@ export interface AuthCallbackParams { resourceAbilityRequests?: LitResourceAbilityRequest[]; litActionCode?: string; - ipfsId?: string; + litActionIpfsId?: string; jsParams?: any; } @@ -1754,7 +1754,7 @@ export interface CapacityCreditsRes { export interface LitCustomAuth { litActionCode?: string; - ipfsId?: string; + litActionIpfsId?: string; jsParams?: { publicKey?: string; sigName?: string; @@ -1782,8 +1782,6 @@ export interface SignerLike { export interface GetPkpSessionSigs extends GetSessionSigsProps { pkpPublicKey: string; authMethods: AuthMethod[]; - litActionIpfsId?: string; - litActionCode?: string; jsParams?: { publicKey?: string; sigName?: string; From a90298ee9c2c7618f3157e35a22fddf8d06958d3 Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 00:08:43 +0100 Subject: [PATCH 088/263] feat: turn on testings on cayenne! --- .../testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts | 2 -- ...estDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts | 2 -- .../testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts | 2 -- ...elegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts | 2 -- ...yDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts | 2 -- ...cityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts | 2 -- ...pacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts | 1 - .../tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts | 1 - ...alidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts | 1 - ...idLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts | 1 - ...ValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts | 1 - ...alidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts | 1 - ...ctionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts | 1 - ...lidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts | 1 - ...dLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts | 1 - ...eValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts | 2 +- ...ctionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts | 1 - .../testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts | 1 - ...estUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts | 2 +- 19 files changed, 2 insertions(+), 25 deletions(-) diff --git a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts index f8de798aa5..d1fe134e45 100644 --- a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts +++ b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs.ts @@ -26,8 +26,6 @@ import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; export const testDelegatingCapacityCreditsNFTToAnotherPkpToExecuteJs = async ( devEnv: TinnyEnvironment ) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts index b3b7bc0a15..46ba42a016 100644 --- a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts +++ b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs.ts @@ -19,8 +19,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts index 00b0f4984b..ac5f308db0 100644 --- a/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts +++ b/local-tests/tests/testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign.ts @@ -20,8 +20,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testDelegatingCapacityCreditsNFTToAnotherWalletToPkpSign = async ( devEnv: TinnyEnvironment ) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts index 16c45d1590..1d85764098 100644 --- a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs.ts @@ -19,8 +19,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToExecuteJs = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts index 4abccce37e..fd7b22c0f7 100644 --- a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign.ts @@ -19,8 +19,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts index f98f9e7592..d552915556 100644 --- a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs.ts @@ -20,8 +20,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToExecuteJs = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); - const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts index c319e809e5..11f0c05550 100644 --- a/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts +++ b/local-tests/tests/testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign.ts @@ -20,7 +20,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testUseCapacityDelegationAuthSigWithUnspecifiedDelegateesToPkpSign = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); const alice = await devEnv.createRandomPerson(); const bob = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts index 9fa7098585..b188da7393 100644 --- a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts +++ b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts @@ -11,7 +11,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testUseInvalidLitActionCodeToGenerateSessionSigs = async ( devEnv: TinnyEnvironment ) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts index 30d4da72e8..e0ca8deb25 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts @@ -16,7 +16,6 @@ import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit- */ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts index fde1ce5e39..34c27fde7c 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts @@ -16,7 +16,6 @@ import { log } from '@lit-protocol/misc'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts index 1e2576865d..78aeb6c844 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts @@ -15,7 +15,6 @@ import { log } from '@lit-protocol/misc'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts index 0606cac29b..daa4d78d24 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys.ts @@ -21,7 +21,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimKeys = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts index 4244e3be5e..1c5c77916f 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys.ts @@ -19,7 +19,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsClaimMultipleKeys = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts index c358f22d61..86d6f93371 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog.ts @@ -13,7 +13,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsConsoleLog = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts index 5c968800f1..e61e3f78a7 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse.ts @@ -11,7 +11,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsJsonResponse = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts index f0f11326a4..b611e71804 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning.ts @@ -14,7 +14,7 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning = async (devEnv: TinnyEnvironment) => { - // devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + // // devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts index fbe8766817..47f23fe038 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts @@ -12,7 +12,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; */ export const testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel = async (devEnv: TinnyEnvironment) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts index 9ec3c85bf9..042056f072 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts @@ -16,7 +16,6 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testUseValidLitActionCodeGeneratedSessionSigsToPkpSign = async ( devEnv: TinnyEnvironment ) => { - devEnv.setUnavailable(LIT_TESTNET.CAYENNE); devEnv.setUnavailable(LIT_TESTNET.MANZANO); const alice = await devEnv.createRandomPerson(); diff --git a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts index 2658da354d..93171186a8 100644 --- a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts @@ -30,7 +30,7 @@ export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign = sessionSigs: litActionSessionSigs, }); - console.log("✅ res:", res); + console.log('✅ res:', res); // -- Expected output: // { From 6b27dc135deab5cfe0b3b7cc1e073e99ea146837 Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 00:23:01 +0100 Subject: [PATCH 089/263] feat: update cayenne tests --- .../session-sigs/get-lit-action-session-sigs.ts | 4 ++-- local-tests/test.ts | 14 -------------- ...nvalidLitActionIpfsCodeToGenerateSessionSigs.ts | 5 +---- ...tActionIpfsCodeGeneratedSessionSigsToPkpSign.ts | 2 +- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts index 1f7138a133..baf05b96ce 100644 --- a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts +++ b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts @@ -27,9 +27,9 @@ const INVALID_SESSION_SIG_LIT_ACTION_CODE = ` export const VALID_IPFS_ID = 'QmRf5K7PVi5TWXiJdw7YYtcgpgRY6ufXGr9yYnxBLvLjDp'; /** - * https://cloudflare-ipfs.com/ipfs/QmR6WDLHvPf6yQwLcCzqJJGXEuXoJGTjdEaF5unXuPSxK9 + * https://cloudflare-ipfs.com/ipfs/QmeUByesskboEkLLcE9Hd3bWFZT5Xt53RSauMNTJSVhfqm */ -export const INVALID_IPFS_ID = 'QmR6WDLHvPf6yQwLcCzqJJGXEuXoJGTjdEaF5unXuPSxK9'; +export const INVALID_IPFS_ID = 'QmeUByesskboEkLLcE9Hd3bWFZT5Xt53RSauMNTJSVhfqm'; export const getLitActionSessionSigs = async ( devEnv: TinnyEnvironment, diff --git a/local-tests/test.ts b/local-tests/test.ts index a589f46a85..ed1277049e 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -51,20 +51,6 @@ import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/te const devEnv = new TinnyEnvironment(); await devEnv.init(); - if (LIT_TESTNET.LOCALCHAIN) { - // set global executeJs endpoint version for all tests. - devEnv.setGlobalExecuteJsVersion( - LIT_TESTNET.LOCALCHAIN, - LIT_ENDPOINT_VERSION.V1 - ); - - // set global pkpSign endpoint version for all tests. - devEnv.setGlobalPkpSignVersion( - LIT_TESTNET.LOCALCHAIN, - LIT_ENDPOINT_VERSION.V1 - ); - } - const eoaSessionSigsTests = { testUseEoaSessionSigsToExecuteJsSigning, testUseEoaSessionSigsToPkpSign, diff --git a/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts index 174ca5f137..4243a1cf90 100644 --- a/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts +++ b/local-tests/tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs.ts @@ -19,10 +19,7 @@ export const testUseInvalidLitActionIpfsCodeToGenerateSessionSigs = async ( } catch (e: any) { console.log('❌ THIS IS EXPECTED: ', e); - if ( - e.message === - 'There was an error getting the signing shares from the nodes.' - ) { + if (e.message === 'An error related to validation has occured.') { console.log( '✅ testUseInvalidLitActionIpfsCodeToGenerateSessionSigs is expected to have an error' ); diff --git a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts index 93171186a8..1ed4405d4f 100644 --- a/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign.ts @@ -6,7 +6,7 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; * Test Commands: * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign * ❌ NOT AVAILABLE IN HABANERO - * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign + * ❌ NETWORK=localchain yarn test:local --filter=testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign * **/ export const testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign = From 32c739879db09b697bfd061d1f3e323c3d680c5c Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 00:26:25 +0100 Subject: [PATCH 090/263] feat: remove version override --- packages/core/src/lib/endpoint-version.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/core/src/lib/endpoint-version.ts b/packages/core/src/lib/endpoint-version.ts index f2d1381b79..41bbb31c07 100644 --- a/packages/core/src/lib/endpoint-version.ts +++ b/packages/core/src/lib/endpoint-version.ts @@ -21,16 +21,7 @@ export const composeLitUrl = (params: { throw new Error(`[composeLitUrl] Invalid URL: "${params.url}"`); } - let versionOverride: string | undefined = undefined; - - // Get the version override for a particular endpoint - // FIXME: We will remove this completly once v0.1 is deployed to all public networks - if (isNode()) { - versionOverride = process.env[`${params.endpoint.envName}`] || undefined; - } - - // Use the overridden version if it exists, otherwise use the default - const version = versionOverride || params.endpoint.version; + const version = params.endpoint.version; return `${params.url}${params.endpoint.path}${version}`; }; From a98760c89abe7f0515f0eafc26d63a8ca95f4def Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 01:10:53 +0100 Subject: [PATCH 091/263] fix: jsdocs --- .../tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts | 2 +- ...idLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts | 2 +- ...ctionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts | 2 +- .../testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts index b188da7393..537ad25408 100644 --- a/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts +++ b/local-tests/tests/testUseInvalidLitActionCodeToGenerateSessionSigs.ts @@ -4,7 +4,7 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; /** * Test Commands: - * ❌ NOT AVAILABLE IN CAYENNE + * ✅ NETWORK=cayenne yarn test:local --filter=testUseInvalidLitActionCodeToGenerateSessionSigs * ❌ NOT AVAILABLE IN MANZANO * ✅ NETWORK=localchain yarn test:local --filter=testUseInvalidLitActionCodeToGenerateSessionSigs */ diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts index 34c27fde7c..6828e8b596 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString.ts @@ -9,7 +9,7 @@ import { log } from '@lit-protocol/misc'; /** * Test Commands: - * ❌ NOT AVAILABLE IN CAYENNE + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString * ❌ NOT AVAILABLE IN MANZANO * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptString * diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts index 47f23fe038..2249b5f01a 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel.ts @@ -6,7 +6,7 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; /** * Test Commands: - * ❌ Not available in Cayenne + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel * ❌ Not available in Habanero * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigningInParallel */ diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts index 042056f072..2a46a2821e 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToPkpSign.ts @@ -8,7 +8,7 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; /** * Test Commands: - * ❌ NOT AVAILABLE IN CAYENNE + * ✅ NETWORK=cayenne yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToPkpSign * ❌ NOT AVAILABLE IN HABANERO * ✅ NETWORK=localchain yarn test:local --filter=testUseValidLitActionCodeGeneratedSessionSigsToPkpSign * From a4dd28ffc4386d64e2fbc6de19ab08e0ca7bc82d Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 02:33:57 +0100 Subject: [PATCH 092/263] fix: browser global undefined see #416 #452 --- packages/auth-browser/src/lib/chains/eth.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/auth-browser/src/lib/chains/eth.ts b/packages/auth-browser/src/lib/chains/eth.ts index 3e66c6f79f..67946c7879 100644 --- a/packages/auth-browser/src/lib/chains/eth.ts +++ b/packages/auth-browser/src/lib/chains/eth.ts @@ -42,10 +42,6 @@ import { } from '@lit-protocol/misc'; import { getStorageItem } from '@lit-protocol/misc-browser'; -if (global && typeof global.Buffer === 'undefined') { - global.Buffer = BufferPolyfill; -} - if (globalThis && typeof globalThis.Buffer === 'undefined') { globalThis.Buffer = BufferPolyfill; } From 01274c2cb961e154b3b95719397492a814d001bd Mon Sep 17 00:00:00 2001 From: Anson Date: Sat, 4 May 2024 03:13:14 +0100 Subject: [PATCH 093/263] feat: add tslib as dependency --- packages/auth-helpers/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 300f3f80c2..0212f2312f 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -17,8 +17,8 @@ "access": "public", "directory": "../../dist/packages/auth-helpers" }, - "peerDependencies": { - "tslib": "^2.3.0" + "dependencies": { + "tslib": "2.6.0" }, "gitHead": "0d7334c2c55f448e91fe32f29edc5db8f5e09e4b", "tags": [ @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-alpha.11", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} From 635ec8da948103f3ce14271ccfc00393bc9e02a2 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 7 May 2024 23:48:19 +0100 Subject: [PATCH 094/263] feat(test): remove `envName` override --- packages/auth-browser/src/lib/auth-browser.ts | 3 +++ packages/constants/src/lib/constants/endpoints.ts | 8 -------- .../src/lib/lit-node-client-nodejs.ts | 1 - packages/types/src/lib/interfaces.ts | 1 - 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/auth-browser/src/lib/auth-browser.ts b/packages/auth-browser/src/lib/auth-browser.ts index 8f65b76158..3004dfdf08 100644 --- a/packages/auth-browser/src/lib/auth-browser.ts +++ b/packages/auth-browser/src/lib/auth-browser.ts @@ -1,3 +1,6 @@ +/** + * FIXME: SessionSigs are only supported for EVM chains at the moment. This will be expanded to other chains in the future. + */ import { ALL_LIT_CHAINS, LIT_ERROR, VMTYPE } from '@lit-protocol/constants'; import { AuthCallbackParams, AuthSig } from '@lit-protocol/types'; diff --git a/packages/constants/src/lib/constants/endpoints.ts b/packages/constants/src/lib/constants/endpoints.ts index fc97194bad..be29b214d6 100644 --- a/packages/constants/src/lib/constants/endpoints.ts +++ b/packages/constants/src/lib/constants/endpoints.ts @@ -7,41 +7,33 @@ export const LIT_ENDPOINT = { HANDSHAKE: { path: '/web/handshake', version: LIT_ENDPOINT_VERSION.V0, - envName: 'HANDSHAKE', }, SIGN_SESSION_KEY: { path: '/web/sign_session_key', version: LIT_ENDPOINT_VERSION.V1, - envName: 'SIGN_SESSION_KEY', }, EXECUTE_JS: { path: '/web/execute', version: LIT_ENDPOINT_VERSION.V1, - envName: 'EXECUTE_JS', }, PKP_SIGN: { path: '/web/pkp/sign', version: LIT_ENDPOINT_VERSION.V1, - envName: 'PKP_SIGN', }, PKP_CLAIM: { path: '/web/pkp/claim', version: LIT_ENDPOINT_VERSION.V0, - envName: 'PKP_CLAIM', }, SIGN_ACCS: { path: '/web/signing/access_control_condition', version: LIT_ENDPOINT_VERSION.V0, - envName: 'SIGN_ACCS', }, ENCRYPTION_SIGN: { path: '/web/encryption/sign', version: LIT_ENDPOINT_VERSION.V0, - envName: 'ENCRYPTION_SIGN', }, SIGN_ECDSA: { path: '/web/signing/signConditionEcdsa', version: LIT_ENDPOINT_VERSION.V0, - envName: 'SIGN_ECDSA', }, }; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index a68df33d7d..7508415f22 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2468,7 +2468,6 @@ const resourceAbilityRequests = [ }; /** -<<<<<<<<< Temporary merge branch 1 * Retrieves the PKP sessionSigs. * * @param params - The parameters for retrieving the PKP sessionSigs. diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index ef8f605ca3..590b90c76a 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1764,7 +1764,6 @@ export interface LitCustomAuth { export interface LitEndpoint { path: string; version: string; - envName: string; } /** From edd615e9f34da29cf0ef64314f3f5435a8665e0e Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 7 May 2024 23:59:06 +0100 Subject: [PATCH 095/263] chore: remove v0 stuff --- local-tests/setup/tinny-environment.ts | 28 -------------------------- 1 file changed, 28 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 1e44718275..f0eb8f276a 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -268,34 +268,6 @@ export class TinnyEnvironment { return await this.createNewPerson('Alice'); } - /** - * Sets the global execute JS version for a specific network. - * @param network - The network for which to set the execute JS version. - * @param version - The execute JS version to set. - */ - setGlobalExecuteJsVersion = ( - network: LIT_TESTNET, - version: LIT_ENDPOINT_VERSION - ) => { - if (this.processEnvs.NETWORK === network) { - process.env[LIT_ENDPOINT.EXECUTE_JS.envName] = version; - } - }; - - /** - * Sets the global PKP sign version for the specified network. - * @param network - The network for which to set the PKP sign version. - * @param version - The PKP sign version to set. - */ - setGlobalPkpSignVersion = ( - network: LIT_TESTNET, - version: LIT_ENDPOINT_VERSION - ) => { - if (this.processEnvs.NETWORK === network) { - process.env[LIT_ENDPOINT.PKP_SIGN.envName] = version; - } - }; - setUnavailable = (network: LIT_TESTNET) => { if (this.processEnvs.NETWORK === network) { throw new Error('LIT_IGNORE_TEST'); From 869988d0e88de9eeb2723d443c0887e4333c87fa Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 7 May 2024 23:59:21 +0100 Subject: [PATCH 096/263] docs: add JsDocs to `checkAndSignAuthMessage` --- packages/auth-browser/src/lib/auth-browser.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/auth-browser/src/lib/auth-browser.ts b/packages/auth-browser/src/lib/auth-browser.ts index 3004dfdf08..76ba8e3f5e 100644 --- a/packages/auth-browser/src/lib/auth-browser.ts +++ b/packages/auth-browser/src/lib/auth-browser.ts @@ -11,6 +11,11 @@ import { checkAndSignEVMAuthMessage } from './chains/eth'; import { checkAndSignSolAuthMessage } from './chains/sol'; /** + * SUPPORTED CHAINS: EVM, Solana, Cosmos + * + * !! NOTE !! + * This function is purely used for crafting the authSig for access control conditions, encryption & decryption. For SessionSigs, you won't be able to use this + * to add resource ability requests in the SIWE message. Instead, you should provide your own signer to the authNeededCallback parameter for the getSessionSigs method. * * Check for an existing cryptographic authentication signature and create one of it does not exist. This is used to prove ownership of a given crypto wallet address to the Lit nodes. The result is stored in LocalStorage so the user doesn't have to sign every time they perform an operation. * From 7c3fc4e9d03cf032800b05857cf77e2460a7c61a Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 00:00:04 +0100 Subject: [PATCH 097/263] feat: make `authNeededCallback` a required parameter, but we need to create a common interface, because GetPkpSessionSigs uses it too --- packages/types/src/lib/interfaces.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 590b90c76a..537fb3a87b 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1038,8 +1038,7 @@ export interface SignSessionKeyResponse { export interface GetSignSessionKeySharesProp { body: SessionRequestBody; } - -export interface GetSessionSigsProps extends LitCustomAuth { +export interface CommonGetSessionSigsProps { pkpPublicKey?: string; // When this session signature will expire. The user will have to reauthenticate after this time using whatever auth method you set up. This means you will have to call this signSessionKey function again to get a new session signature. This is a RFC3339 timestamp. The default is 24 hours from now. @@ -1070,12 +1069,6 @@ export interface GetSessionSigsProps extends LitCustomAuth { * If you want to ask Metamask to try and switch the user's chain, you may pass true here. This will only work if the user is using Metamask. If the user is not using Metamask, then this will be ignored. */ switchChain?: boolean; - - /** - * This is a callback that will be called if the user needs to authenticate using a PKP. For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. This callback should use the LitNodeClient.signSessionKey function to get a session signature for the user from their PKP. If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. - */ - authNeededCallback?: AuthCallback; - /** * The serialized session key pair to sign. * If not provided, a session key pair will be fetched from localStorge or generated. @@ -1095,6 +1088,15 @@ export interface GetSessionSigsProps extends LitCustomAuth { */ capabilityAuthSigs?: AuthSig[]; } + +export interface GetSessionSigsProps + extends CommonGetSessionSigsProps, + LitCustomAuth { + /** + * This is a callback that will be called if the user needs to authenticate using a PKP. For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. This callback should use the LitNodeClient.signSessionKey function to get a session signature for the user from their PKP. If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. + */ + authNeededCallback: AuthCallback; +} export type AuthCallback = (params: AuthCallbackParams) => Promise; /** @@ -1778,7 +1780,9 @@ export interface SignerLike { getAddress: () => Promise; } -export interface GetPkpSessionSigs extends GetSessionSigsProps { +export interface GetPkpSessionSigs + extends CommonGetSessionSigsProps, + LitCustomAuth { pkpPublicKey: string; authMethods: AuthMethod[]; jsParams?: { From 4add9446359bb27a0af033f4e54b6af772713d73 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 7 May 2024 17:58:52 -0400 Subject: [PATCH 098/263] ref: add execption throw if event topics are not found --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index dc3b4c56dc..1487ee7d80 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1065,6 +1065,12 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope let tokenId; + if (!events[0].topics || events[0].topics.length < 1) { + throw new Error( + `No topics found in events, can not derive pkp information. Transaction hash: ${receipt.transactionHash} If you are using your own contracts please use ethers directly` + ); + } + tokenId = events[0].topics[1]; console.warn('tokenId:', tokenId); From cab0e0ae36ca39f767a1dcec04a091398b45d529 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 01:12:48 +0100 Subject: [PATCH 099/263] chore: hide useless logs --- local-tests/setup/tinny-environment.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index f0eb8f276a..4f20cea839 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -122,21 +122,21 @@ export class TinnyEnvironment { if (index !== -1) { // If an available key is found this.processEnvs.KEY_IN_USE[index] = true; // Mark the key as in use - console.log('[𐬺🧪 Tinny Environment𐬺] 🔑 Selected key at index', index); // Log a message indicating that we have selected a key + // console.log('[𐬺🧪 Tinny Environment𐬺] 🔑 Selected key at index', index); // Log a message indicating that we have selected a key // Set a timer to automatically release the key after 10 seconds setTimeout(() => { this.releasePrivateKey(index); - console.log( - '[𐬺🧪 Tinny Environment𐬺] 🔓 Automatically released key at index', - index, - `after ${this.processEnvs.TIME_TO_RELEASE_KEY / 10000} seconds` - ); + // console.log( + // '[𐬺🧪 Tinny Environment𐬺] 🔓 Automatically released key at index', + // index, + // `after ${this.processEnvs.TIME_TO_RELEASE_KEY / 10000} seconds` + // ); }, this.processEnvs.TIME_TO_RELEASE_KEY); return { privateKey: this.processEnvs.PRIVATE_KEYS[index], index }; // Return the key and its index } else { - console.log('[𐬺🧪 Tinny Environment𐬺] No available keys. Waiting...'); // Log a message indicating that we are waiting + // console.log('[𐬺🧪 Tinny Environment𐬺] No available keys. Waiting...'); // Log a message indicating that we are waiting // Wait for the specified interval before checking again await new Promise((resolve) => setTimeout(resolve, this.processEnvs.WAIT_FOR_KEY_INTERVAL) @@ -151,9 +151,9 @@ export class TinnyEnvironment { */ releasePrivateKey(index: number) { this.processEnvs.KEY_IN_USE[index] = false; - console.log( - `[𐬺🧪 Tinny Environment𐬺] 🪽 Released key at index ${index}. Thank you for your service!` - ); + // console.log( + // `[𐬺🧪 Tinny Environment𐬺] 🪽 Released key at index ${index}. Thank you for your service!` + // ); } /** From 9c6d07f7ba2654fe1f3bc5ea5e3c1d35961bb3c0 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 01:13:17 +0100 Subject: [PATCH 100/263] feat: improve keyword filtering, so I can go --filter=Encrypt and will find all tests with `Encrypt` keyword --- local-tests/setup/tinny-operations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-operations.ts b/local-tests/setup/tinny-operations.ts index 6bd14ab41b..4a0156a9f4 100644 --- a/local-tests/setup/tinny-operations.ts +++ b/local-tests/setup/tinny-operations.ts @@ -121,7 +121,7 @@ export const runTestsParallel = async ({ }): Promise => { const filters = getFiltersFlag(); const testsToRun = Object.entries(tests).filter( - ([testName]) => filters.length === 0 || filters.includes(testName) + ([testName]) => filters.length === 0 || filters.some(filter => testName.includes(filter)) ); const testPromises = testsToRun.map( From 4b2f565dbb2b653cdd3eb7ef7c69ce8c9060b767 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 01:15:52 +0100 Subject: [PATCH 101/263] feat: update tests to remove auth material for encryption because it's completely client side --- .../tests/testUseEoaSessionSigsToEncryptDecryptFile.ts | 4 ---- .../tests/testUseEoaSessionSigsToEncryptDecryptString.ts | 4 ---- .../tests/testUseEoaSessionSigsToEncryptDecryptZip.ts | 6 ------ .../tests/testUsePkpSessionSigsToEncryptDecryptFile.ts | 4 ---- .../tests/testUsePkpSessionSigsToEncryptDecryptString.ts | 4 ---- .../tests/testUsePkpSessionSigsToEncryptDecryptZip.ts | 4 ---- ...LitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts | 4 ---- ...dLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts | 4 ---- 8 files changed, 34 deletions(-) diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts index 3f2ebfe90c..c51c09de5d 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptFile.ts @@ -25,13 +25,9 @@ export const testUseEoaSessionSigsToEncryptDecryptFile = async ( userAddress: alice.wallet.address, }); - const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.encryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: eoaSessionSigs, dataToEncrypt: 'Hello world', }, devEnv.litNodeClient as unknown as ILitNodeClient diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts index 5b63ca962c..53fa1a4244 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptString.ts @@ -21,13 +21,9 @@ export const testUseEoaSessionSigsToEncryptDecryptString = async ( userAddress: alice.wallet.address, }); - const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.encryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: eoaSessionSigs, dataToEncrypt: 'Hello world', }, devEnv.litNodeClient as unknown as ILitNodeClient diff --git a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts index 2e3fa881b8..208ee74751 100644 --- a/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseEoaSessionSigsToEncryptDecryptZip.ts @@ -23,13 +23,9 @@ export const testUseEoaSessionSigsToEncryptDecryptZip = async ( userAddress: alice.wallet.address, }); - const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.zipAndEncryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: eoaSessionSigs, dataToEncrypt: message, }, devEnv.litNodeClient as unknown as ILitNodeClient @@ -37,8 +33,6 @@ export const testUseEoaSessionSigsToEncryptDecryptZip = async ( log('encryptRes:', encryptRes); - // await 5 seconds for the encryption to be mined - // -- Expected output: // { // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts index fbe9af30ef..75db87c7bf 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptFile.ts @@ -26,13 +26,9 @@ export const testUsePkpSessionSigsToEncryptDecryptFile = async ( userAddress: alice.authMethodOwnedPkp.ethAddress, }); - const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.encryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: pkpSessionSigs, dataToEncrypt: 'Hello world', }, devEnv.litNodeClient as unknown as ILitNodeClient diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts index a04c8a682c..01d4994875 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptString.ts @@ -21,13 +21,9 @@ export const testUsePkpSessionSigsToEncryptDecryptString = async ( userAddress: alice.authMethodOwnedPkp.ethAddress, }); - const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.encryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: pkpSessionSigs, dataToEncrypt: 'Hello world', }, devEnv.litNodeClient as unknown as ILitNodeClient diff --git a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts index 4554d54ef2..0e926bebcd 100644 --- a/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUsePkpSessionSigsToEncryptDecryptZip.ts @@ -24,13 +24,9 @@ export const testUsePkpSessionSigsToEncryptDecryptZip = async ( userAddress: alice.authMethodOwnedPkp.ethAddress, }); - const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.zipAndEncryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: pkpSessionSigs, dataToEncrypt: message, }, devEnv.litNodeClient as unknown as ILitNodeClient diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts index e0ca8deb25..19a95e0678 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile.ts @@ -28,13 +28,9 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile = userAddress: alice.authMethodOwnedPkp.ethAddress, }); - const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.encryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: litActionSessionSigs, dataToEncrypt: 'Hello world', }, devEnv.litNodeClient as unknown as ILitNodeClient diff --git a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts index 78aeb6c844..332615d3c1 100644 --- a/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts +++ b/local-tests/tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip.ts @@ -25,13 +25,9 @@ export const testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip = userAddress: alice.authMethodOwnedPkp.ethAddress, }); - const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); - const encryptRes = await LitJsSdk.zipAndEncryptString( { accessControlConditions: accs, - chain: 'ethereum', - sessionSigs: litActionSessionSigs, dataToEncrypt: message, }, devEnv.litNodeClient as unknown as ILitNodeClient From 606e3d561ed8db87516bb2224d73c757fe185377 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 01:16:54 +0100 Subject: [PATCH 102/263] feat: add authSig back to encrypt helper functions --- packages/auth-browser/src/lib/auth-browser.ts | 2 +- packages/encryption/src/lib/encryption.ts | 15 +-- .../encryption/src/lib/params-validators.ts | 93 +++++++++++------- .../src/lib/lit-node-client-nodejs.ts | 16 +++- packages/types/src/lib/ILitNodeClient.ts | 4 +- packages/types/src/lib/interfaces.ts | 95 +++++++++++++------ 6 files changed, 150 insertions(+), 75 deletions(-) diff --git a/packages/auth-browser/src/lib/auth-browser.ts b/packages/auth-browser/src/lib/auth-browser.ts index 76ba8e3f5e..a6d8bc6885 100644 --- a/packages/auth-browser/src/lib/auth-browser.ts +++ b/packages/auth-browser/src/lib/auth-browser.ts @@ -14,7 +14,7 @@ import { checkAndSignSolAuthMessage } from './chains/sol'; * SUPPORTED CHAINS: EVM, Solana, Cosmos * * !! NOTE !! - * This function is purely used for crafting the authSig for access control conditions, encryption & decryption. For SessionSigs, you won't be able to use this + * This function is purely used for crafting the authSig for access control conditions & decryption. For SessionSigs, you won't be able to use this * to add resource ability requests in the SIWE message. Instead, you should provide your own signer to the authNeededCallback parameter for the getSessionSigs method. * * Check for an existing cryptographic authentication signature and create one of it does not exist. This is used to prove ownership of a given crypto wallet address to the Lit nodes. The result is stored in LocalStorage so the user doesn't have to sign every time they perform an operation. diff --git a/packages/encryption/src/lib/encryption.ts b/packages/encryption/src/lib/encryption.ts index 2fa80a33af..e0822285eb 100644 --- a/packages/encryption/src/lib/encryption.ts +++ b/packages/encryption/src/lib/encryption.ts @@ -10,7 +10,6 @@ import { DecryptZipFileWithMetadataProps, EncryptFileAndZipWithMetadataProps, EncryptFileRequest, - EncryptRequestBase, EncryptResponse, EncryptStringRequest, EncryptZipRequest, @@ -186,6 +185,11 @@ export async function decryptFromJson( * Encrypt a string. This is used to encrypt any string that is to be locked via the Lit Protocol. * * @param { EncryptStringRequest } params - The params required to encrypt a string + * @param params.dataToEncrypt - (optional) The string to encrypt + * @param params.accessControlConditions - (optional) The access control conditions + * @param params.evmContractConditions - (optional) The EVM contract conditions + * @param params.solRpcConditions - (optional) The Solana RPC conditions + * @param params.unifiedAccessControlConditions - The unified access control conditions * @param { ILitNodeClient } litNodeClient - The Lit Node Client * * @returns { Promise } - The encrypted string and the hash of the string @@ -280,7 +284,7 @@ export const zipAndEncryptString = async ( zip.file('string.txt', params.dataToEncrypt); - return encryptZip({ ...params, zip }, litNodeClient); + return encryptZip({ zip, ...params }, litNodeClient); }; /** @@ -288,7 +292,7 @@ export const zipAndEncryptString = async ( * Zip and encrypt multiple files. * * @param { Array } files - The files to encrypt - * @param { EncryptRequestBase } paramsBase - The params required to encrypt a file + * @param { DecryptRequestBase } paramsBase - The params required to encrypt a file * @param { ILitNodeClient } litNodeClient - The Lit Node Client * * @returns { Promise } - The encrypted file and the hash of the file @@ -296,7 +300,6 @@ export const zipAndEncryptString = async ( */ export const zipAndEncryptFiles = async ( files: File[], - paramsBase: EncryptRequestBase, litNodeClient: ILitNodeClient ): Promise => { // let's zip em @@ -339,7 +342,7 @@ export const zipAndEncryptFiles = async ( folder.file(files[i].name, files[i]); } - return encryptZip({ ...paramsBase, zip }, litNodeClient); + return encryptZip({ zip }, litNodeClient); }; /** @@ -388,6 +391,7 @@ export const decryptToZip = async ( * Encrypt a zip file created with JSZip. * * @param { EncryptZipRequest } params - The params required to encrypt a zip + * @param param.zip - The zip file to encrypt * @param { ILitNodeClient } litNodeClient - The Lit Node Client * * @returns { Promise } - The encrypted zip file and the hash of the zip file @@ -422,7 +426,6 @@ export const encryptZip = async ( // to download the encrypted zip file for testing, uncomment this // saveAs(encryptedZipBlob, 'encrypted.bin') - return litNodeClient.encrypt({ ...params, dataToEncrypt: new Uint8Array(zipBlobArrayBuffer), diff --git a/packages/encryption/src/lib/params-validators.ts b/packages/encryption/src/lib/params-validators.ts index aae0f8d82e..5cbb1591b5 100644 --- a/packages/encryption/src/lib/params-validators.ts +++ b/packages/encryption/src/lib/params-validators.ts @@ -22,7 +22,6 @@ import { AcceptedFileType, AccessControlConditions, AuthMethod, - AuthSig, DecryptFromJsonProps, DecryptRequest, DecryptZipFileWithMetadataProps, @@ -36,8 +35,7 @@ import { EvmContractConditions, GetSignedTokenRequest, JsonExecutionSdkParams, - SessionSigs, - SessionSigsMap, + SessionSigsOrAuthSig, SolRpcConditions, UnifiedAccessControlConditions, } from '@lit-protocol/types'; @@ -72,60 +70,34 @@ export const paramsValidators: Record< string, (params: any) => ParamsValidator[] > = { - executeJs: (params: JsonExecutionSdkParams) => [ - new AuthMaterialValidator('executeJs', params), - new ExecuteJsValidator('executeJs', params), - new AuthMethodValidator('executeJs', params.authMethods), - ], - + // ========== NO AUTH MATERIAL NEEDED FOR CLIENT SIDE ENCRYPTION ========== encrypt: (params: EncryptRequest) => [ new AccessControlConditionsValidator('encrypt', params), - new AuthMaterialValidator('encrypt', params, true), ], encryptFile: (params: EncryptFileRequest) => [ new AccessControlConditionsValidator('encryptFile', params), - new AuthMaterialValidator('encryptFile', params), new FileValidator('encryptFile', params.file), ], encryptString: (params: EncryptStringRequest) => [ new AccessControlConditionsValidator('encryptString', params), - new AuthMaterialValidator('encryptString', params, true), new StringValidator('encryptString', params.dataToEncrypt, 'dataToEncrypt'), ], encryptZip: (params: EncryptZipRequest) => [ new AccessControlConditionsValidator('encryptZip', params), - new AuthMaterialValidator('encryptZip', params), ], zipAndEncryptString: (params: EncryptStringRequest) => [ new StringValidator('zipAndEncryptString', params.dataToEncrypt), ], - decrypt: (params: DecryptRequest) => [ - new AccessControlConditionsValidator('decrypt', params), - new AuthMaterialValidator('decrypt', params, true), - new StringValidator('decrypt', params.ciphertext, 'ciphertext'), - ], - - decryptZipFileWithMetadata: (params: DecryptZipFileWithMetadataProps) => [ - new AuthMaterialValidator('decryptZipFileWithMetadata', params), - new FileValidator('decryptZipFileWithMetadata', params.file), - ], - encryptToJson: (params: EncryptToJsonProps) => [ new AccessControlConditionsValidator('encryptToJson', params), - new AuthMaterialValidator('encryptToJson', params, true), new EncryptToJsonValidator('encryptToJson', params), ], - decryptFromJson: (params: DecryptFromJsonProps) => [ - new AuthMaterialValidator('decryptFromJson', params), - new DecryptFromJsonValidator('decryptFromJson', params.parsedJsonData), - ], - encryptFileAndZipWithMetadata: ( params: EncryptFileAndZipWithMetadataProps ) => [ @@ -142,6 +114,29 @@ export const paramsValidators: Record< ), ], + // ========== REQUIRED AUTH MATERIAL VALIDATORS ========== + executeJs: (params: JsonExecutionSdkParams) => [ + new AuthMaterialValidator('executeJs', params), + new ExecuteJsValidator('executeJs', params), + new AuthMethodValidator('executeJs', params.authMethods), + ], + + decrypt: (params: DecryptRequest) => [ + new AccessControlConditionsValidator('decrypt', params), + new AuthMaterialValidator('decrypt', params, true), + new StringValidator('decrypt', params.ciphertext, 'ciphertext'), + ], + + decryptZipFileWithMetadata: (params: DecryptZipFileWithMetadataProps) => [ + new AuthMaterialValidator('decryptZipFileWithMetadata', params), + new FileValidator('decryptZipFileWithMetadata', params.file), + ], + + decryptFromJson: (params: DecryptFromJsonProps) => [ + new AuthMaterialValidator('decryptFromJson', params), + new DecryptFromJsonValidator('decryptFromJson', params.parsedJsonData), + ], + getSignedToken: (params: GetSignedTokenRequest) => [ new AccessControlConditionsValidator('decrypt', params), new AuthMaterialValidator('decrypt', params, true), @@ -379,8 +374,7 @@ class FileValidator implements ParamsValidator { } } -export interface AuthMaterialValidatorProps { - sessionSigs: SessionSigsMap; +export interface AuthMaterialValidatorProps extends SessionSigsOrAuthSig { chain?: string; } @@ -400,7 +394,14 @@ class AuthMaterialValidator implements ParamsValidator { } validate(): IEither { - const { sessionSigs } = this.authMaterial; + const { authSig, sessionSigs } = this.authMaterial; + + if (authSig && !is(authSig, 'Object', 'authSig', this.fnName)) + return ELeft({ + message: 'authSig is not an object', + errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, + errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, + }); if (this.checkIfAuthSigRequiresChainParam) { if (!this.authMaterial.chain) @@ -409,6 +410,20 @@ class AuthMaterialValidator implements ParamsValidator { errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); + + if ( + authSig && + !checkIfAuthSigRequiresChainParam( + authSig, + this.authMaterial.chain, + this.fnName + ) + ) + return ELeft({ + message: 'authSig is not valid', + errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, + errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, + }); } if (sessionSigs && !is(sessionSigs, 'Object', 'sessionSigs', this.fnName)) @@ -418,9 +433,17 @@ class AuthMaterialValidator implements ParamsValidator { errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, }); - if (!sessionSigs) + if (!sessionSigs && !authSig) + return ELeft({ + message: 'You must pass either authSig or sessionSigs', + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); + + // -- validate: if sessionSig and authSig exists + if (sessionSigs && authSig) return ELeft({ - message: 'You must pass in sessionSigs', + message: 'You cannot have both authSig and sessionSigs', errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 7508415f22..a4b3a5d356 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -116,6 +116,7 @@ import type { ExecuteJsNoSigningResponse, JsonPkpSignSdkParams, SigResponse, + EncryptSdkParams, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; @@ -1542,8 +1543,19 @@ export class LitNodeClientNodeJs * * Encrypt data using the LIT network public key. * + * @param { EncryptSdkParams } params + * @param params.dataToEncrypt - The data to encrypt + * @param params.accessControlConditions - (optional) The access control conditions for the data + * @param params.evmContractConditions - (optional) The EVM contract conditions for the data + * @param params.solRpcConditions - (optional) The Solidity RPC conditions for the data + * @param params.unifiedAccessControlConditions - (optional) The unified access control conditions for the data + * + * @return { Promise } The encrypted ciphertext and the hash of the data + * + * @throws { Error } if the LIT node client is not ready + * @throws { Error } if the subnetPubKey is null */ - encrypt = async (params: EncryptRequest): Promise => { + encrypt = async (params: EncryptSdkParams): Promise => { // ========== Validate Params ========== // -- validate if it's ready if (!this.ready) { @@ -1719,7 +1731,7 @@ export class LitNodeClientNodeJs ): Promise | RejectedNodePromises> => { const nodePromises = this.getNodePromises((url: string) => { // -- if session key is available, use it - const authSigToSend = sessionSigs[url]; + const authSigToSend = sessionSigs ? sessionSigs[url] : params.authSig; return this.getSigningShareForDecryption( url, diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 8ebc666c1e..acdfa00890 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -1,7 +1,7 @@ import { DecryptRequest, DecryptResponse, - EncryptRequest, + EncryptSdkParams, EncryptResponse, ExecuteJsResponse, FormattedMultipleAccs, @@ -234,7 +234,7 @@ export interface ILitNodeClient { * * @param params */ - encrypt(params: EncryptRequest): Promise; + encrypt(params: EncryptSdkParams): Promise; /** * Decrypt data with Lit identity-based Timelock Encryption. diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 537fb3a87b..9fb4889a64 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -520,45 +520,70 @@ export interface JsonExecutionRequest { authMethods?: AuthMethod[]; } -export interface EncryptRequestBase extends MultipleAccessControlConditions { - // The chain name of the chain that this contract is deployed on. See LIT_CHAINS for currently supported chains. - chain: Chain; +/** + * This interface is mainly used for access control conditions & decrypt requests. + * For signing operations such as executeJs and pkpSign, only sessionSigs is used. + */ +export interface SessionSigsOrAuthSig { + /** + * the session signatures to use to authorize the user with the nodes + */ + sessionSigs?: SessionSigsMap; - // the session signatures to use to authorize the user with the nodes - sessionSigs: SessionSigsMap; + /** + * This is a bare authSig generated client side by the user. It can only be used for access control conditions/encrypt/decrypt operations. It CANNOT be used for signing operation. + */ + authSig?: AuthSig; } -export interface EncryptRequest extends EncryptRequestBase { +export interface DecryptRequestBase + extends SessionSigsOrAuthSig, + MultipleAccessControlConditions { + /** + * The chain name of the chain that this contract is deployed on. See LIT_CHAINS for currently supported chains. + */ + chain: Chain; +} +export interface EncryptSdkParams extends MultipleAccessControlConditions { + dataToEncrypt: Uint8Array; +} + +export interface EncryptRequest extends DecryptRequestBase { // The data that you wish to encrypt as a Uint8Array dataToEncrypt: Uint8Array; } export interface EncryptResponse { - // The base64-encoded ciphertext + /** + * The base64-encoded ciphertext + */ ciphertext: string; - // The hash of the data that was encrypted + + /** + * The hash of the data that was encrypted + */ dataToEncryptHash: string; } -export interface EncryptStringRequest extends EncryptRequestBase { - // String that you wish to encrypt +export interface EncryptStringRequest extends MultipleAccessControlConditions { + /** + * String that you wish to encrypt + */ dataToEncrypt: string; } -export interface EncryptZipRequest extends EncryptRequestBase { +export interface EncryptZipRequest extends MultipleAccessControlConditions { + /** + * The zip that you wish to encrypt + */ zip: JSZip; } -export interface EncryptFileRequest extends EncryptRequestBase { +export interface EncryptFileRequest extends DecryptRequestBase { file: AcceptedFileType; } -export interface DecryptRequest extends EncryptRequestBase { - // The base64-encoded ciphertext - ciphertext: string; - // The hash of the data that was encrypted - dataToEncryptHash: string; -} +export interface DecryptRequest extends EncryptResponse, DecryptRequestBase {} export interface DecryptResponse { // The decrypted data as a Uint8Array @@ -856,20 +881,31 @@ export interface JsonHandshakeResponse { latestBlockhash?: string; } -export interface EncryptToJsonProps extends EncryptRequestBase { - // The string you wish to encrypt +export interface EncryptToJsonProps extends MultipleAccessControlConditions { + /** + * The chain + */ + chain: string; + + /** + * The string you wish to encrypt + */ string?: string; - // The file you wish to encrypt + /** + * The file you wish to encrypt + */ file?: AcceptedFileType; - // An instance of LitNodeClient that is already connected + /** + * An instance of LitNodeClient that is already connected + */ litNodeClient: ILitNodeClient; } export type EncryptToJsonDataType = 'string' | 'file'; -export interface EncryptToJsonPayload extends EncryptRequestBase { +export interface EncryptToJsonPayload extends DecryptRequestBase { ciphertext: string; dataToEncryptHash: string; dataType: EncryptToJsonDataType; @@ -903,14 +939,15 @@ export interface EncryptFileAndZipWithMetadataProps readme: string; } -export interface DecryptZipFileWithMetadataProps { - // the session signatures to use to authorize the user with the nodes - sessionSigs: SessionSigsMap; - - // The zip file blob with metadata inside it and the encrypted asset +export interface DecryptZipFileWithMetadataProps extends SessionSigsOrAuthSig { + /** + * The zip file blob with metadata inside it and the encrypted asset + */ file: File | Blob; - // An instance of LitNodeClient that is already connected + /** + * An instance of LitNodeClient that is already connected + */ litNodeClient: ILitNodeClient; } From 21ccc005480e09e06306dffa3a162484ad5f9cc1 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 01:28:06 +0100 Subject: [PATCH 103/263] chore: prettier --- local-tests/setup/tinny-operations.ts | 4 +++- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/auth-helpers/src/lib/generate-auth-sig.ts | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/constants/src/lib/constants/constants.ts | 1 - packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- 28 files changed, 29 insertions(+), 28 deletions(-) diff --git a/local-tests/setup/tinny-operations.ts b/local-tests/setup/tinny-operations.ts index 4a0156a9f4..3b9a0bbb19 100644 --- a/local-tests/setup/tinny-operations.ts +++ b/local-tests/setup/tinny-operations.ts @@ -121,7 +121,9 @@ export const runTestsParallel = async ({ }): Promise => { const filters = getFiltersFlag(); const testsToRun = Object.entries(tests).filter( - ([testName]) => filters.length === 0 || filters.some(filter => testName.includes(filter)) + ([testName]) => + filters.length === 0 || + filters.some((filter) => testName.includes(filter)) ); const testPromises = testsToRun.map( diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 867f3ea362..efaa02b8eb 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 0dd92f6441..2809895bc0 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 0212f2312f..2386457e74 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-alpha.11", + "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/auth-helpers/src/lib/generate-auth-sig.ts b/packages/auth-helpers/src/lib/generate-auth-sig.ts index 9123d713cd..574d67379c 100644 --- a/packages/auth-helpers/src/lib/generate-auth-sig.ts +++ b/packages/auth-helpers/src/lib/generate-auth-sig.ts @@ -6,7 +6,7 @@ import { ethers } from 'ethers'; * * For more context: * We are only using authSig to generate session sigs. In a newer version, we will stop accepting - * authSig all together from the node and will only accept session sigs. The address being + * authSig all together from the node and will only accept session sigs. The address being * used here will be checksummed. * * @param signer the signer must have a "signMessage" method diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 2be81894f8..1e2d1f0389 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index a7420c1e05..4b1881181f 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 2a534af674..865cbf09bb 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -743,7 +743,6 @@ export const LIT_NETWORKS: { [key in LitNetwork]: string[] } & { localhost: string[]; internalDev: string[]; } = { - // FIXME: Reviewers! These are not used in this branch, scroll down to see remapping logic [LitNetwork.Cayenne]: [ `${CAYENNE_URL}:7370'`, diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 3a8f4b5889..044d97ae47 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/core/package.json b/packages/core/package.json index d99c2b2ef3..86700e68b5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 016cca9105..d680c0b241 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index b58823787b..6fcd5713bd 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index d2fab11731..d786daf1e8 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index b9a7990769..33ecc1b9c2 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 1e85f9dd29..8d177b809e 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index c199ce3293..b3a4520aa8 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 34eb65c61d..c405504013 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 25917a6a3b..58b18cfe8d 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 089d70fe07..5acbdba213 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 72b5e19323..4b0af6fb77 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index d09180a573..5e8445f437 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 8e3cdd1dd9..c69e18ab9d 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 12253d0f23..0670776480 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 727e238775..137650df97 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index ce3b4a0c77..9096e55793 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index af3aad5136..6ed7c564dd 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index daf515d3eb..90d7b2094b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 42d20158f1..e98b54d1e7 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} From 030f77f425be0055ee2f64039e474e61e2fa259a Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 02:11:20 +0100 Subject: [PATCH 104/263] fix: typo and jsdocs --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- packages/types/src/lib/interfaces.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 1487ee7d80..4fb162f4b4 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1067,7 +1067,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope if (!events[0].topics || events[0].topics.length < 1) { throw new Error( - `No topics found in events, can not derive pkp information. Transaction hash: ${receipt.transactionHash} If you are using your own contracts please use ethers directly` + `No topics found in events, cannot derive pkp information. Transaction hash: ${receipt.transactionHash} If you are using your own contracts please use ethers directly` ); } diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 9fb4889a64..44e8978c95 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -92,8 +92,19 @@ export interface AuthCallbackParams { resourceAbilityRequests?: LitResourceAbilityRequest[]; + /** + * The js code to run on the nodes + */ litActionCode?: string; + + /** + * The IPFS id of the lit action to run + */ litActionIpfsId?: string; + + /** + * The js params to run on the nodes + */ jsParams?: any; } From c77e32f7c3cd7de89d7316e1e2144c2e7af37692 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 14:05:42 +0100 Subject: [PATCH 105/263] feat: remove AuthValidator for client-side encrypt --- packages/encryption/src/lib/params-validators.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/encryption/src/lib/params-validators.ts b/packages/encryption/src/lib/params-validators.ts index 5cbb1591b5..3afb886824 100644 --- a/packages/encryption/src/lib/params-validators.ts +++ b/packages/encryption/src/lib/params-validators.ts @@ -101,7 +101,6 @@ export const paramsValidators: Record< encryptFileAndZipWithMetadata: ( params: EncryptFileAndZipWithMetadataProps ) => [ - new AuthMaterialValidator('encryptFileAndZipWithMetadata', params, true), new AccessControlConditionsValidator( 'encryptFileAndZipWithMetadata', params From 2d36d4a1241aef23e862f34c7e7086e3497823f5 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 14:12:13 +0100 Subject: [PATCH 106/263] feat: introduce `LIT_CHAIN_RPC_URL` so we don't need to go through `LIT_CHAINS` --- packages/constants/src/lib/constants/constants.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 865cbf09bb..87d1d1b7fd 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -589,6 +589,11 @@ export const LIT_CHAINS: LITChain = { }, }; +/** + * Lit Protocol Chain RPC URL + */ +export const LIT_CHAIN_RPC_URL = LIT_CHAINS['chronicleTestnet'].rpcUrls[0]; + export const LIT_EVM_CHAINS = LIT_CHAINS; /** From 59018218f52814caa5a2cdeb687df40f7f2a10dc Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 14:57:22 +0100 Subject: [PATCH 107/263] fix: use checksum address --- packages/auth-browser/src/lib/chains/eth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth-browser/src/lib/chains/eth.ts b/packages/auth-browser/src/lib/chains/eth.ts index 67946c7879..6c3a754e4f 100644 --- a/packages/auth-browser/src/lib/chains/eth.ts +++ b/packages/auth-browser/src/lib/chains/eth.ts @@ -412,7 +412,7 @@ export const connectWeb3 = async ({ const accounts = await web3.listAccounts(); log('accounts', accounts); - const account = accounts[0].toLowerCase(); + const account = ethers.utils.getAddress(accounts[0]); return { web3, account }; }; From b1e4901f3cea1d0b53be8440943f1d840b82ebb2 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 17:43:48 +0100 Subject: [PATCH 108/263] chore: remove unused import --- packages/core/src/lib/endpoint-version.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/lib/endpoint-version.ts b/packages/core/src/lib/endpoint-version.ts index 41bbb31c07..543d154eee 100644 --- a/packages/core/src/lib/endpoint-version.ts +++ b/packages/core/src/lib/endpoint-version.ts @@ -1,4 +1,3 @@ -import { isNode } from '@lit-protocol/misc'; import { LitEndpoint } from '@lit-protocol/types'; /** From b6bea33904692b23114f9ff5d45b38d10e9818e3 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 17:50:38 +0100 Subject: [PATCH 109/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/455#discussion_r1594312845 --- packages/auth-browser/src/lib/auth-browser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/auth-browser/src/lib/auth-browser.ts b/packages/auth-browser/src/lib/auth-browser.ts index a6d8bc6885..813fa41a78 100644 --- a/packages/auth-browser/src/lib/auth-browser.ts +++ b/packages/auth-browser/src/lib/auth-browser.ts @@ -14,8 +14,8 @@ import { checkAndSignSolAuthMessage } from './chains/sol'; * SUPPORTED CHAINS: EVM, Solana, Cosmos * * !! NOTE !! - * This function is purely used for crafting the authSig for access control conditions & decryption. For SessionSigs, you won't be able to use this - * to add resource ability requests in the SIWE message. Instead, you should provide your own signer to the authNeededCallback parameter for the getSessionSigs method. + * This function is purely used for crafting the authSig for access control conditions & decryption. For SessionSigs, you can pass the `authSig` as `jsParams` + * or Eth Wallet Auth Method for `signSessionKey` and claiming, but you won't be able to use this to add resource ability requests in the SIWE message. Instead, you should provide your own signer to the authNeededCallback parameter for the getSessionSigs method. * * Check for an existing cryptographic authentication signature and create one of it does not exist. This is used to prove ownership of a given crypto wallet address to the Lit nodes. The result is stored in LocalStorage so the user doesn't have to sign every time they perform an operation. * From 65b67092d4cd583e8b654be4c53e41821e8c7089 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 17:52:41 +0100 Subject: [PATCH 110/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/455#discussion_r1594314847 --- packages/encryption/src/lib/encryption.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/encryption/src/lib/encryption.ts b/packages/encryption/src/lib/encryption.ts index e0822285eb..f591549e02 100644 --- a/packages/encryption/src/lib/encryption.ts +++ b/packages/encryption/src/lib/encryption.ts @@ -300,6 +300,7 @@ export const zipAndEncryptString = async ( */ export const zipAndEncryptFiles = async ( files: File[], + params: DecryptRequest, litNodeClient: ILitNodeClient ): Promise => { // let's zip em @@ -342,7 +343,7 @@ export const zipAndEncryptFiles = async ( folder.file(files[i].name, files[i]); } - return encryptZip({ zip }, litNodeClient); + return encryptZip({ zip, ...params }, litNodeClient); }; /** From b541bc228c5e22be1978c63e1b02563b97bcbe68 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 19:13:38 +0100 Subject: [PATCH 111/263] fix: remove `LIT_BLS` as an option --- packages/auth-helpers/src/lib/generate-auth-sig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth-helpers/src/lib/generate-auth-sig.ts b/packages/auth-helpers/src/lib/generate-auth-sig.ts index 574d67379c..49692f89c8 100644 --- a/packages/auth-helpers/src/lib/generate-auth-sig.ts +++ b/packages/auth-helpers/src/lib/generate-auth-sig.ts @@ -23,7 +23,7 @@ export const generateAuthSig = async ({ signer: ethers.Wallet | ethers.Signer | SignerLike; toSign: string; address?: string; - algo?: 'LIT_BLS' | 'ed25519'; + algo?: 'ed25519'; }): Promise => { if (!signer?.signMessage) { throw new Error('signer does not have a signMessage method'); From 06e203d321cd0a6b8f2dd34d63c0d1e438622715 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 8 May 2024 19:23:23 +0100 Subject: [PATCH 112/263] fix: typo --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 4fb162f4b4..e71b7c8b6f 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -652,7 +652,7 @@ export class LitContracts { ): Promise { let address: string = ''; switch (contract) { - case 'AllowList' || 'AllowList': + case 'Allowlist' || 'AllowList': address = await resolverContract['getContract']( await resolverContract['ALLOWLIST_CONTRACT'](), environment From 70e0176bc9683b99e678b5549190c34bb8d5fc8f Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 8 May 2024 15:19:36 -0400 Subject: [PATCH 113/263] ref: refactor cayenne network bootstrap logic --- .../contracts-sdk/src/lib/contracts-sdk.ts | 6 ++- packages/core/src/lib/lit-core.ts | 40 ------------------- 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index dc3b4c56dc..52418e0529 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -915,7 +915,11 @@ export class LitContracts { const networks = activeValidatorStructs.map((item: any) => { let proto = 'https://'; - if (item.port !== 443) { + /** + * ports in range of 8470 - 8479 are configured for https on cayenne network + * we shouold resepct https on these ports as they are using OpenSSL + */ + if (item.port !== 443 || (item.port < 8480 && item.port > 8469)) { proto = 'http://'; } return `${proto}${intToIP(item.ip)}:${item.port}`; diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index f59e2cd970..1b4fa19832 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -255,46 +255,6 @@ export class LitCore { this.config.minNodeCount = parseInt(minNodeCount, 10); this.config.bootstrapUrls = bootstrapUrls; - } else if (this.config.litNetwork === LitNetwork.Cayenne) { - // Handle on staking contract is used to monitor epoch changes - this._stakingContract = await LitContracts.getStakingContract( - this.config.litNetwork - ); - - const minNodeCount = ( - await LitContracts.getMinNodeCount(this.config.litNetwork) - ).toNumber(); - - const bootstrapUrls = await LitContracts.getValidators( - this.config.litNetwork - ); - - /** - * FIXME: We need this reformatting because the Cayenne network is not able to handle the node address as a URL. - * from: https://cayenne.litgateway.com - * to: http://207.244.70.36:7474 - */ - const remappedBootstrapUrls = await Promise.all( - bootstrapUrls.map(async (url) => { - const rootDomain = CAYENNE_URL.replace('https://', ''); - const ipAddress = await getIpAddress(rootDomain); - return `http://${ipAddress}:${new URL(url).port}`; - }) - ); - - // If the network is cayenne it is a centralized testnet, so we use a static config - // This is due to staking contracts holding local ip / port contexts which are innacurate to the ip / port exposed to the world - this.config.bootstrapUrls = remappedBootstrapUrls; - this.config.minNodeCount = - remappedBootstrapUrls.length == 2 - ? 2 - : (remappedBootstrapUrls.length * 2) / 3; - - /** - * Here we are checking if a custom network defined with no node urls (bootstrap urls) defined - * If this is the case we need to bootstrap the network state from the set of contracts given. - * So we call to the Staking contract with the address given by the caller to resolve the network state. - */ } else if ( this.config.litNetwork === LitNetwork.Custom && this.config.bootstrapUrls.length < 1 From 069d60d7d3839b4461fe321049819ece02d28800 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 8 May 2024 15:21:59 -0400 Subject: [PATCH 114/263] ref: remove cayenne default urls --- packages/constants/src/lib/constants/constants.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 2a534af674..3f97a0e292 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -743,13 +743,7 @@ export const LIT_NETWORKS: { [key in LitNetwork]: string[] } & { localhost: string[]; internalDev: string[]; } = { - - // FIXME: Reviewers! These are not used in this branch, scroll down to see remapping logic - [LitNetwork.Cayenne]: [ - `${CAYENNE_URL}:7370'`, - `${CAYENNE_URL}:7371'`, - `${CAYENNE_URL}:7372'`, - ], + [LitNetwork.Cayenne]: [], [LitNetwork.Manzano]: [], [LitNetwork.Habanero]: [], [LitNetwork.Custom]: [], From 42af5dd34c5c882e05854653a790c73a9ef118d9 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 8 May 2024 15:32:06 -0400 Subject: [PATCH 115/263] chore: fmt --- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/src/lib/generate-auth-sig.ts | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 867f3ea362..efaa02b8eb 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 0dd92f6441..2809895bc0 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/src/lib/generate-auth-sig.ts b/packages/auth-helpers/src/lib/generate-auth-sig.ts index 9123d713cd..574d67379c 100644 --- a/packages/auth-helpers/src/lib/generate-auth-sig.ts +++ b/packages/auth-helpers/src/lib/generate-auth-sig.ts @@ -6,7 +6,7 @@ import { ethers } from 'ethers'; * * For more context: * We are only using authSig to generate session sigs. In a newer version, we will stop accepting - * authSig all together from the node and will only accept session sigs. The address being + * authSig all together from the node and will only accept session sigs. The address being * used here will be checksummed. * * @param signer the signer must have a "signMessage" method diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 2be81894f8..1e2d1f0389 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index a7420c1e05..4b1881181f 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 3a8f4b5889..044d97ae47 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/core/package.json b/packages/core/package.json index d99c2b2ef3..86700e68b5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 016cca9105..d680c0b241 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index b58823787b..6fcd5713bd 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index d2fab11731..d786daf1e8 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index b9a7990769..33ecc1b9c2 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 1e85f9dd29..8d177b809e 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index c199ce3293..b3a4520aa8 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 34eb65c61d..c405504013 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 25917a6a3b..58b18cfe8d 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 089d70fe07..5acbdba213 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 72b5e19323..4b0af6fb77 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index d09180a573..5e8445f437 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 8e3cdd1dd9..c69e18ab9d 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 12253d0f23..0670776480 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 727e238775..137650df97 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index ce3b4a0c77..9096e55793 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index af3aad5136..6ed7c564dd 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index daf515d3eb..90d7b2094b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 42d20158f1..e98b54d1e7 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} From 64ffe2602474d5b340f58e24b50e52bc98fa1dc0 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 8 May 2024 19:04:04 -0400 Subject: [PATCH 116/263] ref: fix check on port for http vs https --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 52418e0529..665256b813 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -919,7 +919,7 @@ export class LitContracts { * ports in range of 8470 - 8479 are configured for https on cayenne network * we shouold resepct https on these ports as they are using OpenSSL */ - if (item.port !== 443 || (item.port < 8480 && item.port > 8469)) { + if (item.port !== 443 && item.port > 8480 && item.port < 8469) { proto = 'http://'; } return `${proto}${intToIP(item.ip)}:${item.port}`; From 63d062f62b21c8092a9c607b68b2350086df4d2f Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 00:08:54 +0100 Subject: [PATCH 117/263] feat: add tests for Solana & Cosmos (cosmos is failing) --- local-tests/setup/accs/accs.ts | 43 ++++++++++- local-tests/setup/tinny-environment.ts | 47 +++++++++++- local-tests/test.ts | 15 ++++ local-tests/tests/test-example.ts | 5 +- ...testCosmosAuthSigToEncryptDecryptString.ts | 75 +++++++++++++++++++ .../testEthAuthSigToEncryptDecryptString.ts | 66 ++++++++++++++++ .../testSolAuthSigToEncryptDecryptString.ts | 66 ++++++++++++++++ packages/types/src/lib/interfaces.ts | 10 ++- 8 files changed, 319 insertions(+), 8 deletions(-) create mode 100644 local-tests/tests/testCosmosAuthSigToEncryptDecryptString.ts create mode 100644 local-tests/tests/testEthAuthSigToEncryptDecryptString.ts create mode 100644 local-tests/tests/testSolAuthSigToEncryptDecryptString.ts diff --git a/local-tests/setup/accs/accs.ts b/local-tests/setup/accs/accs.ts index 48a4d03e67..ff7c66564e 100644 --- a/local-tests/setup/accs/accs.ts +++ b/local-tests/setup/accs/accs.ts @@ -1,4 +1,8 @@ -import { LPACC_EVM_BASIC } from '@lit-protocol/accs-schemas'; +import { + LPACC_EVM_ATOM, + LPACC_EVM_BASIC, + LPACC_SOL, +} from '@lit-protocol/accs-schemas'; export namespace AccessControlConditions { export const getEmvBasicAccessControlConditions = ({ @@ -18,4 +22,41 @@ export namespace AccessControlConditions { }, ]; }; + + export const getSolBasicAccessControlConditions = ({ + userAddress, + }): LPACC_SOL[] => { + return [ + { + method: '', + params: [':userAddress'], + pdaParams: [], + pdaInterface: { offset: 0, fields: {} }, + pdaKey: '', + chain: 'solana', + returnValueTest: { + key: '', + comparator: '=', + value: userAddress, + }, + }, + ]; + }; + + export const getCosmosBasicAccessControlConditions = ({ + userAddress, + }): LPACC_EVM_ATOM[] => { + return [ + { + conditionType: 'cosmos', + path: ':userAddress', + chain: 'cosmos', + returnValueTest: { + key: '', + comparator: '=', + value: userAddress, + }, + }, + ]; + }; } diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 4f20cea839..f8d06879e6 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -1,11 +1,16 @@ import { LIT_TESTNET, ProcessEnvs, TinnyEnvConfig } from './tinny-config'; import { LitNodeClient } from '@lit-protocol/lit-node-client'; import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { AuthSig, LitContractContext } from '@lit-protocol/types'; +import { + AuthSig, + CosmosAuthSig, + LitContractContext, + SolanaAuthSig, +} from '@lit-protocol/types'; import { TinnyPerson } from './tinny-person'; import networkContext from './networkContext.json'; import { ethers } from 'ethers'; -import { LIT_ENDPOINT, LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; +import { createSiweMessage, generateAuthSig } from '@lit-protocol/auth-helpers'; export class TinnyEnvironment { public network: LIT_TESTNET; @@ -66,6 +71,22 @@ export class TinnyEnvironment { public contractsClient: LitContracts; public rpc: string; public superCapacityDelegationAuthSig: AuthSig; + public bareEthAuthSig: AuthSig; + public bareSolAuthSig: SolanaAuthSig = { + sig: '706047fcab06ada3cbfeb6990617c1705d59bafb20f5f1c8103d764fb5eaec297328d164e2b891095866b28acc1ab2df288a8729cf026228ef3c4970238b190a', + derivedVia: 'solana.signMessage', + signedMessage: + 'I am creating an account to use Lit Protocol at 2024-05-08T16:39:44.481Z', + address: 'F7r6ENi6dqH8SnMYZdK3YxWAQ4cwfSNXZyMzbea5fbS1', + }; + + public bareCosmosAuthSig: CosmosAuthSig = { + sig: 'dE7J8oaWa8zECuMpaI/IVfJXGpLAO1paGLho+/dmtaQkN7Sh1lmJLAdYqZchDyYhQcg+nqfaoEOzLig3CPlosg==', + derivedVia: 'cosmos.signArbitrary', + signedMessage: + '8c857343720203e3f52606409e6818284186a614e74026998f89e7417eed4d4b', + address: 'cosmos14wp2s5kv07lt220rzfae57k73yv9z2azrmulku', + }; constructor(network?: LIT_TESTNET) { // -- setup networkj @@ -280,6 +301,28 @@ export class TinnyEnvironment { async init() { await this.setupLitNodeClient(); await this.setupSuperCapacityDelegationAuthSig(); + await this.setupBareEthAuthSig(); + } + + /** + * Setup bare eth auth sig to test access control and decryption + */ + async setupBareEthAuthSig() { + const privateKey = await this.getAvailablePrivateKey(); + const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc); + const wallet = new ethers.Wallet(privateKey.privateKey, provider); + + const toSign = await createSiweMessage({ + walletAddress: wallet.address, + nonce: await this.litNodeClient.getLatestBlockhash(), + expiration: new Date(Date.now() + 29 * 24 * 60 * 60 * 1000).toISOString(), + litNodeClient: this.litNodeClient, + }); + + this.bareEthAuthSig = await generateAuthSig({ + signer: wallet, + toSign, + }); } /** diff --git a/local-tests/test.ts b/local-tests/test.ts index ed1277049e..3505160685 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -45,6 +45,9 @@ import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptFile } fro import { testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip } from './tests/testUseValidLitActionCodeGeneratedSessionSigsToEncryptDecryptZip'; import { testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign } from './tests/testUseValidLitActionIpfsCodeGeneratedSessionSigsToPkpSign'; import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/testUseInvalidLitActionIpfsCodeToGenerateSessionSigs'; +import { testSolAuthSigToEncryptDecryptString } from './tests/testSolAuthSigToEncryptDecryptString'; +import { testEthAuthSigToEncryptDecryptString } from './tests/testEthAuthSigToEncryptDecryptString'; +import { testCosmosAuthSigToEncryptDecryptString } from './tests/testCosmosAuthSigToEncryptDecryptString'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -111,6 +114,17 @@ import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/te testUseCapacityDelegationAuthSigWithUnspecifiedCapacityTokenIdToPkpSign, }; + const bareAuthSigTests = { + // -- eth auth sig + testEthAuthSigToEncryptDecryptString, + + // -- solana auth sig + testSolAuthSigToEncryptDecryptString, + + // -- cosmos auth sig + testCosmosAuthSigToEncryptDecryptString, + }; + const testConfig = { tests: { // testExample, @@ -120,6 +134,7 @@ import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/te ...litActionSessionSigsTests, ...litActionIpfsIdSessionSigsTests, ...capacityDelegationTests, + ...bareAuthSigTests, }, devEnv, }; diff --git a/local-tests/tests/test-example.ts b/local-tests/tests/test-example.ts index 6b907d19a0..28665e3a41 100644 --- a/local-tests/tests/test-example.ts +++ b/local-tests/tests/test-example.ts @@ -2,10 +2,7 @@ import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-sessio import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; -import { - LIT_ENDPOINT_VERSION, - LIT_TESTNET, -} from 'local-tests/setup/tinny-config'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; export const testExample = async (devEnv: TinnyEnvironment) => { diff --git a/local-tests/tests/testCosmosAuthSigToEncryptDecryptString.ts b/local-tests/tests/testCosmosAuthSigToEncryptDecryptString.ts new file mode 100644 index 0000000000..374ccf968c --- /dev/null +++ b/local-tests/tests/testCosmosAuthSigToEncryptDecryptString.ts @@ -0,0 +1,75 @@ +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LIT_TESTNET } from 'local-tests/setup/tinny-config'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ NETWORK=cayenne yarn test:local --filter=testCosmosAuthSigToEncryptDecryptString + * ❌ NETWORK=manzano yarn test:local --filter=testCosmosAuthSigToEncryptDecryptString + * ❌ NETWORK=localchain yarn test:local --filter=testCosmosAuthSigToEncryptDecryptString + */ +export const testCosmosAuthSigToEncryptDecryptString = async ( + devEnv: TinnyEnvironment +) => { + console.log('❌❌ THIS IS A KNOWN FAILING TEST, PLEASE IGNORE FOR NOW. ❌❌'); + + devEnv.setUnavailable(LIT_TESTNET.CAYENNE); + devEnv.setUnavailable(LIT_TESTNET.LOCALCHAIN); + devEnv.setUnavailable(LIT_TESTNET.MANZANO); + + const accs = AccessControlConditions.getCosmosBasicAccessControlConditions({ + userAddress: devEnv.bareCosmosAuthSig.address, + }); + + const encryptRes = await LitJsSdk.encryptString( + { + unifiedAccessControlConditions: accs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + console.log('encryptRes:', encryptRes); + + // -- Expected output:´ + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + // -- Decrypt the encrypted string + try { + const decryptRes = await LitJsSdk.decryptToString( + { + unifiedAccessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + authSig: devEnv.bareCosmosAuthSig, + chain: 'cosmos', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + console.log('decryptRes:', decryptRes); + + if (decryptRes !== 'Hello world') { + throw new Error( + `Expected decryptRes to be 'Hello world' but got ${decryptRes}` + ); + } + + console.log('✅ decryptRes:', decryptRes); + } catch (e) { + console.log('❌ ERROR:', e); + } +}; diff --git a/local-tests/tests/testEthAuthSigToEncryptDecryptString.ts b/local-tests/tests/testEthAuthSigToEncryptDecryptString.ts new file mode 100644 index 0000000000..071dc0bc66 --- /dev/null +++ b/local-tests/tests/testEthAuthSigToEncryptDecryptString.ts @@ -0,0 +1,66 @@ +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testEthAuthSigToEncryptDecryptString + * ✅ NETWORK=manzano yarn test:local --filter=testEthAuthSigToEncryptDecryptString + * ✅ NETWORK=localchain yarn test:local --filter=testEthAuthSigToEncryptDecryptString + */ +export const testEthAuthSigToEncryptDecryptString = async ( + devEnv: TinnyEnvironment +) => { + const accs = AccessControlConditions.getEmvBasicAccessControlConditions({ + userAddress: devEnv.bareEthAuthSig.address.toLowerCase(), + }); + + const encryptRes = await LitJsSdk.encryptString( + { + accessControlConditions: accs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + log('encryptRes:', encryptRes); + + // await 5 seconds for the encryption to be mined + + // -- Expected output:´ + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + // -- Decrypt the encrypted string + const decryptRes = await LitJsSdk.decryptToString( + { + accessControlConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + authSig: devEnv.bareEthAuthSig, + chain: 'ethereum', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (decryptRes !== 'Hello world') { + throw new Error( + `Expected decryptRes to be 'Hello world' but got ${decryptRes}` + ); + } + + console.log('✅ decryptRes:', decryptRes); +}; diff --git a/local-tests/tests/testSolAuthSigToEncryptDecryptString.ts b/local-tests/tests/testSolAuthSigToEncryptDecryptString.ts new file mode 100644 index 0000000000..9e110e177c --- /dev/null +++ b/local-tests/tests/testSolAuthSigToEncryptDecryptString.ts @@ -0,0 +1,66 @@ +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import * as LitJsSdk from '@lit-protocol/lit-node-client-nodejs'; +import { ILitNodeClient, LitAbility, SolanaAuthSig } from '@lit-protocol/types'; +import { AccessControlConditions } from 'local-tests/setup/accs/accs'; +import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { log } from '@lit-protocol/misc'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testSolAuthSigToEncryptDecryptString + * ✅ NETWORK=manzano yarn test:local --filter=testSolAuthSigToEncryptDecryptString + * ✅ NETWORK=localchain yarn test:local --filter=testSolAuthSigToEncryptDecryptString + */ +export const testSolAuthSigToEncryptDecryptString = async ( + devEnv: TinnyEnvironment +) => { + const accs = AccessControlConditions.getSolBasicAccessControlConditions({ + userAddress: devEnv.bareSolAuthSig.address, + }); + + const encryptRes = await LitJsSdk.encryptString( + { + solRpcConditions: accs, + dataToEncrypt: 'Hello world', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + console.log('encryptRes:', encryptRes); + + // -- Expected output:´ + // { + // ciphertext: "pSP1Rq4xdyLBzSghZ3DtTtHp2UL7/z45U2JDOQho/WXjd2ntr4IS8BJfqJ7TC2U4CmktrvbVT3edoXJgFqsE7vy9uNrBUyUSTuUdHLfDVMIgh4a7fqMxsdQdkWZjHign3JOaVBihtOjAF5VthVena28D", + // dataToEncryptHash: "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c", + // } + + // -- assertions + if (!encryptRes.ciphertext) { + throw new Error(`Expected "ciphertext" in encryptRes`); + } + + if (!encryptRes.dataToEncryptHash) { + throw new Error(`Expected "dataToEncryptHash" to in encryptRes`); + } + + // -- Decrypt the encrypted string + const decryptRes = await LitJsSdk.decryptToString( + { + solRpcConditions: accs, + ciphertext: encryptRes.ciphertext, + dataToEncryptHash: encryptRes.dataToEncryptHash, + authSig: devEnv.bareSolAuthSig, + chain: 'solana', + }, + devEnv.litNodeClient as unknown as ILitNodeClient + ); + + if (decryptRes !== 'Hello world') { + throw new Error( + `Expected decryptRes to be 'Hello world' but got ${decryptRes}` + ); + } + + console.log('✅ decryptRes:', decryptRes); +}; diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 44e8978c95..bad112b05c 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -40,6 +40,14 @@ export interface AuthSig { algo?: string; } +export interface SolanaAuthSig extends AuthSig { + derivedVia: 'solana.signMessage'; +} + +export interface CosmosAuthSig extends AuthSig { + derivedVia: 'cosmos.signArbitrary'; +} + export type CosmosWalletType = 'keplr' | 'leap'; export interface AuthCallbackParams { @@ -1753,7 +1761,7 @@ export interface WithRecap extends BaseSiweMessage { } export interface WithCapacityDelegation extends BaseSiweMessage { uri: 'lit:capability:delegation'; - litNodeClient: any; + litNodeClient: ILitNodeClient; capacityTokenId?: string; delegateeAddresses?: string[]; uses?: string; From 1af49f107c366084ed60cc24ee91000a6c706cf5 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 00:26:15 +0100 Subject: [PATCH 118/263] fix: replaced with helper --- .../src/lib/lit-node-client.spec.ts | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 packages/lit-node-client/src/lib/lit-node-client.spec.ts diff --git a/packages/lit-node-client/src/lib/lit-node-client.spec.ts b/packages/lit-node-client/src/lib/lit-node-client.spec.ts deleted file mode 100644 index 1fdf3b7cc0..0000000000 --- a/packages/lit-node-client/src/lib/lit-node-client.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { LitNodeClient } from './lit-node-client'; -let client: LitNodeClient; - -jest.setTimeout(60000); - -describe('LitNodeClient static methods', () => { - it('Should combine claim responses', () => { - const nodeclaimResponses = [ - { - foo: { - keyId: 'abc1234', - signature: - 'f84ad3d3efa42abcae2b3567c836f1342552a75ed038e9403b77a7c47e3500242572c86ddee7f9af4994793a741111553ac7652897ee5447b143b8067557a3511b', - }, - bar: { - keyId: 'xyz1234', - signature: - 'f84ad3d3efa42abcae2b3567c836f1342552a75ed038e9403b77a7c47e3500242572c86ddee7f9af4994793a741111553ac7652897ee5447b143b8067557a3511b', - }, - }, - { - foo: { - keyId: 'abc1234', - signature: - 'f84ad3d3efa42abcae2b3567c836f1342552a75ed038e9403b77a7c47e3500242572c86ddee7f9af4994793a741111553ac7652897ee5447b143b8067557a3511b', - }, - bar: { - keyId: 'xyz1234', - signature: - 'f84ad3d3efa42abcae2b3567c836f1342552a75ed038e9403b77a7c47e3500242572c86ddee7f9af4994793a741111553ac7652897ee5447b143b8067557a3511b', - }, - }, - { - foo: { - keyId: 'abc1234', - signature: - 'f84ad3d3efa42abcae2b3567c836f1342552a75ed038e9403b77a7c47e3500242572c86ddee7f9af4994793a741111553ac7652897ee5447b143b8067557a3511b', - }, - bar: { - keyId: 'xyz1234', - signature: - 'f84ad3d3efa42abcae2b3567c836f1342552a75ed038e9403b77a7c47e3500242572c86ddee7f9af4994793a741111553ac7652897ee5447b143b8067557a3511b', - }, - }, - ]; - - const combinedClaims = LitNodeClient.getClaims(nodeclaimResponses); - expect(Object.keys(combinedClaims).length).toEqual(2); - expect(combinedClaims['foo'].signatures.length).toEqual(3); - }); -}); From 2461bc0864eb9075390a9ae3cce91baac19c1724 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 00:26:26 +0100 Subject: [PATCH 119/263] fix: unit test to resolve ip --- packages/misc/src/lib/misc.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/misc/src/lib/misc.spec.ts b/packages/misc/src/lib/misc.spec.ts index 5cf4edeb09..2f0e7e22d9 100644 --- a/packages/misc/src/lib/misc.spec.ts +++ b/packages/misc/src/lib/misc.spec.ts @@ -295,5 +295,5 @@ it('should get ip address', async () => { global.fetch = fetch; const ipAddres = await utilsModule.getIpAddress('cayenne.litgateway.com'); - expect(ipAddres).toBe('1'); + expect(ipAddres).toBe('207.244.70.36'); }); From d735aa297bbfca1bacd0c8ebf5df0519200edb88 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 00:30:59 +0100 Subject: [PATCH 120/263] fix: remove authMethod from executeJs --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index a4b3a5d356..e3935732b0 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -769,7 +769,6 @@ export class LitNodeClientNodeJs const res = await this.executeJs({ ipfsId: LIT_ACTION_IPFS_HASH, sessionSigs, - authMethods: [], jsParams: { dataToHash, }, From 81fb920ee7510dbb5fbecfd342236b2ac79b1e5a Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 02:09:26 +0100 Subject: [PATCH 121/263] Update packages/contracts-sdk/src/lib/contracts-sdk.ts Co-authored-by: Howard Signed-off-by: Anson --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 665256b813..06116fdb21 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -917,7 +917,7 @@ export class LitContracts { let proto = 'https://'; /** * ports in range of 8470 - 8479 are configured for https on cayenne network - * we shouold resepct https on these ports as they are using OpenSSL + * we shouold resepct https on these ports as they are using trusted ZeroSSL certs */ if (item.port !== 443 && item.port > 8480 && item.port < 8469) { proto = 'http://'; From 546c6d101372e3ed9bcfd77f10b547c774e2fe54 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 02:09:41 +0100 Subject: [PATCH 122/263] Update packages/contracts-sdk/src/lib/contracts-sdk.ts Co-authored-by: Howard Signed-off-by: Anson --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 06116fdb21..c70f06cdb8 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -916,7 +916,7 @@ export class LitContracts { const networks = activeValidatorStructs.map((item: any) => { let proto = 'https://'; /** - * ports in range of 8470 - 8479 are configured for https on cayenne network + * ports in range of 8470 - 8479 are configured for https on custom networks (eg. cayenne) * we shouold resepct https on these ports as they are using trusted ZeroSSL certs */ if (item.port !== 443 && item.port > 8480 && item.port < 8469) { From cfd35de9530a084bf138fa8af0e27230c28fec48 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 14:15:19 +0100 Subject: [PATCH 123/263] fix(unit-test): TypeError: Cannot use 'in' operator to search for 'defaultAuthCallback' in undefined --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index e3935732b0..d080b87184 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -141,7 +141,7 @@ export class LitNodeClientNodeJs constructor(args: LitNodeClientConfig | CustomNetwork) { super(args); - if ('defaultAuthCallback' in args) { + if (args !== undefined && args !== null && 'defaultAuthCallback' in args) { this.defaultAuthCallback = args.defaultAuthCallback; } } From 57da70272542e765d3a6bb50e59d325f8cb70733 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 14:16:49 +0100 Subject: [PATCH 124/263] fix(unit-test): remove unused functions & fix test to adapt new interface --- .../src/lib/lit-node-client-nodejs.spec.ts | 69 ------------------- .../pkp-client/src/lib/wallet-factory.spec.ts | 17 ++++- 2 files changed, 16 insertions(+), 70 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.spec.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.spec.ts index c6fc910378..d258aa4cdf 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.spec.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.spec.ts @@ -6,14 +6,6 @@ global.jestTesting = true; import { LitNodeClientNodeJs } from './lit-node-client-nodejs'; -import { hashResourceIdForSigning } from '@lit-protocol/access-control-conditions'; - -import { - LitAbility, - LitAccessControlConditionResource, -} from '@lit-protocol/auth-helpers'; -import * as LITCONFIG from 'lit.config.json'; -import { StorageProvider } from '../../../types/src/lib/interfaces'; const isClass = (v) => { return typeof v === 'function' && /^\s*class\s+/.test(v.toString()); @@ -72,65 +64,4 @@ describe('LitNodeClientNodeJs', () => { expect(expiration).toContain('T'); }); - - describe('normalizeParams', () => { - it('should normalise params', () => { - // Setup - const buffer = new ArrayBuffer(2); - const view = new Uint8Array(buffer); - view[0] = 1; - view[1] = 2; - let params = { jsParams: { bufferArray: view } }; - - // Action - params = LitNodeClientNodeJs.normalizeParams(params); - - // Assert - expect(params.jsParams.bufferArray).toEqual([1, 2]); - }); - - it('should leave normal arrays unchanged', () => { - // Setup - let params = { jsParams: { normalArray: [1, 2, 3] } }; - - // Action - params = LitNodeClientNodeJs.normalizeParams(params); - - // Assert - expect(params.jsParams.normalArray).toEqual([1, 2, 3]); - }); - - it('should ignore non-array and non-ArrayBuffer properties', () => { - // Setup - let params = { jsParams: { number: 123, string: 'test' } }; - - // Action - params = LitNodeClientNodeJs.normalizeParams(params); - - // Assert - expect(params.jsParams.number).toEqual(123); - expect(params.jsParams.string).toEqual('test'); - }); - - it('should handle multiple properties', () => { - // Setup - const buffer = new ArrayBuffer(2); - const view = new Uint8Array(buffer); - view[0] = 1; - view[1] = 2; - let params = { - jsParams: { - bufferArray: view, - normalArray: [3, 4, 5], - }, - }; - - // Action - params = LitNodeClientNodeJs.normalizeParams(params); - - // Assert - expect(params.jsParams.bufferArray).toEqual([1, 2]); - expect(params.jsParams.normalArray).toEqual([3, 4, 5]); - }); - }); }); diff --git a/packages/pkp-client/src/lib/wallet-factory.spec.ts b/packages/pkp-client/src/lib/wallet-factory.spec.ts index 57b4f4b927..400045a98b 100644 --- a/packages/pkp-client/src/lib/wallet-factory.spec.ts +++ b/packages/pkp-client/src/lib/wallet-factory.spec.ts @@ -4,7 +4,12 @@ import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; import { WalletFactory } from './wallet-factory'; import * as LITCONFIG from 'lit.config.json'; -import { PKPCosmosWalletProp, PKPEthersWalletProp } from '@lit-protocol/types'; +import { + AuthCallbackParams, + AuthSig, + PKPCosmosWalletProp, + PKPEthersWalletProp, +} from '@lit-protocol/types'; describe('WalletFactory', () => { it('should create an Ethereum wallet', () => { @@ -32,6 +37,11 @@ describe('WalletFactory', () => { getSessionSigsProps: { chain: 'ethereum', resourceAbilityRequests: [], + authNeededCallback: function ( + params: AuthCallbackParams + ): Promise { + throw new Error('Function not implemented.'); + }, }, }, pkpPubKey: LITCONFIG.PKP_PUBKEY, @@ -57,6 +67,11 @@ describe('WalletFactory', () => { getSessionSigsProps: { chain: 'ethereum', resourceAbilityRequests: [], + authNeededCallback: function ( + params: AuthCallbackParams + ): Promise { + throw new Error('Function not implemented.'); + }, }, }, pkpPubKey: LITCONFIG.PKP_PUBKEY, From a39837b62b31dba68c61799dde56f572be7f9e35 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 14:55:46 +0100 Subject: [PATCH 125/263] feat: add pkp-ethers tests --- local-tests/build.mjs | 7 ++- local-tests/test.ts | 6 ++ local-tests/tests/testPkpEthersOperations.ts | 66 ++++++++++++++++++++ packages/pkp-ethers/src/lib/pkp-ethers.ts | 7 +-- packages/types/src/lib/interfaces.ts | 34 +++++++--- 5 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 local-tests/tests/testPkpEthersOperations.ts diff --git a/local-tests/build.mjs b/local-tests/build.mjs index 644b2bce10..2a3254db6a 100644 --- a/local-tests/build.mjs +++ b/local-tests/build.mjs @@ -15,7 +15,12 @@ export const build = async () => { bundle: true, plugins: [ nodeExternalsPlugin({ - allowList: ['ethers', '@lit-protocol/accs-schemas', 'crypto'], + allowList: [ + 'ethers', + '@lit-protocol/accs-schemas', + 'crypto', + 'secp256k1', + ], }), ], platform: 'node', diff --git a/local-tests/test.ts b/local-tests/test.ts index 3505160685..0482f5d6c3 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -48,6 +48,7 @@ import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/te import { testSolAuthSigToEncryptDecryptString } from './tests/testSolAuthSigToEncryptDecryptString'; import { testEthAuthSigToEncryptDecryptString } from './tests/testEthAuthSigToEncryptDecryptString'; import { testCosmosAuthSigToEncryptDecryptString } from './tests/testCosmosAuthSigToEncryptDecryptString'; +import { testPkpEthersOperations } from './tests/testPkpEthersOperations'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -125,6 +126,10 @@ import { testCosmosAuthSigToEncryptDecryptString } from './tests/testCosmosAuthS testCosmosAuthSigToEncryptDecryptString, }; + const pkpEthersTest = { + testPkpEthersOperations, + }; + const testConfig = { tests: { // testExample, @@ -135,6 +140,7 @@ import { testCosmosAuthSigToEncryptDecryptString } from './tests/testCosmosAuthS ...litActionIpfsIdSessionSigsTests, ...capacityDelegationTests, ...bareAuthSigTests, + ...pkpEthersTest, }, devEnv, }; diff --git a/local-tests/tests/testPkpEthersOperations.ts b/local-tests/tests/testPkpEthersOperations.ts new file mode 100644 index 0000000000..e1c2479168 --- /dev/null +++ b/local-tests/tests/testPkpEthersOperations.ts @@ -0,0 +1,66 @@ +// import { AuthCallbackParams, AuthSig, LitAbility } from '@lit-protocol/types'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +// import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; +// import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersOperations + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersOperations + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersOperations + */ +export const testPkpEthersOperations = async (devEnv: TinnyEnvironment) => { + console.log('Hello!'); + return; + // const alice = await devEnv.createRandomPerson(); + + // const pkpEthersWallet = new PKPEthersWallet({ + // pkpPubKey: alice.pkp.publicKey, + // authContext: { + // authMethods: [alice.authMethod], + // client: devEnv.litNodeClient, + // getSessionSigsProps: { + // resourceAbilityRequests: [ + // { + // resource: new LitPKPResource('*'), + // ability: LitAbility.PKPSigning, + // }, + // { + // resource: new LitActionResource('*'), + // ability: LitAbility.LitActionExecution, + // }, + // ], + // authNeededCallback: async function ( + // props: AuthCallbackParams + // ): Promise { + // const response = await this.signSessionKey({ + // sessionKey: props.sessionKey, + // statement: props.statement || 'Some custom statement.', + // authMethods: [alice.authMethod], + // pkpPublicKey: alice.authMethodOwnedPkp, + // expiration: props.expiration, + // resources: props.resources, + // chainId: 1, + + // // -- required fields + // resourceAbilityRequests: props.resourceAbilityRequests, + + // // -- optional fields + // ...(props.litActionCode && { litActionCode: props.litActionCode }), + // ...(props.litActionIpfsId && { + // litActionIpfsId: props.litActionIpfsId, + // }), + // ...(props.jsParams && { jsParams: props.jsParams }), + // }); + + // return response.authSig; + // }, + // }, + // }, + // }); + + // await pkpEthersWallet.init(); + + // const signature = await pkpEthersWallet.signMessage(alice.loveLetter); + // console.log('signature:', signature); +}; diff --git a/packages/pkp-ethers/src/lib/pkp-ethers.ts b/packages/pkp-ethers/src/lib/pkp-ethers.ts index 1ccd3a5cd4..d17d2109be 100644 --- a/packages/pkp-ethers/src/lib/pkp-ethers.ts +++ b/packages/pkp-ethers/src/lib/pkp-ethers.ts @@ -35,15 +35,10 @@ import { Logger } from '@ethersproject/logger'; import { version } from 'ethers'; import { ethers, Wallet } from 'ethers'; -import { - LITChainRequiredProps, - PKPClientHelpers, - PKPEthersWalletProp, -} from '@lit-protocol/types'; +import { PKPClientHelpers, PKPEthersWalletProp } from '@lit-protocol/types'; import { PKPBase } from '@lit-protocol/pkp-base'; import { ethRequestHandler } from './handler'; import { - ETHHandlerReq, ETHRequestSigningPayload, ETHSignature, ETHTxRes, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index bad112b05c..cbe20c15b6 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1234,20 +1234,21 @@ export interface LitClientSessionManager { export interface AuthenticationProps { client: LitClientSessionManager; + + /** + * This params is equivalent to the `getSessionSigs` params in the `litNodeClient` + */ getSessionSigsProps: GetSessionSigsProps; authMethods: AuthMethod[]; } export interface PKPBaseProp { + // -- required pkpPubKey: string; + + // -- optional rpc?: string; rpcs?: RPCUrls; - controllerAuthSig?: AuthSig; - // @deprecated - controllerAuthMethods?: AuthMethod[]; - // @deprecated - controllerSessionSigs?: SessionSigs; - // @deprecated sessionSigsExpiration?: string; authContext?: AuthenticationProps; litNetwork?: any; @@ -1258,6 +1259,22 @@ export interface PKPBaseProp { litActionIPFS?: string; litActionJsParams?: any; provider?: Provider; + + // -- soon to be deprecated + /** + * @deprecated - use authContext + */ + controllerAuthMethods?: AuthMethod[]; + + /** + * @deprecated - use authContext + */ + controllerSessionSigs?: SessionSigs; + + /** + * @deprecated - use authContext + */ + controllerAuthSig?: AuthSig; } export interface RPCUrls { @@ -1266,7 +1283,10 @@ export interface RPCUrls { btc?: string; } -export type PKPEthersWalletProp = PKPBaseProp; +export type PKPEthersWalletProp = Omit< + PKPBaseProp, + 'controllerAuthSig' | 'controllerAuthMethods' | 'controllerSessionSigs' +>; export interface PKPCosmosWalletProp extends PKPBaseProp { addressPrefix: string | 'cosmos'; // bech32 address prefix (human readable part) (default: cosmos) From 31ffaa617fd06d3aa6d949fd855578c55f56a686 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 14:15:19 +0100 Subject: [PATCH 126/263] docs(tinny): add prerequisite --- local-tests/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/local-tests/README.md b/local-tests/README.md index a4db70e7af..259f926978 100644 --- a/local-tests/README.md +++ b/local-tests/README.md @@ -2,6 +2,11 @@ Tinny is a mini test framework, serving as a temporary solution for running e2e tests in TypeScript until we can integrate `Jest`. It utilizes `esbuild` for its rapid compilation speed to bundle all the tests into a single `test.mjs` file, then runs the built `test.mjs` file immediately. See [Benchmark](#esbuild-benchmark) +# Prerequisite + +- Node v20 or above +- The generated file `networkContext.ts` after running `npm run deploy -- --network localchain` in the `lit-assets` repo + # How to run In most cases, you will only need the following two environment variables, and a `--filter` flag. See [API](#api) From 98209776ea143eed085fbe29c26bdc011a41a362 Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 17:11:22 +0100 Subject: [PATCH 127/263] docs(tinny): update usage --- local-tests/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/local-tests/README.md b/local-tests/README.md index 259f926978..b9c93bd760 100644 --- a/local-tests/README.md +++ b/local-tests/README.md @@ -23,6 +23,9 @@ DEBUG=true NETWORK=localchain yarn test:local DEBUG=true NETWORK=manzano yarn test:local --filter=testExample DEBUG=true NETWORK=manzano yarn test:local --filter=testExample,testBundleSpeed +// run filtered tests by keyword +DEBUG=true NETWORK=manzano yarn test:local --filter=Encrypt + // eg. yarn test:local --filter=testExample,testBundleSpeed From 653674a917cf4af75c459f41834ce7c453d1f37c Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 19:07:47 +0100 Subject: [PATCH 128/263] fix: pkpEthers to adapt new getSession change --- .../test-pkp-ethers-handler-eth-sign.mjs | 54 ----------- ...test-pkp-ethers-handler-personal-sign .mjs | 53 ----------- .../test-pkp-ethers-handler-send-tx.mjs | 71 --------------- local-tests/setup/tinny-config.ts | 5 ++ local-tests/setup/tinny-environment.ts | 6 +- local-tests/test.ts | 14 ++- local-tests/tests/testPkpEthersOperations.ts | 66 -------------- ...estPkpEthersWithEoaSessionSigsToEthSign.ts | 60 +++++++++++++ ...pEthersWithEoaSessionSigsToPersonalSign.ts | 61 +++++++++++++ ...testPkpEthersWithEoaSessionSigsToSendTx.ts | 64 +++++++++++++ ...kpEthersWithEoaSessionSigsToSignMessage.ts | 33 +++++++ ...WithEoaSessionSigsToSignWithAuthContext.ts | 69 ++++++++++++++ packages/pkp-base/src/lib/pkp-base.ts | 89 ++++++++++--------- packages/types/src/lib/interfaces.ts | 25 ++---- 14 files changed, 361 insertions(+), 309 deletions(-) delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-eth-sign.mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-personal-sign .mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-send-tx.mjs delete mode 100644 local-tests/tests/testPkpEthersOperations.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSign.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToPersonalSign.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToSignMessage.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-eth-sign.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-eth-sign.mjs deleted file mode 100644 index dcbcfaf03c..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-eth-sign.mjs +++ /dev/null @@ -1,54 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - // Message to sign - const message = 'Hello world'; - const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); - - // eth_sign parameters - // DATA, 20 Bytes - address - // DATA, N Bytes - message to sign - // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sign - const signature = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_sign', - params: [globalThis.LitCI.PKP_INFO.ethAddress, hexMsg], - }, - }); - - const recoveredAddr = ethers.utils.verifyMessage(message, signature); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if (recoveredAddr !== globalThis.LitCI.PKP_INFO.ethAddress) { - return fail( - `recoveredAddr should be ${LITCONFIG.PKP_ETH_ADDRESS} but got ${recoveredAddr}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to eth_sign'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-personal-sign .mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-personal-sign .mjs deleted file mode 100644 index 79bd948b4d..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-personal-sign .mjs +++ /dev/null @@ -1,53 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - // Message to sign - const message = 'Free the web'; - const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); - - // personal_sign parameters - // DATA, N Bytes - message to sign. - // DATA, 20 Bytes - address - // Reference: https://metamask.github.io/api-playground/api-documentation/#personal_sign - const signature = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'personal_sign', - params: [hexMsg, globalThis.LitCI.PKP_INFO.ethAddress], - }, - }); - - const recoveredAddr = ethers.utils.verifyMessage(message, signature); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if (recoveredAddr !== globalThis.LitCI.PKP_INFO.ethAddress) { - return fail( - `recoveredAddr should be ${LITCONFIG.PKP_ETH_ADDRESS} but got ${recoveredAddr}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to personal_sign'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-send-tx.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-send-tx.mjs deleted file mode 100644 index 1aa7983bdd..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-send-tx.mjs +++ /dev/null @@ -1,71 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - - // Transaction to sign and send - const from = globalThis.LitCI.PKP_INFO.ethAddress; - const to = globalThis.LitCI.PKP_INFO.ethAddress; - const gasLimit = ethers.BigNumber.from('21000'); - const value = ethers.BigNumber.from('0'); - const data = '0x'; - - // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) - const tx = { - from: from, - to: to, - gasLimit, - value, - data, - }; - - // eth_sendTransaction parameters - // Transaction - Object - // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sendTransaction - let txRes; - - try { - txRes = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_sendTransaction', - params: [tx], - }, - }); - } catch (e) { - if (e.toString().includes('insufficient FPE funds')) { - return success( - `PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` - ); - } - return fail( - `PKPEthersWallet should be able to send tx unexpected error: ${e.toString()}` - ); - } - - // ==================== Post-Validation ==================== - if (!txRes) { - return fail('txRes should not be null'); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to send tx'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/local-tests/setup/tinny-config.ts b/local-tests/setup/tinny-config.ts index c9227ab8ac..e62e2e4175 100644 --- a/local-tests/setup/tinny-config.ts +++ b/local-tests/setup/tinny-config.ts @@ -75,6 +75,11 @@ export interface ProcessEnvs { * The list of keys that are currently in use. */ KEY_IN_USE: boolean[]; + + /** + * Ignore setup steps. Usually when you run to quickly run a single test. + */ + NO_SETUP: boolean; } /** diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index f8d06879e6..81cdac3a33 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -41,7 +41,6 @@ export class TinnyEnvironment { // Available Accounts // ================== - // (0) "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" (10000.000000000000000000 ETH) // (1) "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (10000.000000000000000000 ETH) // (2) "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" (10000.000000000000000000 ETH) @@ -65,6 +64,7 @@ export class TinnyEnvironment { '0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6', ], KEY_IN_USE: new Array(), + NO_SETUP: Boolean(process.env['NO_SETUP']) || false, }; public litNodeClient: LitNodeClient; @@ -299,6 +299,10 @@ export class TinnyEnvironment { * Init */ async init() { + if (this.processEnvs.NO_SETUP) { + console.log('[𐬺🧪 Tinny Environment𐬺] Skipping setup'); + return; + } await this.setupLitNodeClient(); await this.setupSuperCapacityDelegationAuthSig(); await this.setupBareEthAuthSig(); diff --git a/local-tests/test.ts b/local-tests/test.ts index 0482f5d6c3..240710aefe 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -1,5 +1,3 @@ -import { LIT_ENDPOINT_VERSION } from '@lit-protocol/constants'; -import { LIT_TESTNET } from './setup/tinny-config'; import { TinnyEnvironment } from './setup/tinny-environment'; import { runInBand, runTestsParallel } from './setup/tinny-operations'; // import { testBundleSpeed } from './tests/test-bundle-speed'; @@ -48,7 +46,11 @@ import { testUseInvalidLitActionIpfsCodeToGenerateSessionSigs } from './tests/te import { testSolAuthSigToEncryptDecryptString } from './tests/testSolAuthSigToEncryptDecryptString'; import { testEthAuthSigToEncryptDecryptString } from './tests/testEthAuthSigToEncryptDecryptString'; import { testCosmosAuthSigToEncryptDecryptString } from './tests/testCosmosAuthSigToEncryptDecryptString'; -import { testPkpEthersOperations } from './tests/testPkpEthersOperations'; +import { testPkpEthersWithEoaSessionSigsToSignMessage } from './tests/testPkpEthersWithEoaSessionSigsToSignMessage'; +import { testPkpEthersWithEoaSessionSigsToSignWithAuthContext } from './tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext'; +import { testPkpEthersWithEoaSessionSigsToEthSign } from './tests/testPkpEthersWithEoaSessionSigsToEthSign'; +import { testPkpEthersWithEoaSessionSigsToPersonalSign } from './tests/testPkpEthersWithEoaSessionSigsToPersonalSign'; +import { testPkpEthersWithEoaSessionSigsToSendTx } from './tests/testPkpEthersWithEoaSessionSigsToSendTx'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -127,7 +129,11 @@ import { testPkpEthersOperations } from './tests/testPkpEthersOperations'; }; const pkpEthersTest = { - testPkpEthersOperations, + testPkpEthersWithEoaSessionSigsToSignWithAuthContext, + testPkpEthersWithEoaSessionSigsToSignMessage, + testPkpEthersWithEoaSessionSigsToEthSign, + testPkpEthersWithEoaSessionSigsToPersonalSign, + testPkpEthersWithEoaSessionSigsToSendTx, }; const testConfig = { diff --git a/local-tests/tests/testPkpEthersOperations.ts b/local-tests/tests/testPkpEthersOperations.ts deleted file mode 100644 index e1c2479168..0000000000 --- a/local-tests/tests/testPkpEthersOperations.ts +++ /dev/null @@ -1,66 +0,0 @@ -// import { AuthCallbackParams, AuthSig, LitAbility } from '@lit-protocol/types'; -import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; -// import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -// import { LitActionResource, LitPKPResource } from '@lit-protocol/auth-helpers'; - -/** - * Test Commands: - * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersOperations - * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersOperations - * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersOperations - */ -export const testPkpEthersOperations = async (devEnv: TinnyEnvironment) => { - console.log('Hello!'); - return; - // const alice = await devEnv.createRandomPerson(); - - // const pkpEthersWallet = new PKPEthersWallet({ - // pkpPubKey: alice.pkp.publicKey, - // authContext: { - // authMethods: [alice.authMethod], - // client: devEnv.litNodeClient, - // getSessionSigsProps: { - // resourceAbilityRequests: [ - // { - // resource: new LitPKPResource('*'), - // ability: LitAbility.PKPSigning, - // }, - // { - // resource: new LitActionResource('*'), - // ability: LitAbility.LitActionExecution, - // }, - // ], - // authNeededCallback: async function ( - // props: AuthCallbackParams - // ): Promise { - // const response = await this.signSessionKey({ - // sessionKey: props.sessionKey, - // statement: props.statement || 'Some custom statement.', - // authMethods: [alice.authMethod], - // pkpPublicKey: alice.authMethodOwnedPkp, - // expiration: props.expiration, - // resources: props.resources, - // chainId: 1, - - // // -- required fields - // resourceAbilityRequests: props.resourceAbilityRequests, - - // // -- optional fields - // ...(props.litActionCode && { litActionCode: props.litActionCode }), - // ...(props.litActionIpfsId && { - // litActionIpfsId: props.litActionIpfsId, - // }), - // ...(props.jsParams && { jsParams: props.jsParams }), - // }); - - // return response.authSig; - // }, - // }, - // }, - // }); - - // await pkpEthersWallet.init(); - - // const signature = await pkpEthersWallet.signMessage(alice.loveLetter); - // console.log('signature:', signature); -}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSign.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSign.ts new file mode 100644 index 0000000000..bf3151a105 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSign.ts @@ -0,0 +1,60 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSign + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSign + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSign + */ +export const testPkpEthersWithEoaSessionSigsToEthSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + console.log('devEnv.network:', devEnv.network); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- test eth_sign + try { + // Message to sign + const message = 'Hello world'; + const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); + + // DATA, 20 Bytes - address + // DATA, N Bytes - message to sign + // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sign + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_sign', + params: [alice.pkp.ethAddress, hexMsg], + }, + }); + const recoveredAddr = ethers.utils.verifyMessage(message, signature); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr !== alice.pkp.ethAddress) { + throw new Error( + `❌ test eth_sign recoveredAddr should be ${alice.pkp.ethAddress} but got ${recoveredAddr}` + ); + } + + console.log('✅ recoveredAddr:', recoveredAddr); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToPersonalSign.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToPersonalSign.ts new file mode 100644 index 0000000000..74c963d307 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToPersonalSign.ts @@ -0,0 +1,61 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToPersonalSign + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToPersonalSign + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToPersonalSign + */ +export const testPkpEthersWithEoaSessionSigsToPersonalSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- personal_sign parameters + try { + // Message to sign + const message = 'Free the web'; + const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); + + // personal_sign parameters + // DATA, N Bytes - message to sign. + // DATA, 20 Bytes - address + // Reference: https://metamask.github.io/api-playground/api-documentation/#personal_sign + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'personal_sign', + params: [hexMsg, alice.pkp.ethAddress], + }, + }); + + const recoveredAddr = ethers.utils.verifyMessage(message, signature); + + // ==================== Post-Validation ==================== + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr !== alice.pkp.ethAddress) { + throw new Error( + `❌ recoveredAddr should be ${alice.pkp.ethAddress} but got ${recoveredAddr}` + ); + } + + console.log('✅ personal_sign recoveredAddr:', recoveredAddr); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts new file mode 100644 index 0000000000..9f4830a34a --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts @@ -0,0 +1,64 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSendTx + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSendTx + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSendTx + */ +export const testPkpEthersWithEoaSessionSigsToSendTx = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_sendTransaction parameters + try { + // Transaction to sign and send + const from = alice.pkp.ethAddress; + const to = alice.pkp.ethAddress; + const gasLimit = ethers.BigNumber.from('21000'); + const value = ethers.BigNumber.from('0'); + const data = '0x'; + + // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) + const tx = { + from: from, + to: to, + gasLimit, + value, + data, + }; + + const txRes = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_sendTransaction', + params: [tx], + }, + }); + + console.log('✅ txRes:', txRes); + } catch (e) { + if (e.message.includes('insufficient FPE funds')) { + console.log( + `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` + ); + } else { + throw new Error( + `❌ PKPEthersWallet should be able to send tx unexpected error: ${e.toString()}` + ); + } + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignMessage.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignMessage.ts new file mode 100644 index 0000000000..42591b54c4 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignMessage.ts @@ -0,0 +1,33 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSignMessage + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSignMessage + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSignMessage + */ +export const testPkpEthersWithEoaSessionSigsToSignMessage = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- test signMessage + try { + const signature = await pkpEthersWallet.signMessage(alice.loveLetter); + console.log('✅ signature:', signature); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts new file mode 100644 index 0000000000..81ae3a5395 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts @@ -0,0 +1,69 @@ +import { + LitAbility, + LitActionResource, + LitPKPResource, + createSiweMessageWithRecaps, + generateAuthSig, +} from '@lit-protocol/auth-helpers'; +import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; +import { AuthCallbackParams, AuthSig } from '@lit-protocol/types'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSignWithAuthContext + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSignWithAuthContext + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToSignWithAuthContext + */ +export const testPkpEthersWithEoaSessionSigsToSignWithAuthContext = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + const pkpEthersWallet = new PKPEthersWallet({ + pkpPubKey: alice.pkp.publicKey, + litNodeClient: devEnv.litNodeClient, + authContext: { + getSessionSigsProps: { + authNeededCallback: async function ( + params: AuthCallbackParams + ): Promise { + const toSign = await createSiweMessageWithRecaps({ + uri: params.uri, + expiration: params.expiration, + resources: params.resourceAbilityRequests, + walletAddress: alice.wallet.address, + nonce: await devEnv.litNodeClient.getLatestBlockhash(), + litNodeClient: devEnv.litNodeClient, + }); + + const authSig = await generateAuthSig({ + signer: alice.wallet, + toSign, + }); + + return authSig; + }, + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ], + }, + }, + }); + + await pkpEthersWallet.init(); + + try { + const signature = await pkpEthersWallet.signMessage(alice.loveLetter); + console.log('✅ signature:', signature); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/packages/pkp-base/src/lib/pkp-base.ts b/packages/pkp-base/src/lib/pkp-base.ts index 9bcf6ea0e4..b81bd982ce 100644 --- a/packages/pkp-base/src/lib/pkp-base.ts +++ b/packages/pkp-base/src/lib/pkp-base.ts @@ -18,6 +18,7 @@ import { RPCUrls, AuthMethod, ExecuteJsResponse, + SessionSigsMap, } from '@lit-protocol/types'; import { LitNodeClient } from '@lit-protocol/lit-node-client'; import { publicKeyConvert } from 'secp256k1'; @@ -51,7 +52,7 @@ export class PKPBase { // @deprecated controllerAuthSig?: AuthSig; controllerAuthMethods?: AuthMethod[]; - controllerSessionSigs?: SessionSigs; + controllerSessionSigs?: SessionSigsMap; sessionSigsExpiration?: string; authContext?: AuthenticationProps; @@ -100,18 +101,22 @@ export class PKPBase { this.debug = prop.debug || false; this.setLitAction(prop); this.setLitActionJsParams(prop.litActionJsParams || {}); - this.litNodeClient = new LitNodeClient({ - litNetwork: prop.litNetwork ?? 'cayenne', - ...(prop.bootstrapUrls && - prop.litNetwork === 'custom' && { bootstrapUrls: prop.bootstrapUrls }), - ...(prop.bootstrapUrls && - prop.litNetwork == 'custom' && { minNodeCount: prop.minNodeCount }), - debug: this.debug, - // minNodeCount: - // prop.bootstrapUrls && prop.litNetwork == 'custom' - // ? prop.minNodeCount - // : defaultLitnodeClientConfig.minNodeCount, - }); + this.litNodeClient = + (prop.litNodeClient as LitNodeClient) || + new LitNodeClient({ + litNetwork: prop.litNetwork ?? 'cayenne', + ...(prop.bootstrapUrls && + prop.litNetwork === 'custom' && { + bootstrapUrls: prop.bootstrapUrls, + }), + ...(prop.bootstrapUrls && + prop.litNetwork == 'custom' && { minNodeCount: prop.minNodeCount }), + debug: this.debug, + // minNodeCount: + // prop.bootstrapUrls && prop.litNetwork == 'custom' + // ? prop.minNodeCount + // : defaultLitnodeClientConfig.minNodeCount, + }); } /** @@ -234,16 +239,14 @@ export class PKPBase { ); } - // Print deprecation warning for controllerSessionSigs - if (this.controllerSessionSigs) { - logError( - 'controllerSessionSigs is deprecated, please use authContext instead' - ); - } - - // Check auth context if provided + // Check if authContext is provided if (this.authContext) { - // It must have a valid client and getSessionSigsProps + // Try to assign litNodeClient to authContext.client if it's not already set and litNodeClient is available + if (!this.authContext.client && this.litNodeClient) { + this.authContext.client = this.litNodeClient; + } + + // Ensure authContext has a valid client and getSessionSigsProps if ( !(this.authContext.client instanceof LitNodeClientNodeJs) || !this.authContext.getSessionSigsProps @@ -266,6 +269,13 @@ export class PKPBase { * @throws {Error} - Throws an error if `pkpPubKey` is not provided, if `controllerAuthSig` or `controllerSessionSigs` is not provided, if `controllerSessionSigs` is not an object, if `executeJsArgs` does not have either `code` or `ipfsId`, or if an error occurs during the execution of the Lit action. */ async runLitAction(toSign: Uint8Array, sigName: string): Promise { + // -- validate executeJsArgs + if (this.litActionCode && this.litActionIPFS) { + return this.throwError( + 'litActionCode and litActionIPFS cannot exist at the same time' + ); + } + if (!this.litNodeClientReady) { await this.init(); } @@ -286,7 +296,6 @@ export class PKPBase { ...(this.litActionCode && { code: this.litActionCode }), ...(this.litActionIPFS && { ipfsId: this.litActionIPFS }), sessionSigs: controllerSessionSigs, - authMethods: this.authContext?.authMethods, jsParams: { ...{ toSign, @@ -359,28 +368,24 @@ export class PKPBase { this.validateAuthContext(); + const sessionSigsFromAuthContext = + await this.authContext?.client?.getSessionSigs({ + ...this.authContext.getSessionSigsProps, + }); + const controllerSessionSigs = - (await this.authContext?.client?.getSessionSigs( - this.authContext.getSessionSigsProps - )) || this.controllerSessionSigs; + sessionSigsFromAuthContext || this.controllerSessionSigs; + + if (!controllerSessionSigs) { + this.throwError('controllerSessionSigs is required'); + } try { - let sig; - if (controllerSessionSigs) { - sig = await this.litNodeClient.pkpSign({ - toSign, - pubKey: this.uncompressedPubKey, - authMethods: this.authContext?.authMethods ?? [], - sessionSigs: controllerSessionSigs, - }); - } else if (this.authContext?.authMethods) { - sig = await this.litNodeClient.pkpSign({ - toSign, - pubKey: this.uncompressedPubKey, - authMethods: this.authContext.authMethods, - sessionSigs: controllerSessionSigs!, - }); - } + const sig = await this.litNodeClient.pkpSign({ + toSign, + pubKey: this.uncompressedPubKey, + sessionSigs: controllerSessionSigs as SessionSigsMap, + }); if (!sig) { throw new Error('No signature returned'); diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index cbe20c15b6..92deae6447 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -272,7 +272,6 @@ export interface BaseJsonPkpSignRequest { export interface JsonPkpSignSdkParams extends BaseJsonPkpSignRequest { pubKey: string; sessionSigs: SessionSigsMap; - authMethods?: AuthMethod[]; } /** @@ -514,11 +513,6 @@ export interface JsonExecutionSdkParams { * the session signatures to use to authorize the user with the nodes */ sessionSigs: any; - - /** - * auth methods to resolve - */ - authMethods?: AuthMethod[]; } export interface JsonExecutionRequestTargetNode extends JsonExecutionRequest { @@ -1233,20 +1227,17 @@ export interface LitClientSessionManager { } export interface AuthenticationProps { - client: LitClientSessionManager; + client?: LitClientSessionManager; /** * This params is equivalent to the `getSessionSigs` params in the `litNodeClient` */ getSessionSigsProps: GetSessionSigsProps; - authMethods: AuthMethod[]; } export interface PKPBaseProp { - // -- required + litNodeClient?: ILitNodeClient; pkpPubKey: string; - - // -- optional rpc?: string; rpcs?: RPCUrls; sessionSigsExpiration?: string; @@ -1259,6 +1250,7 @@ export interface PKPBaseProp { litActionIPFS?: string; litActionJsParams?: any; provider?: Provider; + controllerSessionSigs?: SessionSigs; // -- soon to be deprecated /** @@ -1266,11 +1258,6 @@ export interface PKPBaseProp { */ controllerAuthMethods?: AuthMethod[]; - /** - * @deprecated - use authContext - */ - controllerSessionSigs?: SessionSigs; - /** * @deprecated - use authContext */ @@ -1285,8 +1272,10 @@ export interface RPCUrls { export type PKPEthersWalletProp = Omit< PKPBaseProp, - 'controllerAuthSig' | 'controllerAuthMethods' | 'controllerSessionSigs' ->; + 'controllerAuthSig' | 'controllerAuthMethods' +> & { + litNodeClient: ILitNodeClient; +}; export interface PKPCosmosWalletProp extends PKPBaseProp { addressPrefix: string | 'cosmos'; // bech32 address prefix (human readable part) (default: cosmos) From 9e713d2cffe3954ae5908c514d374132c65c9d0c Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 9 May 2024 19:21:46 +0100 Subject: [PATCH 129/263] fix: authContext litNodeClient --- .../testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts index 81ae3a5395..365b52d2ae 100644 --- a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSignWithAuthContext.ts @@ -24,6 +24,7 @@ export const testPkpEthersWithEoaSessionSigsToSignWithAuthContext = async ( pkpPubKey: alice.pkp.publicKey, litNodeClient: devEnv.litNodeClient, authContext: { + client: devEnv.litNodeClient, getSessionSigsProps: { authNeededCallback: async function ( params: AuthCallbackParams From b922f3458e0d109eeec40c6771ad98db586f433d Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 16:56:05 -0400 Subject: [PATCH 130/263] feat: most common least common support for la responses --- ...ocess-lit-action-response-strategy.spec.ts | 141 ++++++++++++++++++ .../process-lit-action-response-strategy.ts | 90 +++++++++++ .../src/lib/lit-node-client-nodejs.ts | 11 +- packages/types/src/lib/interfaces.ts | 14 +- packages/types/src/lib/types.ts | 2 + 5 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts new file mode 100644 index 0000000000..700b72836f --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts @@ -0,0 +1,141 @@ +import { NodeShare } from '@lit-protocol/types'; +import { processLitActionResponseStrategy } from './process-lit-action-response-strategy'; +import { assert } from 'console'; + +describe('processLitActionResponseStrategy', () => { + const litActionResponses: any[] = [ + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '{"hello":"world","res": "71"}', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '{"hello":"world","res":{}}', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"E90BAE64AFA7C571CE41BEF25FF771CA2F1BC20FC09A7762200552B30ACC0CDC"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '{"hello":"world","res":{}}', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"31977D4BE7F49C0CD97CC0756CCA3244A949EA7D591F79B64F324846507448CD"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '{"hello":"world","res":{}}', + logs: 'is_leader: true\nresponse: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"F21798A1A37CC86566EA0D751F37CC144774A1A8A4FCD5E6E64287690FB60119"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '{"hello":"world","res":{}}', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"7ECB0E020BED801905D3FE941751E4313086603BBBF21F1756832F02A6FBE567"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: '{"hello":"world","res":{}}', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + ]; + it('should find least common response', () => { + let resp = processLitActionResponseStrategy(litActionResponses, { + strategy: 'leastCommon', + }); + expect(resp.res).toBe('71'); + }); + + it('should find most common response', () => { + let resp = processLitActionResponseStrategy(litActionResponses, { + strategy: 'mostCommon', + }); + expect(resp.res).toBeDefined(); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts new file mode 100644 index 0000000000..2af766936e --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -0,0 +1,90 @@ +import { + LitActionResponseStrategy, + ResponseStrategy, + NodeShare, +} from '@lit-protocol/types'; +import { log, logError } from '@lit-protocol/misc'; + +/** + * Finds the most and least common object within an of objects array + * @param responses any[] + * @returns an object which contains both the least and most occuring item in the array + */ +const findFrequency = (responses: any[]): { min: any; max: any } => { + var maxEl = responses[0], + minEl = responses[0], + maxCount = 1, + minCount = 1; + for (var i = 0; i < responses.length; i++) { + var el = responses[i]; + if (responses[el] == null) responses[el] = 1; + else responses[el]++; + if (responses[el] > maxCount) { + maxEl = el; + maxCount = responses[el]; + } else if (responses[el] <= minCount) { + minEl = el; + minCount = responses[el]; + } + } + + return { min: minEl, max: maxEl }; +}; +export const processLitActionResponseStrategy = ( + responses: NodeShare[], + strategy: LitActionResponseStrategy +): any => { + const executionResponses = responses.map((resp) => { + return JSON.parse(resp.response); + }); + const copiedExecutionResponses = executionResponses.map((r) => { + return { ...r }; + }); + log( + 'filtered responses with frequency dist: ', + JSON.stringify(copiedExecutionResponses) + ); + if (strategy.strategy === 'custom') { + try { + if (strategy.customFilter) { + const customResponseFilterResult = + strategy?.customFilter(executionResponses); + return customResponseFilterResult; + } else { + logError( + 'Custom filter specified for response strategy but none found. using most common' + ); + } + } catch (e) { + logError( + 'Error while executing custom response filter, defaulting to most common', + (e as Error).toString() + ); + } + } + let respFrequency = findFrequency(copiedExecutionResponses); + for (let i = 0; i < executionResponses.length; i++) { + if (strategy?.strategy === 'leastCommon') { + if (copiedExecutionResponses[i] === respFrequency.min) { + log( + 'strategy found to be most common, taking most common response from execution results' + ); + return executionResponses[i]; + } + } else if (strategy?.strategy === 'mostCommon') { + if (copiedExecutionResponses[i] === respFrequency.max) { + log( + 'strategy found to be most common, taking most common response from execution results' + ); + return executionResponses[i]; + } + } else { + if (copiedExecutionResponses[i].leastPopular === respFrequency.min) { + log( + 'no strategy found, using least common response object from execution results' + ); + return executionResponses[i]; + } + } + } +}; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index e3935732b0..313620a74b 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -21,12 +21,12 @@ import { AuthMethodType, EITHER_TYPE, LIT_ACTION_IPFS_HASH, + LIT_CURVE, LIT_ENDPOINT, LIT_ERROR, LIT_SESSION_KEY_URI, LOCAL_STORAGE_KEYS, LitNetwork, - LIT_CURVE, } from '@lit-protocol/constants'; import { LitCore, composeLitUrl } from '@lit-protocol/core'; import { @@ -130,6 +130,7 @@ import { getClaims } from './helpers/get-claims'; import { normalizeArray } from './helpers/normalize-array'; import { parsePkpSignResponse } from './helpers/parse-pkp-sign-response'; import { getBlsSignatures } from './helpers/get-bls-signatures'; +import { processLitActionResponseStrategy } from './helpers/process-lit-action-response-strategy'; export class LitNodeClientNodeJs extends LitCore @@ -176,7 +177,6 @@ export class LitNodeClientNodeJs } const nonce = await this.getLatestBlockhash(); - const siweMessage = await createSiweMessageWithCapacityDelegation({ uri: 'lit:capability:delegation', litNodeClient: this, @@ -1192,6 +1192,12 @@ export class LitNodeClientNodeJs responseData ) as NodeShare; + const responseFromStrategy: any = processLitActionResponseStrategy( + responseData, + params.responseStrategy ?? { strategy: 'leastCommon' } + ); + mostCommonResponse.response = responseFromStrategy; + const isSuccess = mostCommonResponse.success; const hasSignedData = Object.keys(mostCommonResponse.signedData).length > 0; const hasClaimData = Object.keys(mostCommonResponse.claimData).length > 0; @@ -2306,6 +2312,7 @@ export class LitNodeClientNodeJs * ```ts * import { LitPKPResource, LitActionResource } from "@lit-protocol/auth-helpers"; import { LitAbility } from "@lit-protocol/types"; +import { logWithRequestId } from '../../../misc/src/lib/misc'; const resourceAbilityRequests = [ { diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index bad112b05c..1026c912f6 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -13,12 +13,12 @@ import { LIT_NETWORKS_KEYS, LitContractContext, LitContractResolverContext, + ResponseStrategy, SolRpcConditions, SymmetricKey, UnifiedAccessControlConditions, } from './types'; import { ISessionCapabilityObject, LitResourceAbilityRequest } from './models'; - /** ---------- Access Control Conditions Interfaces ---------- */ export interface ABIParams { @@ -489,6 +489,12 @@ export interface JsonEncryptionRetrieveRequest extends JsonAccsRequest { toDecrypt: string; } +export interface LitActionResponseStrategy { + strategy: ResponseStrategy; + customFilter?: ( + responses: Record[] + ) => Record; +} export interface JsonExecutionSdkParamsTargetNode extends JsonExecutionSdkParams { targetNodeRange: number; @@ -519,6 +525,12 @@ export interface JsonExecutionSdkParams { * auth methods to resolve */ authMethods?: AuthMethod[]; + + /** + * a strategy for proccessing `reponse` objects returned from the + * Lit Action execution context + */ + responseStrategy?: LitActionResponseStrategy; } export interface JsonExecutionRequestTargetNode extends JsonExecutionRequest { diff --git a/packages/types/src/lib/types.ts b/packages/types/src/lib/types.ts index 3726672eec..2cbba01483 100644 --- a/packages/types/src/lib/types.ts +++ b/packages/types/src/lib/types.ts @@ -245,3 +245,5 @@ export type LitContractResolverContext = { contractContext?: LitContractContext; provider?: ethers.providers.JsonRpcProvider; }; + +export type ResponseStrategy = 'leastCommon' | 'mostCommon' | 'custom'; From ae20daa84e1084565f090c284a1b0f85cd9ad06a Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 16:57:13 -0400 Subject: [PATCH 131/263] fmt --- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- tsconfig.json | 17 +++++++++++++---- 27 files changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index efaa02b8eb..867f3ea362 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 2809895bc0..0dd92f6441 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 2386457e74..ca2e0056d5 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 1e2d1f0389..2be81894f8 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/package.json b/packages/constants/package.json index 4b1881181f..a7420c1e05 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 044d97ae47..3a8f4b5889 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 86700e68b5..d99c2b2ef3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/crypto/package.json b/packages/crypto/package.json index d680c0b241..016cca9105 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index 6fcd5713bd..b58823787b 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/encryption/package.json b/packages/encryption/package.json index d786daf1e8..d2fab11731 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index 33ecc1b9c2..b9a7990769 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 8d177b809e..1e85f9dd29 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index a4053f0697..5b03324499 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/logger/package.json b/packages/logger/package.json index b3a4520aa8..c199ce3293 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index c405504013..34eb65c61d 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc/package.json b/packages/misc/package.json index 58b18cfe8d..25917a6a3b 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 5acbdba213..089d70fe07 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 4b0af6fb77..72b5e19323 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 5e8445f437..d09180a573 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index c69e18ab9d..8e3cdd1dd9 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 0670776480..12253d0f23 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 137650df97..727e238775 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 9096e55793..ce3b4a0c77 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 6ed7c564dd..af3aad5136 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/types/package.json b/packages/types/package.json index 90d7b2094b..daf515d3eb 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index e98b54d1e7..42d20158f1 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d79d1c4238..e8f4e19b50 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,15 +10,24 @@ "importHelpers": true, "target": "ES2020", "module": "ES2020", - "lib": ["ES2020", "dom", "ES2021.String"], + "lib": [ + "ES2020", + "dom", + "ES2021.String" + ], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "paths": { - "@lit-protocol/*": ["packages/*/src"] + "@lit-protocol/*": [ + "packages/*/src" + ] } }, - "exclude": ["node_modules", "tmp"] -} + "exclude": [ + "node_modules", + "tmp" + ] +} \ No newline at end of file From 589525aa6a4d87f142df37c76f76450e15bf9379 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 17:11:32 -0400 Subject: [PATCH 132/263] chore: fmt --- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- tsconfig.json | 17 ++++------------- 27 files changed, 30 insertions(+), 39 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 867f3ea362..efaa02b8eb 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 0dd92f6441..2809895bc0 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index ca2e0056d5..2386457e74 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 2be81894f8..1e2d1f0389 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index a7420c1e05..4b1881181f 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 3a8f4b5889..044d97ae47 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/core/package.json b/packages/core/package.json index d99c2b2ef3..86700e68b5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 016cca9105..d680c0b241 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index b58823787b..6fcd5713bd 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index d2fab11731..d786daf1e8 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index b9a7990769..33ecc1b9c2 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 1e85f9dd29..8d177b809e 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index 5b03324499..a4053f0697 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index c199ce3293..b3a4520aa8 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 34eb65c61d..c405504013 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 25917a6a3b..58b18cfe8d 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 089d70fe07..5acbdba213 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 72b5e19323..4b0af6fb77 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index d09180a573..5e8445f437 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 8e3cdd1dd9..c69e18ab9d 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 12253d0f23..0670776480 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 727e238775..137650df97 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index ce3b4a0c77..9096e55793 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index af3aad5136..6ed7c564dd 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index daf515d3eb..90d7b2094b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 42d20158f1..e98b54d1e7 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-alpha.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index e8f4e19b50..d79d1c4238 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,24 +10,15 @@ "importHelpers": true, "target": "ES2020", "module": "ES2020", - "lib": [ - "ES2020", - "dom", - "ES2021.String" - ], + "lib": ["ES2020", "dom", "ES2021.String"], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "paths": { - "@lit-protocol/*": [ - "packages/*/src" - ] + "@lit-protocol/*": ["packages/*/src"] } }, - "exclude": [ - "node_modules", - "tmp" - ] -} \ No newline at end of file + "exclude": ["node_modules", "tmp"] +} From ffa30790063c976f833bb9075ff7a64294e49ebc Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 17:49:49 -0400 Subject: [PATCH 133/263] feat: add customFilter testcase --- .../pocess-lit-action-response-strategy.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts index 700b72836f..d980621e82 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts @@ -138,4 +138,16 @@ describe('processLitActionResponseStrategy', () => { }); expect(resp.res).toBeDefined(); }); + + it('should find most common response', () => { + let resp = processLitActionResponseStrategy(litActionResponses, { + strategy: 'custom', + customFilter: (responses) => { + return responses[0]; + } + }); + expect(resp).toBeDefined(); + expect(resp.res).toBeDefined(); + expect(resp.res).toBe('71'); + }); }); From 01c86c8dac1dec266bd88d055f4ca27a831e02db Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 18:54:46 -0400 Subject: [PATCH 134/263] ref: use array sort / filter to processes responses as strings over objects --- ...ocess-lit-action-response-strategy.spec.ts | 7 +- .../process-lit-action-response-strategy.ts | 73 ++++++++----------- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts index d980621e82..8bc530678c 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts @@ -129,14 +129,14 @@ describe('processLitActionResponseStrategy', () => { let resp = processLitActionResponseStrategy(litActionResponses, { strategy: 'leastCommon', }); - expect(resp.res).toBe('71'); + expect(resp).toBe('{"hello":"world","res": "71"}'); }); it('should find most common response', () => { let resp = processLitActionResponseStrategy(litActionResponses, { strategy: 'mostCommon', }); - expect(resp.res).toBeDefined(); + expect(resp).toBe('{"hello":"world","res":{}}'); }); it('should find most common response', () => { @@ -147,7 +147,6 @@ describe('processLitActionResponseStrategy', () => { } }); expect(resp).toBeDefined(); - expect(resp.res).toBeDefined(); - expect(resp.res).toBe('71'); + expect(resp).toBe('{"hello":"world","res": "71"}'); }); }); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts index 2af766936e..bb542dd10c 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -10,35 +10,27 @@ import { log, logError } from '@lit-protocol/misc'; * @param responses any[] * @returns an object which contains both the least and most occuring item in the array */ -const findFrequency = (responses: any[]): { min: any; max: any } => { - var maxEl = responses[0], - minEl = responses[0], - maxCount = 1, - minCount = 1; - for (var i = 0; i < responses.length; i++) { - var el = responses[i]; - if (responses[el] == null) responses[el] = 1; - else responses[el]++; - if (responses[el] > maxCount) { - maxEl = el; - maxCount = responses[el]; - } else if (responses[el] <= minCount) { - minEl = el; - minCount = responses[el]; - } - } +const findFrequency = (responses: string[]): { min: any; max: any } => { + const sorted = responses + .sort( + (a: any, b: any) => + responses.filter((v: any) => v === a).length - + responses.filter((v: any) => v === b).length + ); - return { min: minEl, max: maxEl }; + return { min: sorted[0], max: sorted[sorted?.length -1] }; }; + export const processLitActionResponseStrategy = ( responses: NodeShare[], strategy: LitActionResponseStrategy ): any => { - const executionResponses = responses.map((resp) => { - return JSON.parse(resp.response); + const executionResponses = responses.map((nodeResp) => { + return nodeResp.response; }); + const copiedExecutionResponses = executionResponses.map((r) => { - return { ...r }; + return "" +r; }); log( 'filtered responses with frequency dist: ', @@ -62,29 +54,24 @@ export const processLitActionResponseStrategy = ( ); } } + let respFrequency = findFrequency(copiedExecutionResponses); - for (let i = 0; i < executionResponses.length; i++) { - if (strategy?.strategy === 'leastCommon') { - if (copiedExecutionResponses[i] === respFrequency.min) { - log( - 'strategy found to be most common, taking most common response from execution results' - ); - return executionResponses[i]; - } - } else if (strategy?.strategy === 'mostCommon') { - if (copiedExecutionResponses[i] === respFrequency.max) { - log( - 'strategy found to be most common, taking most common response from execution results' - ); - return executionResponses[i]; - } - } else { - if (copiedExecutionResponses[i].leastPopular === respFrequency.min) { - log( - 'no strategy found, using least common response object from execution results' - ); - return executionResponses[i]; - } + if (strategy?.strategy === 'leastCommon') { + log( + 'strategy found to be most common, taking most common response from execution results' + ); + return respFrequency.min; + } else if (strategy?.strategy === 'mostCommon') { + log( + 'strategy found to be most common, taking most common response from execution results' + ); + return respFrequency.max; + } else { + if (copiedExecutionResponses[i] === respFrequency.min) { + log( + 'no strategy found, using least common response object from execution results' + ); + respFrequency.min; } } }; From c7ea1218b58d33345c701f7f70c746d6ad2926d3 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 18:56:11 -0400 Subject: [PATCH 135/263] chore: fmt --- ...ocess-lit-action-response-strategy.spec.ts | 2 +- .../process-lit-action-response-strategy.ts | 33 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts index 8bc530678c..1134261a41 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts @@ -144,7 +144,7 @@ describe('processLitActionResponseStrategy', () => { strategy: 'custom', customFilter: (responses) => { return responses[0]; - } + }, }); expect(resp).toBeDefined(); expect(resp).toBe('{"hello":"world","res": "71"}'); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts index bb542dd10c..dcf793094d 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -11,14 +11,13 @@ import { log, logError } from '@lit-protocol/misc'; * @returns an object which contains both the least and most occuring item in the array */ const findFrequency = (responses: string[]): { min: any; max: any } => { - const sorted = responses - .sort( - (a: any, b: any) => - responses.filter((v: any) => v === a).length - - responses.filter((v: any) => v === b).length - ); + const sorted = responses.sort( + (a: any, b: any) => + responses.filter((v: any) => v === a).length - + responses.filter((v: any) => v === b).length + ); - return { min: sorted[0], max: sorted[sorted?.length -1] }; + return { min: sorted[0], max: sorted[sorted?.length - 1] }; }; export const processLitActionResponseStrategy = ( @@ -30,7 +29,7 @@ export const processLitActionResponseStrategy = ( }); const copiedExecutionResponses = executionResponses.map((r) => { - return "" +r; + return '' + r; }); log( 'filtered responses with frequency dist: ', @@ -54,18 +53,18 @@ export const processLitActionResponseStrategy = ( ); } } - + let respFrequency = findFrequency(copiedExecutionResponses); if (strategy?.strategy === 'leastCommon') { - log( - 'strategy found to be most common, taking most common response from execution results' - ); - return respFrequency.min; + log( + 'strategy found to be most common, taking most common response from execution results' + ); + return respFrequency.min; } else if (strategy?.strategy === 'mostCommon') { - log( - 'strategy found to be most common, taking most common response from execution results' - ); - return respFrequency.max; + log( + 'strategy found to be most common, taking most common response from execution results' + ); + return respFrequency.max; } else { if (copiedExecutionResponses[i] === respFrequency.min) { log( From e51b9ce39472cbd621a7779fdbed372788a33c9f Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 9 May 2024 18:57:04 -0400 Subject: [PATCH 136/263] ref: remove condition --- .../src/lib/helpers/process-lit-action-response-strategy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts index dcf793094d..70aff1266f 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -66,11 +66,9 @@ export const processLitActionResponseStrategy = ( ); return respFrequency.max; } else { - if (copiedExecutionResponses[i] === respFrequency.min) { log( 'no strategy found, using least common response object from execution results' ); respFrequency.min; - } } }; From 50ff1a3ddb507c86b702a35a9deb13a98293f56a Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 08:43:11 -0400 Subject: [PATCH 137/263] chore: fmt --- .../lib/helpers/process-lit-action-response-strategy.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts index 70aff1266f..8cbc3e8922 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -66,9 +66,9 @@ export const processLitActionResponseStrategy = ( ); return respFrequency.max; } else { - log( - 'no strategy found, using least common response object from execution results' - ); - respFrequency.min; + log( + 'no strategy found, using least common response object from execution results' + ); + respFrequency.min; } }; From 96deffa350f28448b174beb840ee0ae7337aed37 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 10:01:28 -0400 Subject: [PATCH 138/263] ref: fix cayenne contexts --- packages/core/src/lib/lit-core.ts | 3 ++- .../src/lib/lit-node-client-nodejs.ts | 18 ++---------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 1b4fa19832..34ae2c4877 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -222,7 +222,8 @@ export class LitCore { setNewConfig = async (): Promise => { if ( this.config.litNetwork === LitNetwork.Manzano || - this.config.litNetwork === LitNetwork.Habanero + this.config.litNetwork === LitNetwork.Habanero || + this.config.litNetwork === LitNetwork.Cayenne ) { const minNodeCount = await LitContracts.getMinNodeCount( this.config.litNetwork diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index e3935732b0..3313db08ca 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2434,25 +2434,11 @@ const resourceAbilityRequests = [ const signatures: SessionSigsMap = {}; this.connectedNodes.forEach((nodeAddress: string) => { - let toSign: SessionSigningTemplate; - - // FIXME: We need this reformatting because the Cayenne network is not able to handle the node address as a URL. - // We are converting back - // from: http://207.244.70.36:7474 - // to: 127.0.0.1:7474 - if (this.config.litNetwork === LitNetwork.Cayenne) { - const url = new URL(nodeAddress); - const newNodeAddress = `127.0.0.1:${url.port}`; - toSign = { - ...signingTemplate, - nodeAddress: newNodeAddress, - }; - } else { - toSign = { + const toSign: SessionSigningTemplate = { ...signingTemplate, nodeAddress, }; - } + const signedMessage = JSON.stringify(toSign); From b0018250a9a6aa95a14ad41d8c34ca4c8bd53de4 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 10:11:39 -0400 Subject: [PATCH 139/263] chore: fmt --- .../src/lib/lit-node-client-nodejs.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 3313db08ca..0175f8cc01 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2435,10 +2435,9 @@ const resourceAbilityRequests = [ this.connectedNodes.forEach((nodeAddress: string) => { const toSign: SessionSigningTemplate = { - ...signingTemplate, - nodeAddress, - }; - + ...signingTemplate, + nodeAddress, + }; const signedMessage = JSON.stringify(toSign); From 7428a15455d46d0b49374ac78dd33868203b3cc5 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 10:22:50 -0400 Subject: [PATCH 140/263] chore: fmt --- packages/core/src/lib/lit-core.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 34ae2c4877..fe67acd536 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -325,6 +325,13 @@ export class LitCore { this.config.contractContext, this.config.rpcUrl! ); + } else { + return throwError({ + message: + 'Unsuported network has been provided please use a "litNetwork" option which is supported ("cayenne", "habanero", "manzano")', + errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, + errorCode: LIT_ERROR.INVALID_PARAM_TYPE.code, + }); } }; From 0c579eb5ee0ab394b44996bccc196c79d22ff479 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 10:01:28 -0400 Subject: [PATCH 141/263] ref: fix cayenne contexts --- packages/core/src/lib/lit-core.ts | 3 ++- .../src/lib/lit-node-client-nodejs.ts | 18 ++---------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index f59e2cd970..4fcdb3e785 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -222,7 +222,8 @@ export class LitCore { setNewConfig = async (): Promise => { if ( this.config.litNetwork === LitNetwork.Manzano || - this.config.litNetwork === LitNetwork.Habanero + this.config.litNetwork === LitNetwork.Habanero || + this.config.litNetwork === LitNetwork.Cayenne ) { const minNodeCount = await LitContracts.getMinNodeCount( this.config.litNetwork diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d080b87184..583025651e 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2434,25 +2434,11 @@ const resourceAbilityRequests = [ const signatures: SessionSigsMap = {}; this.connectedNodes.forEach((nodeAddress: string) => { - let toSign: SessionSigningTemplate; - - // FIXME: We need this reformatting because the Cayenne network is not able to handle the node address as a URL. - // We are converting back - // from: http://207.244.70.36:7474 - // to: 127.0.0.1:7474 - if (this.config.litNetwork === LitNetwork.Cayenne) { - const url = new URL(nodeAddress); - const newNodeAddress = `127.0.0.1:${url.port}`; - toSign = { - ...signingTemplate, - nodeAddress: newNodeAddress, - }; - } else { - toSign = { + const toSign: SessionSigningTemplate = { ...signingTemplate, nodeAddress, }; - } + const signedMessage = JSON.stringify(toSign); From 23033f9a9f54adda820ca379b8dc72dd3e97ade4 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 10:22:50 -0400 Subject: [PATCH 142/263] chore: fmt --- packages/core/src/lib/lit-core.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 4fcdb3e785..2e59a4f210 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -365,6 +365,13 @@ export class LitCore { this.config.contractContext, this.config.rpcUrl! ); + } else { + return throwError({ + message: + 'Unsuported network has been provided please use a "litNetwork" option which is supported ("cayenne", "habanero", "manzano")', + errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, + errorCode: LIT_ERROR.INVALID_PARAM_TYPE.code, + }); } }; From d2c258e57b46e33f1c270a82d8f1c8001346471a Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 10:11:39 -0400 Subject: [PATCH 143/263] chore: fmt --- .../src/lib/lit-node-client-nodejs.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 583025651e..d431eb855a 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2435,10 +2435,9 @@ const resourceAbilityRequests = [ this.connectedNodes.forEach((nodeAddress: string) => { const toSign: SessionSigningTemplate = { - ...signingTemplate, - nodeAddress, - }; - + ...signingTemplate, + nodeAddress, + }; const signedMessage = JSON.stringify(toSign); From ccc4952168c9e73c376c3d53219d35b96e261eb2 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 10 May 2024 16:36:33 +0100 Subject: [PATCH 144/263] feat(tinny): show errors when no tests found --- local-tests/setup/tinny-operations.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-operations.ts b/local-tests/setup/tinny-operations.ts index 3b9a0bbb19..41439a18fa 100644 --- a/local-tests/setup/tinny-operations.ts +++ b/local-tests/setup/tinny-operations.ts @@ -126,6 +126,12 @@ export const runTestsParallel = async ({ filters.some((filter) => testName.includes(filter)) ); + if (!testsToRun || testsToRun.length <= 0) { + throw new Error( + '❌ No tests to run. You might have provided an invalid filter or no tests are available.' + ); + } + const testPromises = testsToRun.map( async ([testName, testFunction], testIndex) => { const maxAttempts = devEnv.processEnvs.MAX_ATTEMPTS; @@ -168,7 +174,7 @@ export const runTestsParallel = async ({ testIndex + 1 }. ${testName} - Failed after ${maxAttempts} attempts (${timeTaken} ms)\x1b[0m` ); - console.error(`\x1b[31mError:\x1b[90m ${error}\x1b[0m`); + console.error(`\x1b[31m❌Error:\x1b[90m ${error}\x1b[0m`); return `${testName} (Failed in ${timeTaken} ms) - Error: ${error}`; } } From d72697f61b84ad98ad744dd8cf7d01f35f1c3f08 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 10 May 2024 16:38:17 +0100 Subject: [PATCH 145/263] feat: add pkpSessionSigs & litActionSessionSigs tests for pkpEthers and migrated old tests to .ts --- .../test-pkp-ethers-handler-sign-tx.mjs | 105 ----------------- ...-pkp-ethers-handler-sign-typed-data-v1.mjs | 72 ------------ ...-pkp-ethers-handler-sign-typed-data-v3.mjs | 102 ---------------- ...-pkp-ethers-handler-sign-typed-data-v4.mjs | 108 ----------------- ...est-pkp-ethers-handler-sign-typed-data.mjs | 93 --------------- .../test-pkp-ethers-sign-typed-data.mjs | 86 -------------- local-tests/test.ts | 74 +++++++++++- ...sWithEoaSessionSigsToEthSignTransaction.ts | 109 ++++++++++++++++++ ...ersWithEoaSessionSigsToEthSignTypedData.ts | 95 +++++++++++++++ ...ithEoaSessionSigsToEthSignTypedDataUtil.ts | 92 +++++++++++++++ ...sWithEoaSessionSigsToEthSignTypedDataV1.ts | 77 +++++++++++++ ...sWithEoaSessionSigsToEthSignTypedDataV3.ts | 105 +++++++++++++++++ ...sWithEoaSessionSigsToEthSignTypedDataV4.ts | 105 +++++++++++++++++ ...testPkpEthersWithEoaSessionSigsToSendTx.ts | 2 +- ...EthersWithLitActionSessionSigsToEthSign.ts | 60 ++++++++++ ...itActionSessionSigsToEthSignTransaction.ts | 109 ++++++++++++++++++ ...hLitActionSessionSigsToEthSignTypedData.ts | 95 +++++++++++++++ ...ActionSessionSigsToEthSignTypedDataUtil.ts | 87 ++++++++++++++ ...itActionSessionSigsToEthSignTypedDataV1.ts | 77 +++++++++++++ ...itActionSessionSigsToEthSignTypedDataV3.ts | 104 +++++++++++++++++ ...itActionSessionSigsToEthSignTypedDataV4.ts | 105 +++++++++++++++++ ...sWithLitActionSessionSigsToPersonalSign.ts | 61 ++++++++++ ...pEthersWithLitActionSessionSigsToSendTx.ts | 62 ++++++++++ ...rsWithLitActionSessionSigsToSignMessage.ts | 32 +++++ ...estPkpEthersWithPkpSessionSigsToEthSign.ts | 60 ++++++++++ ...sWithPkpSessionSigsToEthSignTransaction.ts | 109 ++++++++++++++++++ ...ersWithPkpSessionSigsToEthSignTypedData.ts | 95 +++++++++++++++ ...ithPkpSessionSigsToEthSignTypedDataUtil.ts | 88 ++++++++++++++ ...sWithPkpSessionSigsToEthSignTypedDataV1.ts | 77 +++++++++++++ ...sWithPkpSessionSigsToEthSignTypedDataV3.ts | 104 +++++++++++++++++ ...sWithPkpSessionSigsToEthSignTypedDataV4.ts | 105 +++++++++++++++++ ...pEthersWithPkpSessionSigsToPersonalSign.ts | 61 ++++++++++ ...testPkpEthersWithPkpSessionSigsToSendTx.ts | 64 ++++++++++ ...kpEthersWithPkpSessionSigsToSignMessage.ts | 32 +++++ 34 files changed, 2239 insertions(+), 573 deletions(-) delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-tx.mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v1.mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v3.mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v4.mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data.mjs delete mode 100644 e2e-nodejs/group-pkp-ethers/test-pkp-ethers-sign-typed-data.mjs create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedData.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3.ts create mode 100644 local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSign.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToPersonalSign.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToSendTx.ts create mode 100644 local-tests/tests/testPkpEthersWithLitActionSessionSigsToSignMessage.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSign.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedData.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToPersonalSign.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts create mode 100644 local-tests/tests/testPkpEthersWithPkpSessionSigsToSignMessage.ts diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-tx.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-tx.mjs deleted file mode 100644 index 64a399d559..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-tx.mjs +++ /dev/null @@ -1,105 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { AuthMethodType, ProviderType } from '@lit-protocol/constants'; -import { client } from '../00-setup.mjs'; -export async function main() { - // ==================== Setup ==================== - const authMethod = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }; - - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthMethods: [authMethod], - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - // Transaction to sign and send - const from = globalThis.LitCI.PKP_INFO.ethAddress; - const to = globalThis.LitCI.PKP_INFO.ethAddress; - const gasLimit = ethers.BigNumber.from('21000'); - const value = ethers.BigNumber.from('0'); - const data = '0x'; - - // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) - const tx = { - from: from, - to: to, - gasLimit, - value, - data, - }; - - // eth_sendTransaction parameters - // Transaction - Object - // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sendTransaction - // A serialized form of the whole transaction - const rawSignedTx = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_signTransaction', - params: [tx], - }, - }); - - const parsedTransaction = ethers.utils.parseTransaction(rawSignedTx); - - const signature = ethers.utils.joinSignature({ - r: parsedTransaction.r, - s: parsedTransaction.s, - v: parsedTransaction.v, - }); - - const rawTx = { - nonce: parsedTransaction.nonce, - gasPrice: parsedTransaction.gasPrice, - gasLimit: parsedTransaction.gasLimit, - to: parsedTransaction.to, - value: parsedTransaction.value, - data: parsedTransaction.data, - chainId: parsedTransaction.chainId, // Include chainId if the transaction is EIP-155 - }; - - const txHash = ethers.utils.keccak256( - ethers.utils.serializeTransaction(rawTx) - ); - - const { v, r, s } = parsedTransaction; - - const recoveredAddress = ethers.utils.recoverAddress(txHash, { r, s, v }); - - // ==================== Post-Validation ==================== - if (!parsedTransaction) { - return fail('parsedTransaction should not be null'); - } - - if (signature.length !== 132) { - return fail( - `signature should be 132 characters long, got ${signature.length}` - ); - } - - if ( - recoveredAddress.toLowerCase() !== - globalThis.LitCI.PKP_INFO.ethAddress.toLowerCase() - ) { - return fail( - `recoveredAddres should be ${globalThis.LitCI.PKP_INFO.ethAddress}, got ${recoveredAddress}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to sign tx'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v1.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v1.mjs deleted file mode 100644 index e687a03ff8..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v1.mjs +++ /dev/null @@ -1,72 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; -import { - SignTypedDataVersion, - recoverTypedSignature, -} from '@metamask/eth-sig-util'; - -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - const msgParams = [ - { - type: 'string', - name: 'Message', - value: 'Hi, Alice!', - }, - { - type: 'uint32', - name: 'A number', - value: '1337', - }, - ]; - - const signature = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_signTypedData_v1', - params: [msgParams, globalThis.LitCI.PKP_INFO.ethAddress], - }, - }); - - const signatureBytes = ethers.utils.arrayify(signature); - - const recoveredAddr = recoverTypedSignature({ - data: msgParams, - signature: signatureBytes, - version: SignTypedDataVersion.V1, - }); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if ( - recoveredAddr.toLowerCase() !== - globalThis.LitCI.PKP_INFO.ethAddress.toLowerCase() - ) { - return fail( - `recoveredAddr ${recoveredAddr} should be ${LITCONFIG.PKP_ETH_ADDRESS}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to eth_signTypedData_v1'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v3.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v3.mjs deleted file mode 100644 index c338b342ca..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v3.mjs +++ /dev/null @@ -1,102 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; -import { - SignTypedDataVersion, - recoverTypedSignature, -} from '@metamask/eth-sig-util'; - -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - const msgParams = { - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallet', type: 'address' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person' }, - { name: 'contents', type: 'string' }, - ], - }, - primaryType: 'Mail', - domain: { - name: 'Ether Mail', - version: '1', - chainId: 80001, - verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', - }, - message: { - from: { - name: 'Cow', - wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', - }, - to: { - name: 'Bob', - wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', - }, - contents: 'Hello, Bob!', - }, - }; - - const signature = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_signTypedData_v3', - params: [globalThis.LitCI.PKP_INFO.ethAddress, JSON.stringify(msgParams)], - }, - }); - - const signatureBytes = ethers.utils.arrayify(signature); - - const recoveredAddr = recoverTypedSignature({ - data: { - types: msgParams.types, - domain: msgParams.domain, - primaryType: msgParams.primaryType, - message: msgParams.message, - }, - signature: signature, - version: SignTypedDataVersion.V3, - }); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if ( - recoveredAddr.toLowerCase() !== - globalThis.LitCI.PKP_INFO.ethAddress.toLowerCase() - ) { - return fail( - `recoveredAddr ${recoveredAddr} should be ${LITCONFIG.PKP_ETH_ADDRESS}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to eth_signTypedData_v3'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v4.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v4.mjs deleted file mode 100644 index 11d83cdd96..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data-v4.mjs +++ /dev/null @@ -1,108 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; -import { - SignTypedDataVersion, - recoverTypedSignature, -} from '@metamask/eth-sig-util'; - -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - // Typed data to sign - // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1155 - const msgParams = { - domain: { - chainId: 80001, - name: 'Ether Mail', - verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', - version: '1', - }, - message: { - contents: 'Hello, Bob!', - from: { - name: 'Cow', - wallets: [ - '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', - '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', - ], - }, - to: [ - { - name: 'Bob', - wallets: [ - '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', - '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', - '0xB0B0b0b0b0b0B000000000000000000000000000', - ], - }, - ], - }, - primaryType: 'Mail', - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person[]' }, - { name: 'contents', type: 'string' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallets', type: 'address[]' }, - ], - }, - }; - - const signature = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_signTypedData_v4', - params: [globalThis.LitCI.PKP_INFO.ethAddress, JSON.stringify(msgParams)], - }, - }); - - const signatureBytes = ethers.utils.arrayify(signature); - - const recoveredAddr = recoverTypedSignature({ - data: msgParams, - signature: signature, - version: SignTypedDataVersion.V4, - }); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if ( - recoveredAddr.toLowerCase() !== - globalThis.LitCI.PKP_INFO.ethAddress.toLowerCase() - ) { - return fail( - `recoveredAddr ${recoveredAddr} should be ${LITCONFIG.PKP_ETH_ADDRESS}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to eth_signTypedData_v4'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data.mjs deleted file mode 100644 index b9ab3621cc..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-handler-sign-typed-data.mjs +++ /dev/null @@ -1,93 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 - const msgParams = { - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallet', type: 'address' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person' }, - { name: 'contents', type: 'string' }, - ], - }, - primaryType: 'Mail', - domain: { - name: 'Ether Mail', - version: '1', - chainId: 80001, - verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', - }, - message: { - from: { - name: 'Cow', - wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', - }, - to: { - name: 'Bob', - wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', - }, - contents: 'Hello, Bob!', - }, - }; - - const signature = await ethRequestHandler({ - signer: pkpEthersWallet, - payload: { - method: 'eth_signTypedData', - params: [globalThis.LitCI.PKP_INFO.ethAddress, msgParams], - }, - }); - - // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData - const recoveredAddr = ethers.utils.verifyTypedData( - msgParams.domain, - { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, - msgParams.message, - signature - ); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if ( - recoveredAddr.toLowerCase() !== - globalThis.LitCI.PKP_INFO.ethAddress.toLowerCase() - ) { - return fail( - `recoveredAddr ${recoveredAddr} should be ${LITCONFIG.PKP_ETH_ADDRESS}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to eth_signTypedData'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-sign-typed-data.mjs b/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-sign-typed-data.mjs deleted file mode 100644 index d8f14b9d7b..0000000000 --- a/e2e-nodejs/group-pkp-ethers/test-pkp-ethers-sign-typed-data.mjs +++ /dev/null @@ -1,86 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { signTypedData } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; -import { client } from '../00-setup.mjs'; -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - await pkpEthersWallet.init(); - - // ==================== Test Logic ==================== - // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 - const msgParams = { - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallet', type: 'address' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person' }, - { name: 'contents', type: 'string' }, - ], - }, - primaryType: 'Mail', - domain: { - name: 'Ether Mail', - version: '1', - chainId: 80001, - verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', - }, - message: { - from: { - name: 'Cow', - wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', - }, - to: { - name: 'Bob', - wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', - }, - contents: 'Hello, Bob!', - }, - }; - - const signature = await signTypedData(pkpEthersWallet, msgParams); - - const recoveredAddr = ethers.utils.verifyTypedData( - msgParams.domain, - { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, - msgParams.message, - signature - ); - - // ==================== Post-Validation ==================== - if (signature.length !== 132) { - return fail('signature should be 132 characters long'); - } - - if ( - recoveredAddr.toLowerCase() !== - globalThis.LitCI.PKP_INFO.ethAddress.toLowerCase() - ) { - return fail( - `recoveredAddr "${recoveredAddr}" should be ${LITCONFIG.PKP_ETH_ADDRESS}` - ); - } - - // ==================== Success ==================== - return success('PKPEthersWallet should be able to sign typed data'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/local-tests/test.ts b/local-tests/test.ts index 240710aefe..255dabebb6 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -51,6 +51,33 @@ import { testPkpEthersWithEoaSessionSigsToSignWithAuthContext } from './tests/te import { testPkpEthersWithEoaSessionSigsToEthSign } from './tests/testPkpEthersWithEoaSessionSigsToEthSign'; import { testPkpEthersWithEoaSessionSigsToPersonalSign } from './tests/testPkpEthersWithEoaSessionSigsToPersonalSign'; import { testPkpEthersWithEoaSessionSigsToSendTx } from './tests/testPkpEthersWithEoaSessionSigsToSendTx'; +import { testPkpEthersWithPkpSessionSigsToSignMessage } from './tests/testPkpEthersWithPkpSessionSigsToSignMessage'; +import { testPkpEthersWithPkpSessionSigsToEthSign } from './tests/testPkpEthersWithPkpSessionSigsToEthSign'; +import { testPkpEthersWithPkpSessionSigsToPersonalSign } from './tests/testPkpEthersWithPkpSessionSigsToPersonalSign'; +import { testPkpEthersWithPkpSessionSigsToSendTx } from './tests/testPkpEthersWithPkpSessionSigsToSendTx'; +import { testPkpEthersWithEoaSessionSigsToEthSignTransaction } from './tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction'; + +import { testPkpEthersWithPkpSessionSigsToEthSignTransaction } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction'; +import { testPkpEthersWithLitActionSessionSigsToEthSignTransaction } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction'; +import { testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1 } from './tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1'; +import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1 } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1'; +import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1 } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1'; +import { testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3 } from './tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3'; +import { testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4 } from './tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4'; +import { testPkpEthersWithEoaSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithEoaSessionSigsToEthSignTypedData'; +import { testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil'; +import { testPkpEthersWithLitActionSessionSigsToSignMessage } from './tests/testPkpEthersWithLitActionSessionSigsToSignMessage'; +import { testPkpEthersWithLitActionSessionSigsToEthSign } from './tests/testPkpEthersWithLitActionSessionSigsToEthSign'; +import { testPkpEthersWithLitActionSessionSigsToPersonalSign } from './tests/testPkpEthersWithLitActionSessionSigsToPersonalSign'; +import { testPkpEthersWithLitActionSessionSigsToSendTx } from './tests/testPkpEthersWithLitActionSessionSigsToSendTx'; +import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3 } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3'; +import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3 } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3'; +import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4 } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4'; +import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4 } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4'; +import { testPkpEthersWithPkpSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedData'; +import { testPkpEthersWithLitActionSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData'; +import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil'; +import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -129,11 +156,43 @@ import { testPkpEthersWithEoaSessionSigsToSendTx } from './tests/testPkpEthersWi }; const pkpEthersTest = { - testPkpEthersWithEoaSessionSigsToSignWithAuthContext, - testPkpEthersWithEoaSessionSigsToSignMessage, - testPkpEthersWithEoaSessionSigsToEthSign, - testPkpEthersWithEoaSessionSigsToPersonalSign, - testPkpEthersWithEoaSessionSigsToSendTx, + eoaSessionSigs: { + testPkpEthersWithEoaSessionSigsToSignWithAuthContext, + testPkpEthersWithEoaSessionSigsToSignMessage, + testPkpEthersWithEoaSessionSigsToEthSign, + testPkpEthersWithEoaSessionSigsToPersonalSign, + testPkpEthersWithEoaSessionSigsToSendTx, + testPkpEthersWithEoaSessionSigsToEthSignTransaction, + testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1, + testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3, + testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4, + testPkpEthersWithEoaSessionSigsToEthSignTypedData, + testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil, + }, + pkpSessionSigs: { + testPkpEthersWithPkpSessionSigsToSignMessage, + testPkpEthersWithPkpSessionSigsToEthSign, + testPkpEthersWithPkpSessionSigsToPersonalSign, + testPkpEthersWithPkpSessionSigsToSendTx, + testPkpEthersWithPkpSessionSigsToEthSignTransaction, + testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1, + testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3, + testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4, + testPkpEthersWithPkpSessionSigsToEthSignTypedData, + testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil, + }, + litActionSessionSigs: { + testPkpEthersWithLitActionSessionSigsToSignMessage, + testPkpEthersWithLitActionSessionSigsToEthSign, + testPkpEthersWithLitActionSessionSigsToPersonalSign, + testPkpEthersWithLitActionSessionSigsToSendTx, + testPkpEthersWithLitActionSessionSigsToEthSignTransaction, + testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1, + testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3, + testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4, + testPkpEthersWithLitActionSessionSigsToEthSignTypedData, + testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil, + }, }; const testConfig = { @@ -146,7 +205,10 @@ import { testPkpEthersWithEoaSessionSigsToSendTx } from './tests/testPkpEthersWi ...litActionIpfsIdSessionSigsTests, ...capacityDelegationTests, ...bareAuthSigTests, - ...pkpEthersTest, + + ...pkpEthersTest.eoaSessionSigs, + ...pkpEthersTest.pkpSessionSigs, + ...pkpEthersTest.litActionSessionSigs, }, devEnv, }; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts new file mode 100644 index 0000000000..17cef6d9f4 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts @@ -0,0 +1,109 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTransaction + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTransaction + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTransaction + */ +export const testPkpEthersWithEoaSessionSigsToEthSignTransaction = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_sendTransaction parameters + try { + // Transaction to sign and send + const from = alice.pkp.ethAddress; + const to = alice.pkp.ethAddress; + const gasLimit = ethers.BigNumber.from('21000'); + const value = ethers.BigNumber.from('0'); + const data = '0x'; + + // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) + const tx = { + from: from, + to: to, + gasLimit, + value, + data, + }; + + // eth_sendTransaction parameters + // Transaction - Object + // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sendTransaction + // A serialized form of the whole transaction + const rawSignedTx = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTransaction', + params: [tx], + }, + }); + + const parsedTransaction = ethers.utils.parseTransaction(rawSignedTx); + + const signature = ethers.utils.joinSignature({ + r: parsedTransaction.r, + s: parsedTransaction.s, + v: parsedTransaction.v, + }); + + const rawTx = { + nonce: parsedTransaction.nonce, + gasPrice: parsedTransaction.gasPrice, + gasLimit: parsedTransaction.gasLimit, + to: parsedTransaction.to, + value: parsedTransaction.value, + data: parsedTransaction.data, + chainId: parsedTransaction.chainId, // Include chainId if the transaction is EIP-155 + }; + + const txHash = ethers.utils.keccak256( + ethers.utils.serializeTransaction(rawTx) + ); + + const { v, r, s } = parsedTransaction; + + const recoveredAddress = ethers.utils.recoverAddress(txHash, { r, s, v }); + + // ==================== Post-Validation ==================== + if (!parsedTransaction) { + throw new Error('❌ parsedTransaction should not be null'); + } + + if (signature.length !== 132) { + throw new Error( + `❌ signature should be 132 characters long, got ${signature.length}` + ); + } + + if (recoveredAddress.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddres should be ${alice.pkp.ethAddress}, got ${recoveredAddress}` + ); + } + } catch (e) { + if (e.message.includes('insufficient FPE funds')) { + console.log( + `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` + ); + } else { + throw new Error( + `❌ Error: ${e.toString()}` + ); + } + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedData.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedData.ts new file mode 100644 index 0000000000..1e7b502dd8 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedData.ts @@ -0,0 +1,95 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedData + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedData + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedData + */ +export const testPkpEthersWithEoaSessionSigsToEthSignTypedData = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData parameters + try { + // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData + const recoveredAddr = ethers.utils.verifyTypedData( + msgParams.domain, + { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, + msgParams.message, + signature + ); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil.ts new file mode 100644 index 0000000000..60af8f09aa --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil.ts @@ -0,0 +1,92 @@ +import { + PKPEthersWallet, + ethRequestHandler, + signTypedData, +} from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil + */ +export const testPkpEthersWithEoaSessionSigsToEthSignTypedDataUtil = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData parameters + try { + // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + const signature = await signTypedData(pkpEthersWallet, msgParams); + + // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData + const recoveredAddr = ethers.utils.verifyTypedData( + msgParams.domain, + { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, + msgParams.message, + signature + ); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1.ts new file mode 100644 index 0000000000..6227559d7a --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1.ts @@ -0,0 +1,77 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1 + */ +export const testPkpEthersWithEoaSessionSigsToEthSignTypedDataV1 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v1 parameters + try { + const msgParams = [ + { + type: 'string', + name: 'Message', + value: 'Hi, Alice!', + }, + { + type: 'uint32', + name: 'A number', + value: '1337', + }, + ]; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v1', + params: [msgParams, alice.pkp.ethAddress], + }, + }); + + const signatureBytes = ethers.utils.arrayify(signature); + + const recoveredAddr = recoverTypedSignature({ + data: msgParams, + signature: signatureBytes as any, + version: SignTypedDataVersion.V1, + }); + + // ==================== Post-Validation ==================== + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + + console.log('signature: ', signature); + console.log('recoveredAddr: ', recoveredAddr); + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3.ts new file mode 100644 index 0000000000..d0c7f64a21 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3.ts @@ -0,0 +1,105 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3 + */ +export const testPkpEthersWithEoaSessionSigsToEthSignTypedDataV3 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v3 parameters + try { + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v3', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + const recoveredAddr = recoverTypedSignature({ + data: { + // @ts-ignore + types: msgParams.types, + // @ts-ignore + domain: msgParams.domain, + // @ts-ignore + primaryType: msgParams.primaryType, + // @ts-ignore + message: msgParams.message, + }, + signature: signature, + version: SignTypedDataVersion.V3, + }); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4.ts new file mode 100644 index 0000000000..adaa3d34f7 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4.ts @@ -0,0 +1,105 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4 + */ +export const testPkpEthersWithEoaSessionSigsToEthSignTypedDataV4 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const eoaSessionSigs = await getEoaSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: eoaSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v3 parameters + try { + const msgParams = { + domain: { + chainId: 80001, + name: 'Ether Mail', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + ], + }, + to: [ + { + name: 'Bob', + wallets: [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', + ], + }, + ], + }, + primaryType: 'Mail', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v4', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + const recoveredAddr = recoverTypedSignature({ + data: msgParams as any, + signature: signature, + version: SignTypedDataVersion.V4, + }); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts index 9f4830a34a..efabece572 100644 --- a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts @@ -57,7 +57,7 @@ export const testPkpEthersWithEoaSessionSigsToSendTx = async ( ); } else { throw new Error( - `❌ PKPEthersWallet should be able to send tx unexpected error: ${e.toString()}` + `❌ Error: ${e.toString()}` ); } } diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSign.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSign.ts new file mode 100644 index 0000000000..897ea8b1a1 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSign.ts @@ -0,0 +1,60 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSign + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSign + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSign + */ +export const testPkpEthersWithLitActionSessionSigsToEthSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + console.log('devEnv.network:', devEnv.network); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- test eth_sign + try { + // Message to sign + const message = 'Hello world'; + const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); + + // DATA, 20 Bytes - address + // DATA, N Bytes - message to sign + // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sign + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_sign', + params: [alice.pkp.ethAddress, hexMsg], + }, + }); + const recoveredAddr = ethers.utils.verifyMessage(message, signature); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr !== alice.pkp.ethAddress) { + throw new Error( + `❌ test eth_sign recoveredAddr should be ${alice.pkp.ethAddress} but got ${recoveredAddr}` + ); + } + + console.log('✅ recoveredAddr:', recoveredAddr); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts new file mode 100644 index 0000000000..31e7ea19e1 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts @@ -0,0 +1,109 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTransaction + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTransaction + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTransaction + */ +export const testPkpEthersWithLitActionSessionSigsToEthSignTransaction = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_sendTransaction parameters + try { + // Transaction to sign and send + const from = alice.pkp.ethAddress; + const to = alice.pkp.ethAddress; + const gasLimit = ethers.BigNumber.from('21000'); + const value = ethers.BigNumber.from('0'); + const data = '0x'; + + // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) + const tx = { + from: from, + to: to, + gasLimit, + value, + data, + }; + + // eth_sendTransaction parameters + // Transaction - Object + // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sendTransaction + // A serialized form of the whole transaction + const rawSignedTx = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTransaction', + params: [tx], + }, + }); + + const parsedTransaction = ethers.utils.parseTransaction(rawSignedTx); + + const signature = ethers.utils.joinSignature({ + r: parsedTransaction.r, + s: parsedTransaction.s, + v: parsedTransaction.v, + }); + + const rawTx = { + nonce: parsedTransaction.nonce, + gasPrice: parsedTransaction.gasPrice, + gasLimit: parsedTransaction.gasLimit, + to: parsedTransaction.to, + value: parsedTransaction.value, + data: parsedTransaction.data, + chainId: parsedTransaction.chainId, // Include chainId if the transaction is EIP-155 + }; + + const txHash = ethers.utils.keccak256( + ethers.utils.serializeTransaction(rawTx) + ); + + const { v, r, s } = parsedTransaction; + + const recoveredAddress = ethers.utils.recoverAddress(txHash, { r, s, v }); + + // ==================== Post-Validation ==================== + if (!parsedTransaction) { + throw new Error('❌ parsedTransaction should not be null'); + } + + if (signature.length !== 132) { + throw new Error( + `❌ signature should be 132 characters long, got ${signature.length}` + ); + } + + if (recoveredAddress.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddres should be ${alice.pkp.ethAddress}, got ${recoveredAddress}` + ); + } + } catch (e) { + if (e.message.includes('insufficient FPE funds')) { + console.log( + `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` + ); + } else { + throw new Error( + `❌ Error: ${e.toString()}` + ); + } + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData.ts new file mode 100644 index 0000000000..60fc57cb03 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData.ts @@ -0,0 +1,95 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedData + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedData + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedData + */ +export const testPkpEthersWithLitActionSessionSigsToEthSignTypedData = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData parameters + try { + // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData + const recoveredAddr = ethers.utils.verifyTypedData( + msgParams.domain, + { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, + msgParams.message, + signature + ); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil.ts new file mode 100644 index 0000000000..d3dd79393f --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil.ts @@ -0,0 +1,87 @@ +import { PKPEthersWallet, signTypedData } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil + */ +export const testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil = + async (devEnv: TinnyEnvironment) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData parameters + try { + // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + const signature = await signTypedData(pkpEthersWallet, msgParams); + + // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData + const recoveredAddr = ethers.utils.verifyTypedData( + msgParams.domain, + { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, + msgParams.message, + signature + ); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } + }; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1.ts new file mode 100644 index 0000000000..d126811422 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1.ts @@ -0,0 +1,77 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1 + */ +export const testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV1 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v1 parameters + try { + const msgParams = [ + { + type: 'string', + name: 'Message', + value: 'Hi, Alice!', + }, + { + type: 'uint32', + name: 'A number', + value: '1337', + }, + ]; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v1', + params: [msgParams, alice.pkp.ethAddress], + }, + }); + + const signatureBytes = ethers.utils.arrayify(signature); + + const recoveredAddr = recoverTypedSignature({ + data: msgParams, + signature: signatureBytes as any, + version: SignTypedDataVersion.V1, + }); + + // ==================== Post-Validation ==================== + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + + console.log('signature: ', signature); + console.log('recoveredAddr: ', recoveredAddr); + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3.ts new file mode 100644 index 0000000000..fd4e4268ab --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3.ts @@ -0,0 +1,104 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3 + */ +export const testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV3 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v3 parameters + try { + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v3', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + const recoveredAddr = recoverTypedSignature({ + data: { + // @ts-ignore + types: msgParams.types, + // @ts-ignore + domain: msgParams.domain, + // @ts-ignore + primaryType: msgParams.primaryType, + // @ts-ignore + message: msgParams.message, + }, + signature: signature, + version: SignTypedDataVersion.V3, + }); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4.ts new file mode 100644 index 0000000000..034260228b --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4.ts @@ -0,0 +1,105 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4 + */ +export const testPkpEthersWithLitActionSessionSigsToEthSignTypedDataV4 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v3 parameters + try { + const msgParams = { + domain: { + chainId: 80001, + name: 'Ether Mail', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + ], + }, + to: [ + { + name: 'Bob', + wallets: [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', + ], + }, + ], + }, + primaryType: 'Mail', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v4', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + const recoveredAddr = recoverTypedSignature({ + data: msgParams as any, + signature: signature, + version: SignTypedDataVersion.V4, + }); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToPersonalSign.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToPersonalSign.ts new file mode 100644 index 0000000000..ecfca49e60 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToPersonalSign.ts @@ -0,0 +1,61 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToPersonalSign + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToPersonalSign + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToPersonalSign + */ +export const testPkpEthersWithLitActionSessionSigsToPersonalSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- personal_sign parameters + try { + // Message to sign + const message = 'Free the web'; + const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); + + // personal_sign parameters + // DATA, N Bytes - message to sign. + // DATA, 20 Bytes - address + // Reference: https://metamask.github.io/api-playground/api-documentation/#personal_sign + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'personal_sign', + params: [hexMsg, alice.pkp.ethAddress], + }, + }); + + const recoveredAddr = ethers.utils.verifyMessage(message, signature); + + // ==================== Post-Validation ==================== + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr !== alice.pkp.ethAddress) { + throw new Error( + `❌ recoveredAddr should be ${alice.pkp.ethAddress} but got ${recoveredAddr}` + ); + } + + console.log('✅ personal_sign recoveredAddr:', recoveredAddr); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToSendTx.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToSendTx.ts new file mode 100644 index 0000000000..f4bcf05340 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToSendTx.ts @@ -0,0 +1,62 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToSendTx + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToSendTx + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToSendTx + */ +export const testPkpEthersWithLitActionSessionSigsToSendTx = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_sendTransaction parameters + try { + // Transaction to sign and send + const from = alice.pkp.ethAddress; + const to = alice.pkp.ethAddress; + const gasLimit = ethers.BigNumber.from('21000'); + const value = ethers.BigNumber.from('0'); + const data = '0x'; + + // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) + const tx = { + from: from, + to: to, + gasLimit, + value, + data, + }; + + const txRes = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_sendTransaction', + params: [tx], + }, + }); + + console.log('✅ txRes:', txRes); + } catch (e) { + if (e.message.includes('insufficient FPE funds')) { + console.log( + `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` + ); + } else { + throw new Error(`❌ Error: ${e.toString()}`); + } + } +}; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToSignMessage.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToSignMessage.ts new file mode 100644 index 0000000000..76bceaf03b --- /dev/null +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToSignMessage.ts @@ -0,0 +1,32 @@ +import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; +import { getLitActionSessionSigs } from 'local-tests/setup/session-sigs/get-lit-action-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToSignMessage + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToSignMessage + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithLitActionSessionSigsToSignMessage + */ +export const testPkpEthersWithLitActionSessionSigsToSignMessage = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const litActionSessionSigs = await getLitActionSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: litActionSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- test signMessage + try { + const signature = await pkpEthersWallet.signMessage(alice.loveLetter); + console.log('✅ signature:', signature); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSign.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSign.ts new file mode 100644 index 0000000000..6bf9cd0bb7 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSign.ts @@ -0,0 +1,60 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSign + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSign + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSign + */ +export const testPkpEthersWithPkpSessionSigsToEthSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + console.log('devEnv.network:', devEnv.network); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- test eth_sign + try { + // Message to sign + const message = 'Hello world'; + const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); + + // DATA, 20 Bytes - address + // DATA, N Bytes - message to sign + // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sign + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_sign', + params: [alice.pkp.ethAddress, hexMsg], + }, + }); + const recoveredAddr = ethers.utils.verifyMessage(message, signature); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr !== alice.pkp.ethAddress) { + throw new Error( + `❌ test eth_sign recoveredAddr should be ${alice.pkp.ethAddress} but got ${recoveredAddr}` + ); + } + + console.log('✅ recoveredAddr:', recoveredAddr); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts new file mode 100644 index 0000000000..6fcda6c07e --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts @@ -0,0 +1,109 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTransaction + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTransaction + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTransaction + */ +export const testPkpEthersWithPkpSessionSigsToEthSignTransaction = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_sendTransaction parameters + try { + // Transaction to sign and send + const from = alice.pkp.ethAddress; + const to = alice.pkp.ethAddress; + const gasLimit = ethers.BigNumber.from('21000'); + const value = ethers.BigNumber.from('0'); + const data = '0x'; + + // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) + const tx = { + from: from, + to: to, + gasLimit, + value, + data, + }; + + // eth_sendTransaction parameters + // Transaction - Object + // Reference: https://ethereum.github.io/execution-apis/api-documentation/#eth_sendTransaction + // A serialized form of the whole transaction + const rawSignedTx = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTransaction', + params: [tx], + }, + }); + + const parsedTransaction = ethers.utils.parseTransaction(rawSignedTx); + + const signature = ethers.utils.joinSignature({ + r: parsedTransaction.r, + s: parsedTransaction.s, + v: parsedTransaction.v, + }); + + const rawTx = { + nonce: parsedTransaction.nonce, + gasPrice: parsedTransaction.gasPrice, + gasLimit: parsedTransaction.gasLimit, + to: parsedTransaction.to, + value: parsedTransaction.value, + data: parsedTransaction.data, + chainId: parsedTransaction.chainId, // Include chainId if the transaction is EIP-155 + }; + + const txHash = ethers.utils.keccak256( + ethers.utils.serializeTransaction(rawTx) + ); + + const { v, r, s } = parsedTransaction; + + const recoveredAddress = ethers.utils.recoverAddress(txHash, { r, s, v }); + + // ==================== Post-Validation ==================== + if (!parsedTransaction) { + throw new Error('❌ parsedTransaction should not be null'); + } + + if (signature.length !== 132) { + throw new Error( + `❌ signature should be 132 characters long, got ${signature.length}` + ); + } + + if (recoveredAddress.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddres should be ${alice.pkp.ethAddress}, got ${recoveredAddress}` + ); + } + } catch (e) { + if (e.message.includes('insufficient FPE funds')) { + console.log( + `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` + ); + } else { + throw new Error( + `❌ Error: ${e.toString()}` + ); + } + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedData.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedData.ts new file mode 100644 index 0000000000..91f267fe9e --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedData.ts @@ -0,0 +1,95 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedData + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedData + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedData + */ +export const testPkpEthersWithPkpSessionSigsToEthSignTypedData = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData parameters + try { + // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData + const recoveredAddr = ethers.utils.verifyTypedData( + msgParams.domain, + { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, + msgParams.message, + signature + ); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil.ts new file mode 100644 index 0000000000..a9ec574c2a --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil.ts @@ -0,0 +1,88 @@ +import { PKPEthersWallet, signTypedData } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil + */ +export const testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData parameters + try { + // Example from https://github.com/MetaMask/test-dapp/blob/main/src/index.js#L1033 + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + const signature = await signTypedData(pkpEthersWallet, msgParams); + + // https://docs.ethers.io/v5/api/utils/signing-key/#utils-verifyTypedData + const recoveredAddr = ethers.utils.verifyTypedData( + msgParams.domain, + { Person: msgParams.types.Person, Mail: msgParams.types.Mail }, + msgParams.message, + signature + ); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1.ts new file mode 100644 index 0000000000..b13f716f9e --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1.ts @@ -0,0 +1,77 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1 + */ +export const testPkpEthersWithPkpSessionSigsToEthSignTypedDataV1 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v1 parameters + try { + const msgParams = [ + { + type: 'string', + name: 'Message', + value: 'Hi, Alice!', + }, + { + type: 'uint32', + name: 'A number', + value: '1337', + }, + ]; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v1', + params: [msgParams, alice.pkp.ethAddress], + }, + }); + + const signatureBytes = ethers.utils.arrayify(signature); + + const recoveredAddr = recoverTypedSignature({ + data: msgParams, + signature: signatureBytes as any, + version: SignTypedDataVersion.V1, + }); + + // ==================== Post-Validation ==================== + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + + console.log('signature: ', signature); + console.log('recoveredAddr: ', recoveredAddr); + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3.ts new file mode 100644 index 0000000000..b5e2c55ca5 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3.ts @@ -0,0 +1,104 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3 + */ +export const testPkpEthersWithPkpSessionSigsToEthSignTypedDataV3 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v3 parameters + try { + const msgParams = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 80001, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { + name: 'Cow', + wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + to: { + name: 'Bob', + wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + contents: 'Hello, Bob!', + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v3', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + const recoveredAddr = recoverTypedSignature({ + data: { + // @ts-ignore + types: msgParams.types, + // @ts-ignore + domain: msgParams.domain, + // @ts-ignore + primaryType: msgParams.primaryType, + // @ts-ignore + message: msgParams.message, + }, + signature: signature, + version: SignTypedDataVersion.V3, + }); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4.ts new file mode 100644 index 0000000000..a5de892413 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4.ts @@ -0,0 +1,105 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { + SignTypedDataVersion, + recoverTypedSignature, +} from '@metamask/eth-sig-util'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4 + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4 + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4 + */ +export const testPkpEthersWithPkpSessionSigsToEthSignTypedDataV4 = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_signTypedData_v3 parameters + try { + const msgParams = { + domain: { + chainId: 80001, + name: 'Ether Mail', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + ], + }, + to: [ + { + name: 'Bob', + wallets: [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', + ], + }, + ], + }, + primaryType: 'Mail', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + }, + }; + + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_signTypedData_v4', + params: [alice.pkp.ethAddress, JSON.stringify(msgParams)], + }, + }); + + const recoveredAddr = recoverTypedSignature({ + data: msgParams as any, + signature: signature, + version: SignTypedDataVersion.V4, + }); + + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr.toLowerCase() !== alice.pkp.ethAddress.toLowerCase()) { + throw new Error( + `❌ recoveredAddr ${recoveredAddr} should be ${alice.pkp.ethAddress}` + ); + } + } catch (e) { + throw new Error(`❌ ${e.toString()}`); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToPersonalSign.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToPersonalSign.ts new file mode 100644 index 0000000000..944119c32a --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToPersonalSign.ts @@ -0,0 +1,61 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToPersonalSign + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToPersonalSign + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToPersonalSign + */ +export const testPkpEthersWithPkpSessionSigsToPersonalSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- personal_sign parameters + try { + // Message to sign + const message = 'Free the web'; + const hexMsg = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message)); + + // personal_sign parameters + // DATA, N Bytes - message to sign. + // DATA, 20 Bytes - address + // Reference: https://metamask.github.io/api-playground/api-documentation/#personal_sign + const signature = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'personal_sign', + params: [hexMsg, alice.pkp.ethAddress], + }, + }); + + const recoveredAddr = ethers.utils.verifyMessage(message, signature); + + // ==================== Post-Validation ==================== + if (signature.length !== 132) { + throw new Error('❌ signature should be 132 characters long'); + } + + if (recoveredAddr !== alice.pkp.ethAddress) { + throw new Error( + `❌ recoveredAddr should be ${alice.pkp.ethAddress} but got ${recoveredAddr}` + ); + } + + console.log('✅ personal_sign recoveredAddr:', recoveredAddr); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts new file mode 100644 index 0000000000..d474a77523 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts @@ -0,0 +1,64 @@ +import { PKPEthersWallet, ethRequestHandler } from '@lit-protocol/pkp-ethers'; +import { ethers } from 'ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToSendTx + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToSendTx + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToSendTx + */ +export const testPkpEthersWithPkpSessionSigsToSendTx = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- eth_sendTransaction parameters + try { + // Transaction to sign and send + const from = alice.pkp.ethAddress; + const to = alice.pkp.ethAddress; + const gasLimit = ethers.BigNumber.from('21000'); + const value = ethers.BigNumber.from('0'); + const data = '0x'; + + // pkp-ethers signer will automatically add missing fields (nonce, chainId, gasPrice, gasLimit) + const tx = { + from: from, + to: to, + gasLimit, + value, + data, + }; + + const txRes = await ethRequestHandler({ + signer: pkpEthersWallet, + payload: { + method: 'eth_sendTransaction', + params: [tx], + }, + }); + + console.log('✅ txRes:', txRes); + } catch (e) { + if (e.message.includes('insufficient FPE funds')) { + console.log( + `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` + ); + } else { + throw new Error( + `❌ Error: ${e.toString()}` + ); + } + } +}; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToSignMessage.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToSignMessage.ts new file mode 100644 index 0000000000..568f144bc9 --- /dev/null +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToSignMessage.ts @@ -0,0 +1,32 @@ +import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; +import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ✅ NETWORK=cayenne yarn test:local --filter=testPkpEthersWithPkpSessionSigsToSignMessage + * ✅ NETWORK=manzano yarn test:local --filter=testPkpEthersWithPkpSessionSigsToSignMessage + * ✅ NETWORK=localchain yarn test:local --filter=testPkpEthersWithPkpSessionSigsToSignMessage + */ +export const testPkpEthersWithPkpSessionSigsToSignMessage = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + const pkpSessionSigs = await getPkpSessionSigs(devEnv, alice); + + const pkpEthersWallet = new PKPEthersWallet({ + litNodeClient: devEnv.litNodeClient, + pkpPubKey: alice.pkp.publicKey, + controllerSessionSigs: pkpSessionSigs, + }); + + await pkpEthersWallet.init(); + + // -- test signMessage + try { + const signature = await pkpEthersWallet.signMessage(alice.loveLetter); + console.log('✅ signature:', signature); + } catch (e) { + throw new Error('❌ Error: ' + e.message); + } +}; From 72f79e887cd96f83f9d116fe03f6f75b37c0a74f Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 10 May 2024 17:01:40 +0100 Subject: [PATCH 146/263] chore: pretty jest --- .../testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts | 4 +--- local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts | 4 +--- ...stPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts | 4 +--- .../testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts | 4 +--- local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts | 4 +--- packages/pkp-base/src/lib/pkp-base.ts | 1 - packages/pkp-ethers/src/lib/pkp-ethers.ts | 1 - 7 files changed, 5 insertions(+), 17 deletions(-) diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts index 17cef6d9f4..8ad1ebf554 100644 --- a/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToEthSignTransaction.ts @@ -101,9 +101,7 @@ export const testPkpEthersWithEoaSessionSigsToEthSignTransaction = async ( `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` ); } else { - throw new Error( - `❌ Error: ${e.toString()}` - ); + throw new Error(`❌ Error: ${e.toString()}`); } } }; diff --git a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts index efabece572..8a347da507 100644 --- a/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts +++ b/local-tests/tests/testPkpEthersWithEoaSessionSigsToSendTx.ts @@ -56,9 +56,7 @@ export const testPkpEthersWithEoaSessionSigsToSendTx = async ( `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` ); } else { - throw new Error( - `❌ Error: ${e.toString()}` - ); + throw new Error(`❌ Error: ${e.toString()}`); } } }; diff --git a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts index 31e7ea19e1..cbfb204787 100644 --- a/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts +++ b/local-tests/tests/testPkpEthersWithLitActionSessionSigsToEthSignTransaction.ts @@ -101,9 +101,7 @@ export const testPkpEthersWithLitActionSessionSigsToEthSignTransaction = async ( `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` ); } else { - throw new Error( - `❌ Error: ${e.toString()}` - ); + throw new Error(`❌ Error: ${e.toString()}`); } } }; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts index 6fcda6c07e..ae33298efd 100644 --- a/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToEthSignTransaction.ts @@ -101,9 +101,7 @@ export const testPkpEthersWithPkpSessionSigsToEthSignTransaction = async ( `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` ); } else { - throw new Error( - `❌ Error: ${e.toString()}` - ); + throw new Error(`❌ Error: ${e.toString()}`); } } }; diff --git a/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts b/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts index d474a77523..783d5f8a9b 100644 --- a/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts +++ b/local-tests/tests/testPkpEthersWithPkpSessionSigsToSendTx.ts @@ -56,9 +56,7 @@ export const testPkpEthersWithPkpSessionSigsToSendTx = async ( `🧪 PKPEthersWallet should be able to send tx (insufficient FPE funds ❗️)` ); } else { - throw new Error( - `❌ Error: ${e.toString()}` - ); + throw new Error(`❌ Error: ${e.toString()}`); } } }; diff --git a/packages/pkp-base/src/lib/pkp-base.ts b/packages/pkp-base/src/lib/pkp-base.ts index b81bd982ce..94017ebeeb 100644 --- a/packages/pkp-base/src/lib/pkp-base.ts +++ b/packages/pkp-base/src/lib/pkp-base.ts @@ -245,7 +245,6 @@ export class PKPBase { if (!this.authContext.client && this.litNodeClient) { this.authContext.client = this.litNodeClient; } - // Ensure authContext has a valid client and getSessionSigsProps if ( !(this.authContext.client instanceof LitNodeClientNodeJs) || diff --git a/packages/pkp-ethers/src/lib/pkp-ethers.ts b/packages/pkp-ethers/src/lib/pkp-ethers.ts index d17d2109be..3d9f3c2920 100644 --- a/packages/pkp-ethers/src/lib/pkp-ethers.ts +++ b/packages/pkp-ethers/src/lib/pkp-ethers.ts @@ -237,7 +237,6 @@ export class PKPEthersWallet if (!this.litNodeClientReady) { await this.init(); } - const toSign = arrayify(hashMessage(message)); let signature; if (this.useAction) { From 06e937e97beeed7cbb545a157377f7b6e7c67b45 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 13:42:33 -0400 Subject: [PATCH 147/263] ref: fix port check --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 748566f0ed..0e5e605f89 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -919,7 +919,7 @@ export class LitContracts { * ports in range of 8470 - 8479 are configured for https on custom networks (eg. cayenne) * we shouold resepct https on these ports as they are using trusted ZeroSSL certs */ - if (item.port !== 443 && item.port > 8480 && item.port < 8469) { + if (item.port !== 443 || (item.port > 8480 && item.port < 8469)) { proto = 'http://'; } return `${proto}${intToIP(item.ip)}:${item.port}`; From 7271ab5ef098d2bae5a3e44d360e63a1da6afe85 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 10 May 2024 18:44:55 +0100 Subject: [PATCH 148/263] fix: executeJs doesn't require Auth Material --- packages/encryption/src/lib/params-validators.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/encryption/src/lib/params-validators.ts b/packages/encryption/src/lib/params-validators.ts index 3afb886824..f3b7887ede 100644 --- a/packages/encryption/src/lib/params-validators.ts +++ b/packages/encryption/src/lib/params-validators.ts @@ -117,7 +117,6 @@ export const paramsValidators: Record< executeJs: (params: JsonExecutionSdkParams) => [ new AuthMaterialValidator('executeJs', params), new ExecuteJsValidator('executeJs', params), - new AuthMethodValidator('executeJs', params.authMethods), ], decrypt: (params: DecryptRequest) => [ From 10b3b6cca3c780de683d64259202eb43167019ea Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 10 May 2024 19:17:47 +0100 Subject: [PATCH 149/263] chore: remove redundant tests --- .../pkp-client/src/lib/wallet-factory.spec.ts | 121 ------------------ .../pkp-ethers/src/lib/pkp-ethers.spec.ts | 21 --- 2 files changed, 142 deletions(-) delete mode 100644 packages/pkp-client/src/lib/wallet-factory.spec.ts delete mode 100644 packages/pkp-ethers/src/lib/pkp-ethers.spec.ts diff --git a/packages/pkp-client/src/lib/wallet-factory.spec.ts b/packages/pkp-client/src/lib/wallet-factory.spec.ts deleted file mode 100644 index 400045a98b..0000000000 --- a/packages/pkp-client/src/lib/wallet-factory.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { LitNodeClientNodeJs } from '@lit-protocol/lit-node-client-nodejs'; -import { PKPCosmosWallet } from '@lit-protocol/pkp-cosmos'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { WalletFactory } from './wallet-factory'; - -import * as LITCONFIG from 'lit.config.json'; -import { - AuthCallbackParams, - AuthSig, - PKPCosmosWalletProp, - PKPEthersWalletProp, -} from '@lit-protocol/types'; - -describe('WalletFactory', () => { - it('should create an Ethereum wallet', () => { - const ethProp: PKPEthersWalletProp = { - controllerAuthSig: LITCONFIG.CONTROLLER_AUTHSIG, - pkpPubKey: LITCONFIG.PKP_PUBKEY, - rpcs: { - eth: LITCONFIG.CHRONICLE_RPC, - cosmos: LITCONFIG.COSMOS_RPC, - }, - }; - const ethWallet = WalletFactory.createWallet('eth', ethProp); - - expect(ethWallet).toBeInstanceOf(PKPEthersWallet); - }); - - it('should create an Ethereum wallet using auth context', () => { - const client = new LitNodeClientNodeJs({ - litNetwork: 'localhost', - }); - const ethProp: PKPEthersWalletProp = { - authContext: { - client, - authMethods: [], - getSessionSigsProps: { - chain: 'ethereum', - resourceAbilityRequests: [], - authNeededCallback: function ( - params: AuthCallbackParams - ): Promise { - throw new Error('Function not implemented.'); - }, - }, - }, - pkpPubKey: LITCONFIG.PKP_PUBKEY, - rpcs: { - eth: LITCONFIG.CHRONICLE_RPC, - cosmos: LITCONFIG.COSMOS_RPC, - }, - }; - const ethWallet = WalletFactory.createWallet('eth', ethProp); - - expect(ethWallet).toBeInstanceOf(PKPEthersWallet); - }); - - it('should throw when creating an Ethereum wallet using auth sig and auth context simultaneously', () => { - const client = new LitNodeClientNodeJs({ - litNetwork: 'localhost', - }); - const ethProp: PKPEthersWalletProp = { - controllerAuthSig: LITCONFIG.CONTROLLER_AUTHSIG, - authContext: { - client, - authMethods: [], - getSessionSigsProps: { - chain: 'ethereum', - resourceAbilityRequests: [], - authNeededCallback: function ( - params: AuthCallbackParams - ): Promise { - throw new Error('Function not implemented.'); - }, - }, - }, - pkpPubKey: LITCONFIG.PKP_PUBKEY, - rpcs: { - eth: LITCONFIG.CHRONICLE_RPC, - cosmos: LITCONFIG.COSMOS_RPC, - }, - }; - - expect(() => WalletFactory.createWallet('eth', ethProp)).toThrowError( - 'Multiple authentications are defined, can only use one at a time' - ); - }); - - it('should create a Cosmos wallet', () => { - const cosmosProp: PKPCosmosWalletProp = { - controllerAuthSig: LITCONFIG.CONTROLLER_AUTHSIG, - pkpPubKey: LITCONFIG.PKP_PUBKEY, - rpcs: { - eth: LITCONFIG.CHRONICLE_RPC, - cosmos: LITCONFIG.COSMOS_RPC, - }, - addressPrefix: 'cosmos', - }; - const cosmosWallet = WalletFactory.createWallet('cosmos', cosmosProp); - - expect(cosmosWallet).toBeInstanceOf(PKPCosmosWallet); - }); - - it('should throw an error for unsupported BTC wallet', () => { - const btcProp: any = { - /* Bitcoin properties */ - }; - expect(() => WalletFactory.createWallet('btc', btcProp)).toThrowError( - 'BTC wallet is not supported yet' - ); - }); - - it('should throw an error for unsupported chain', () => { - const unsupportedProp: any = { - /* Unsupported properties */ - }; - expect(() => - WalletFactory.createWallet('unsupportedChain', unsupportedProp) - ).toThrowError('Unsupported chain: unsupportedChain'); - }); -}); diff --git a/packages/pkp-ethers/src/lib/pkp-ethers.spec.ts b/packages/pkp-ethers/src/lib/pkp-ethers.spec.ts deleted file mode 100644 index 84bfb3b01c..0000000000 --- a/packages/pkp-ethers/src/lib/pkp-ethers.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { PKPEthersWallet } from './pkp-ethers'; -import * as LITCONFIG from 'lit.config.json'; - -describe('PKP-ethers', () => { - let pkpEthersWallet: PKPEthersWallet; - - beforeAll(async () => { - console.log('Before All - init pkp ethers wallet'); - pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: LITCONFIG.CONTROLLER_AUTHSIG, - pkpPubKey: LITCONFIG.PKP_PUBKEY, - rpc: LITCONFIG.CHRONICLE_RPC, - }); - }); - - describe('pkp ethers JSON RPC handler', () => { - it('PKPEthersWallet should be defined', () => { - expect(PKPEthersWallet).toBeDefined(); - }); - }); -}); From 2e9302123066c3ffc826ee2c98121fef4d5cd014 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 10 May 2024 19:25:05 +0100 Subject: [PATCH 150/263] Published version 6.0.0-beta-1 to `@cayenne` tag --- README.md | 2 +- lerna.json | 2 +- packages/access-control-conditions/package.json | 4 ++-- packages/auth-browser/package.json | 4 ++-- packages/auth-helpers/package.json | 4 ++-- packages/bls-sdk/package.json | 4 ++-- packages/constants/package.json | 4 ++-- .../src/lib/constants/autogen_internal.ts | 16 ++++++++++++---- packages/constants/src/lib/version.ts | 2 +- packages/contracts-sdk/package.json | 4 ++-- packages/core/package.json | 4 ++-- packages/crypto/package.json | 4 ++-- packages/ecdsa-sdk/package.json | 4 ++-- packages/encryption/package.json | 4 ++-- packages/lit-auth-client/package.json | 4 ++-- packages/lit-node-client-nodejs/package.json | 4 ++-- packages/lit-node-client/package.json | 4 ++-- packages/logger/package.json | 4 ++-- packages/misc-browser/package.json | 4 ++-- packages/misc/package.json | 4 ++-- packages/nacl/package.json | 4 ++-- packages/pkp-base/package.json | 4 ++-- packages/pkp-client/package.json | 4 ++-- packages/pkp-cosmos/package.json | 4 ++-- packages/pkp-ethers/package.json | 4 ++-- packages/pkp-sui/package.json | 4 ++-- packages/pkp-walletconnect/package.json | 4 ++-- packages/sev-snp-utils-sdk/package.json | 4 ++-- packages/types/package.json | 4 ++-- packages/uint8arrays/package.json | 4 ++-- yarn.lock | 5 +++++ 31 files changed, 72 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 30df787cb1..34efb54790 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-

Lit Protocol Javascript/Typescript SDK V5.0.0

+

Lit Protocol Javascript/Typescript SDK V6.0.0


diff --git a/lerna.json b/lerna.json index ea99d3dbed..592abd5f81 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "useNx": true, "useWorkspaces": true, - "version": "6.0.0-alpha.1" + "version": "6.0.0-beta.1" } diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index efaa02b8eb..8dac7e0069 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 2809895bc0..3a425ade5f 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -30,7 +30,7 @@ "tags": [ "browser" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 2386457e74..30a45653da 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 1e2d1f0389..d4cf8a2fdc 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/package.json b/packages/constants/package.json index 4b1881181f..f655ce13cd 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/src/lib/constants/autogen_internal.ts b/packages/constants/src/lib/constants/autogen_internal.ts index 98f0e489a0..8e0ea60db6 100644 --- a/packages/constants/src/lib/constants/autogen_internal.ts +++ b/packages/constants/src/lib/constants/autogen_internal.ts @@ -1,11 +1,15 @@ // This file is auto-generated by tools/scripts/gen-internal-dev.mjs export const INTERNAL_DEV = [ 'https://167.114.17.201:443', - 'https://64.131.85.106:443', - 'https://167.114.17.202:443', 'https://199.115.117.113:443', + 'https://167.114.17.202:443', + 'https://167.114.17.205:443', 'https://167.114.17.203:443', 'https://108.62.0.105:443', + 'https://199.115.117.115:443', + 'https://64.131.85.106:443', + 'https://167.114.17.204:443', + 'https://64.131.85.108:443', ]; export const INTERNAL_MIN_NODE_COUNT = 2; @@ -16,11 +20,15 @@ export const INTERNAL_DEFAULT_CONFIG = { debug: true, bootstrapUrls: [ 'https://167.114.17.201:443', - 'https://64.131.85.106:443', - 'https://167.114.17.202:443', 'https://199.115.117.113:443', + 'https://167.114.17.202:443', + 'https://167.114.17.205:443', 'https://167.114.17.203:443', 'https://108.62.0.105:443', + 'https://199.115.117.115:443', + 'https://64.131.85.106:443', + 'https://167.114.17.204:443', + 'https://64.131.85.108:443', ], litNetwork: 'internalDev', connectTimeout: 20000, diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index 5a6c12d616..ce73dcf282 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = '6.0.0-alpha.1'; +export const version = '6.0.0-beta.1'; diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 044d97ae47..0c3a9d7c28 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -32,7 +32,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 86700e68b5..d95fbba3bd 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/core", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/crypto/package.json b/packages/crypto/package.json index d680c0b241..59192c8d2f 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index 6fcd5713bd..e4f5e0c65d 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/encryption/package.json b/packages/encryption/package.json index d786daf1e8..17752f89c1 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index 33ecc1b9c2..4aefb06aa1 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/lit-auth-client", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 8d177b809e..e58d6cda91 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -24,7 +24,7 @@ "tags": [ "nodejs" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index a4053f0697..fbe1299154 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/logger/package.json b/packages/logger/package.json index b3a4520aa8..196ea880ef 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/logger", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "tags": [ "universal" @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index c405504013..7ac09bbbfe 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -21,7 +21,7 @@ "tags": [ "browser" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc/package.json b/packages/misc/package.json index 58b18cfe8d..2707732f05 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 5acbdba213..ca5724d20e 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -21,7 +21,7 @@ "access": "public", "directory": "../../dist/packages/nacl" }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 4b0af6fb77..c57ffd3933 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-base", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 5e8445f437..e6ba255d7b 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-client", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index c69e18ab9d..f694b4f992 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-cosmos", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 0670776480..10631481e8 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 137650df97..1da6967f3a 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-sui", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 9096e55793..6396c3a983 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-walletconnect", - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 6ed7c564dd..ad0f16f821 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/types/package.json b/packages/types/package.json index 90d7b2094b..bf1148c1cb 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -23,7 +23,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index e98b54d1e7..3b06468b86 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-alpha.1", + "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 66ee163b86..5bbc2c7589 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24015,6 +24015,11 @@ tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" From 6b3458d4bcd4ad87b31025aeefa94f58918360ef Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 15:29:37 -0400 Subject: [PATCH 151/263] chore: fmt --- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 8dac7e0069..0488f0e88b 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 3a425ade5f..8585167aa4 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 30a45653da..d545221540 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index d4cf8a2fdc..d49719d8ef 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index f655ce13cd..8376b884e6 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 0c3a9d7c28..cc84b307b0 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/core/package.json b/packages/core/package.json index d95fbba3bd..f7e4e91a71 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 59192c8d2f..144dd9c236 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index e4f5e0c65d..e23fa0995f 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 17752f89c1..b252179f32 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index 4aefb06aa1..4fb69b5c1c 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index e58d6cda91..40684490cb 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index fbe1299154..be31a09253 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index 196ea880ef..20521609ec 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 7ac09bbbfe..d06bd71aec 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 2707732f05..25cffacad6 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index ca5724d20e..b120440910 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index c57ffd3933..a777208aee 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index e6ba255d7b..eae3e004fd 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index f694b4f992..fd857537cb 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 10631481e8..95dea9fa1b 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 1da6967f3a..42cf963bfc 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 6396c3a983..e9cf1b6cc0 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index ad0f16f821..7c26485571 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index bf1148c1cb..d447fcf1db 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 3b06468b86..4f584a4741 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.1", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} From c29b6b97ff8e116fd977283d5cebc046969b4dcb Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 10 May 2024 18:13:32 -0400 Subject: [PATCH 152/263] ref: removing logging --- .../src/lib/helpers/process-lit-action-response-strategy.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts index 8cbc3e8922..8116fae21d 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -31,10 +31,6 @@ export const processLitActionResponseStrategy = ( const copiedExecutionResponses = executionResponses.map((r) => { return '' + r; }); - log( - 'filtered responses with frequency dist: ', - JSON.stringify(copiedExecutionResponses) - ); if (strategy.strategy === 'custom') { try { if (strategy.customFilter) { From 0e13a8d86c20a711da42e22dbbeb02c4ceec04de Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 13 May 2024 12:44:44 -0400 Subject: [PATCH 153/263] ref: make internal helper noted as private --- .../src/lib/helpers/process-lit-action-response-strategy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts index 8116fae21d..4d725ffeda 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/process-lit-action-response-strategy.ts @@ -10,7 +10,7 @@ import { log, logError } from '@lit-protocol/misc'; * @param responses any[] * @returns an object which contains both the least and most occuring item in the array */ -const findFrequency = (responses: string[]): { min: any; max: any } => { +const _findFrequency = (responses: string[]): { min: any; max: any } => { const sorted = responses.sort( (a: any, b: any) => responses.filter((v: any) => v === a).length - @@ -50,7 +50,7 @@ export const processLitActionResponseStrategy = ( } } - let respFrequency = findFrequency(copiedExecutionResponses); + let respFrequency = _findFrequency(copiedExecutionResponses); if (strategy?.strategy === 'leastCommon') { log( 'strategy found to be most common, taking most common response from execution results' From 3c2c1c4fb55c678cea276df1739b634e71ba6737 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 13 May 2024 12:45:01 -0400 Subject: [PATCH 154/263] test: add non json formatted repsonses to unit tests --- ...ocess-lit-action-response-strategy.spec.ts | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts index 1134261a41..515fbaa29e 100644 --- a/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts +++ b/packages/lit-node-client-nodejs/src/lib/helpers/pocess-lit-action-response-strategy.spec.ts @@ -125,6 +125,129 @@ describe('processLitActionResponseStrategy', () => { logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', }, ]; + + const litActionResponsesNonJson: any[] = [ + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: 'Hello World', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: 'fail', + signatureShare: '', + shareIndex: 0, + bigR: '', + publicKey: '', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: 'Hello World, 71', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"E90BAE64AFA7C571CE41BEF25FF771CA2F1BC20FC09A7762200552B30ACC0CDC"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: 'Hello World', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"31977D4BE7F49C0CD97CC0756CCA3244A949EA7D591F79B64F324846507448CD"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: 'Hello World', + logs: 'is_leader: true\nresponse: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"F21798A1A37CC86566EA0D751F37CC144774A1A8A4FCD5E6E64287690FB60119"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: 'Hello World', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + { + success: true, + signedData: { + sig: { + sigType: 'K256', + dataSigned: + '"7D87C5EA75F7378BB701E404C50639161AF3EFF66293E9F375B5F17EB50476F4"', + signatureShare: + '"7ECB0E020BED801905D3FE941751E4313086603BBBF21F1756832F02A6FBE567"', + shareIndex: 0, + bigR: '"02330092EBF809B05EA0A032A42AD2FE32579D997A739D7BB4CF40EBA83B4355D3"', + publicKey: + '"047E3AC46588256338E62D8763592B8AA9BD13C31C9326D51CE82254A1839759A4FE7C1281AA1A9F8E810DA52B72046731CB3EE4D213799F7CE26C55A63783DB78"', + sigName: 'sig', + }, + }, + decryptedData: {}, + claimData: {}, + response: 'Hello World', + logs: 'is_leader: false\nwaiting for response using collect\ncollect from leader: 4\n', + }, + ]; it('should find least common response', () => { let resp = processLitActionResponseStrategy(litActionResponses, { strategy: 'leastCommon', @@ -149,4 +272,20 @@ describe('processLitActionResponseStrategy', () => { expect(resp).toBeDefined(); expect(resp).toBe('{"hello":"world","res": "71"}'); }); + + it('should find most common response non json', () => { + let resp = processLitActionResponseStrategy(litActionResponsesNonJson, { + strategy: 'mostCommon', + }); + expect(resp).toBeDefined(); + expect(resp).toBe('Hello World'); + }); + + it('should find least common response non json', () => { + let resp = processLitActionResponseStrategy(litActionResponsesNonJson, { + strategy: 'leastCommon', + }); + expect(resp).toBeDefined(); + expect(resp).toBe('Hello World, 71'); + }); }); From 2fcf24fca6bba95ed0a66c287bd0a28a3801d470 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 13 May 2024 15:46:21 -0400 Subject: [PATCH 155/263] ref: switch & and || operators in port check --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 0e5e605f89..23da2323fa 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -919,7 +919,7 @@ export class LitContracts { * ports in range of 8470 - 8479 are configured for https on custom networks (eg. cayenne) * we shouold resepct https on these ports as they are using trusted ZeroSSL certs */ - if (item.port !== 443 || (item.port > 8480 && item.port < 8469)) { + if (item.port !== 443 && (item.port > 8480 || item.port < 8469)) { proto = 'http://'; } return `${proto}${intToIP(item.ip)}:${item.port}`; From 72dc96a245b5e8216af4fcb255ea6cfa5bad1f05 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 13 May 2024 15:59:59 -0400 Subject: [PATCH 156/263] publish 6.0.0-beta.2 --- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/constants/src/lib/version.ts | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 0488f0e88b..49d1652d30 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 8585167aa4..75e6372dcf 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -30,7 +30,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index d545221540..d5695e23ce 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index d49719d8ef..c0ffab694b 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/constants/package.json b/packages/constants/package.json index 8376b884e6..b20ccfab90 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index ce73dcf282..96cbe99b8f 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = '6.0.0-beta.1'; +export const version = '6.0.0-beta.2'; diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index cc84b307b0..c4ca0de3d5 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -32,7 +32,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/core/package.json b/packages/core/package.json index f7e4e91a71..24c776acbe 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/core", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 144dd9c236..b5d169bf6e 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index e23fa0995f..e7b40c8f45 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/encryption/package.json b/packages/encryption/package.json index b252179f32..0542df409e 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index 4fb69b5c1c..db56194122 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/lit-auth-client", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 40684490cb..454bf1cb1c 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -24,7 +24,7 @@ "tags": [ "nodejs" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index be31a09253..bb18a0d62d 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/logger/package.json b/packages/logger/package.json index 20521609ec..7baa7d6072 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/logger", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "tags": [ "universal" diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index d06bd71aec..23e3b2806c 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -21,7 +21,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/misc/package.json b/packages/misc/package.json index 25cffacad6..5c69732cd0 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/nacl/package.json b/packages/nacl/package.json index b120440910..a5010da387 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -21,7 +21,7 @@ "access": "public", "directory": "../../dist/packages/nacl" }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index a777208aee..862e7e45ea 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-base", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index eae3e004fd..1541da1fd4 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-client", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index fd857537cb..8e4c005481 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-cosmos", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 95dea9fa1b..2b7b882243 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 42cf963bfc..2db9f2674d 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-sui", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index e9cf1b6cc0..72dfb5a04f 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-walletconnect", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 7c26485571..eb0b681e3b 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/types/package.json b/packages/types/package.json index d447fcf1db..91533ec2aa 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -23,7 +23,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 4f584a4741..c95c6e6a1e 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } From 56da674709f0647fd64e7280c9f078cecbfda85f Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 13 May 2024 16:00:15 -0400 Subject: [PATCH 157/263] up version from publish --- lerna.json | 2 +- local-tests/test.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 592abd5f81..c9c78976e2 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "useNx": true, "useWorkspaces": true, - "version": "6.0.0-beta.1" + "version": "6.0.0-beta.2" } diff --git a/local-tests/test.ts b/local-tests/test.ts index 255dabebb6..688f40e8a1 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -78,10 +78,18 @@ import { testPkpEthersWithPkpSessionSigsToEthSignTypedData } from './tests/testP import { testPkpEthersWithLitActionSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData'; import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil'; import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil'; +import { testExecuteJsSignAndCombineEcdsa } from './tests/testExecuteJsSignAndCombineEcdsa'; +import { testExecutJsDecryptAndCombine } from './tests/testExecuteJsDecryptAndCombine'; +import { testExecuteJsBroadcastAndCollect } from './tests/testExecuteJsBroadcastAndCollect'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); const devEnv = new TinnyEnvironment(); + + await devEnv.startTestnetManager(); + // wait for the testnet to be active before we start the tests. + await devEnv.pollTestnetForActive(); + await devEnv.init(); const eoaSessionSigsTests = { @@ -195,6 +203,11 @@ import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './t }, }; + const litActionCombiningTests = { + testExecuteJsSignAndCombineEcdsa, + testExecutJsDecryptAndCombine, + testExecuteJsBroadcastAndCollect, + }; const testConfig = { tests: { // testExample, @@ -209,6 +222,8 @@ import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './t ...pkpEthersTest.eoaSessionSigs, ...pkpEthersTest.pkpSessionSigs, ...pkpEthersTest.litActionSessionSigs, + + ...litActionCombiningTests }, devEnv, }; From 710e5e828dad3292a8119977e5109a2d89002017 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 14 May 2024 10:01:38 -0400 Subject: [PATCH 158/263] ref: remove local test changes --- local-tests/test.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/local-tests/test.ts b/local-tests/test.ts index 688f40e8a1..cc45dbeca1 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -78,18 +78,11 @@ import { testPkpEthersWithPkpSessionSigsToEthSignTypedData } from './tests/testP import { testPkpEthersWithLitActionSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData'; import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil'; import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil'; -import { testExecuteJsSignAndCombineEcdsa } from './tests/testExecuteJsSignAndCombineEcdsa'; -import { testExecutJsDecryptAndCombine } from './tests/testExecuteJsDecryptAndCombine'; -import { testExecuteJsBroadcastAndCollect } from './tests/testExecuteJsBroadcastAndCollect'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); const devEnv = new TinnyEnvironment(); - await devEnv.startTestnetManager(); - // wait for the testnet to be active before we start the tests. - await devEnv.pollTestnetForActive(); - await devEnv.init(); const eoaSessionSigsTests = { @@ -203,11 +196,6 @@ import { testExecuteJsBroadcastAndCollect } from './tests/testExecuteJsBroadcast }, }; - const litActionCombiningTests = { - testExecuteJsSignAndCombineEcdsa, - testExecutJsDecryptAndCombine, - testExecuteJsBroadcastAndCollect, - }; const testConfig = { tests: { // testExample, @@ -222,8 +210,6 @@ import { testExecuteJsBroadcastAndCollect } from './tests/testExecuteJsBroadcast ...pkpEthersTest.eoaSessionSigs, ...pkpEthersTest.pkpSessionSigs, ...pkpEthersTest.litActionSessionSigs, - - ...litActionCombiningTests }, devEnv, }; From 636d535e23aa6b318009a672b609888b72583ba1 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 14 May 2024 10:14:07 -0400 Subject: [PATCH 159/263] chore: fmt --- lit.config.json | 2 +- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- tsconfig.json | 17 ++++------------- 28 files changed, 31 insertions(+), 40 deletions(-) diff --git a/lit.config.json b/lit.config.json index e8940535fc..b9b0a3c3d4 100644 --- a/lit.config.json +++ b/lit.config.json @@ -115,4 +115,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 89c354b6df..49d1652d30 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 9f5ccbdbed..75e6372dcf 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index a9a00f5bd0..d5695e23ce 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index e634894f30..c0ffab694b 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index e1f61d234e..b20ccfab90 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 125e5e821a..c4ca0de3d5 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/core/package.json b/packages/core/package.json index 13f746d540..24c776acbe 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 3fbcb8afe6..b5d169bf6e 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index 43f5ba5da4..e7b40c8f45 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index ccc7191848..0542df409e 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index af71708e3a..db56194122 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index a116970c5d..454bf1cb1c 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index 4f22f5d77d..bb18a0d62d 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index 690a0f43d9..7baa7d6072 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 8f9327012a..23e3b2806c 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 41be3817eb..5c69732cd0 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 690f074853..a5010da387 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 4e6455f1bd..862e7e45ea 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 5abcd729c7..1541da1fd4 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 84b89cc521..8e4c005481 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index db662e4e5b..2b7b882243 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 3bc535092c..2db9f2674d 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 92b7ce10eb..72dfb5a04f 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 729c01b53c..eb0b681e3b 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index a2bd3bf457..91533ec2aa 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index a8ce6d730a..c95c6e6a1e 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.2", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index e8f4e19b50..d79d1c4238 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,24 +10,15 @@ "importHelpers": true, "target": "ES2020", "module": "ES2020", - "lib": [ - "ES2020", - "dom", - "ES2021.String" - ], + "lib": ["ES2020", "dom", "ES2021.String"], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "paths": { - "@lit-protocol/*": [ - "packages/*/src" - ] + "@lit-protocol/*": ["packages/*/src"] } }, - "exclude": [ - "node_modules", - "tmp" - ] -} \ No newline at end of file + "exclude": ["node_modules", "tmp"] +} From d2729ceef64b22b0af88922b726711ec7c3f6fe9 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 16:44:32 +0100 Subject: [PATCH 160/263] feat: remove e2e-nodejs and replace it with Tinny, and use Tinny for CI --- .github/workflows/ci.yml | 6 +- README.md | 15 +- e2e-nodejs/00-setup.mjs | 33 - .../test-block-has-update-after-exp.mjs | 55 -- ...est-concurrent-signing-2-parallel-sigs.mjs | 196 ------ .../0_manual-tests/test-epoch-cache.mjs | 39 -- .../0_manual-tests/test-lit-action-2-sigs.mjs | 72 --- .../test-lit-action-run-target-node.mjs | 51 -- ...test-pkp-ethers-integrations-tableland.mjs | 105 --- e2e-nodejs/0_manual-tests/test-pkp-sui.mjs | 71 -- e2e-nodejs/0_manual-tests/test-recap.mjs | 47 -- .../0_manual-tests/test-relayer-mint.mjs | 118 ---- ...ail-without-rli-when-state-is-recorded.mjs | 107 --- e2e-nodejs/README.md | 34 - ...est-concurrent-signing-1-parallel-sigs.mjs | 138 ---- .../test-connection-cert-caching.mjs | 53 -- .../test-connection-multi-network.mjs | 30 - .../test-connection-threshold.mjs | 37 -- .../group-connection/test-connection.mjs | 29 - .../test-latest-blockhash.mjs | 32 - .../test-contracts-get-read-validators.mjs | 30 - .../test-contracts-read-mint-cost.mjs | 23 - .../test-contracts-read-with-pkp-ethers.mjs | 40 -- .../test-contracts-read-with-private-key.mjs | 35 - .../test-contracts-read-with-provider.mjs | 32 - ...rite-mint-a-pkp-and-set-scope-1-2-easy.mjs | 83 --- ...te-mint-a-pkp-and-set-scope-1-advanced.mjs | 86 --- ...acts-write-mint-a-pkp-then-set-scope-1.mjs | 107 --- ...t-a-pkp-with-a-pkp-with-no-permissions.mjs | 104 --- ...s-write-mint-a-pkp-with-no-permissions.mjs | 45 -- .../group-custom-network/resolver.data.js | 604 ----------------- ...t-custom-contract-passthrough-resolver.mjs | 32 - .../test-hotwallet-with-blockhash.mjs | 133 ---- .../test-block-has-update-after-exp.mjs | 55 -- .../test-lit-action-1-sig.mjs | 50 -- .../test-lit-action-claim-key.mjs | 59 -- .../test-lit-action-get-ipfsid.mjs | 24 - .../test-lit-action-grouped-claims.mjs | 75 --- .../test-lit-action-json-response.mjs | 60 -- .../group-lit-actions/test-lit-action-log.mjs | 31 - .../test-lit-action-no-params.mjs | 42 -- ...st-should-init-with-correct-properties.mjs | 38 -- ...kp-auth-meth-authentication-no-methods.mjs | 80 --- .../test-pkp-auth-method-authentication.mjs | 81 --- ...-auth-method-multiple-auth-method-mint.mjs | 88 --- .../test-pkp-eth-wallet-provider.mjs | 33 - .../test-pkp-client-with-rpc.mjs | 72 --- ...st-pkp-client-without-rpc-sign-message.mjs | 34 - .../test-pkp-client-without-rpc-sign-tx.mjs | 68 -- .../test-pkp-cosmos-send-tx.mjs | 77 --- .../test-pkp-cosmos-stargate-client.mjs | 67 -- .../group-pkp-cosmos/test-pkp-cosmos.mjs | 46 -- .../test-pkp-encryption-acc-schema.mjs | 608 ------------------ .../test-pkp-encryption-decryption-file.mjs | 63 -- ...st-pkp-encryption-decryption-json-file.mjs | 57 -- ...-pkp-encryption-decryption-json-string.mjs | 50 -- .../test-pkp-encryption-decryption-nodes.mjs | 127 ---- .../test-pkp-encryption-decryption-string.mjs | 56 -- ...t-pkp-encryption-decryption-zip-string.mjs | 60 -- .../test-pkp-multiple-auth-contexts.mjs | 143 ---- ...th-session-sigs-eth-wallet-auth-method.mjs | 81 --- ...p-sign-with-session-sigs-session-cache.mjs | 92 --- e2e-nodejs/group-pkp-sign/test-pkp-sign.mjs | 50 -- .../group-pkp-sui/test-pkp-sui-send-tx.mjs | 102 --- .../group-rli-mint/test-rli-mint-day.mjs | 62 -- .../test-rli-mint-kilosecond.mjs | 60 -- .../group-rli-mint/test-rli-mint-second.mjs | 62 -- ...li-from-lit-node-client-diff-delegatee.mjs | 232 ------- ...-rli-from-lit-node-client-no-delegatee.mjs | 184 ------ ...node-client-optional-capacity-token-id.mjs | 209 ------ ...li-from-lit-node-client-self-delegatee.mjs | 201 ------ .../group-rli/test-rli-pkp-as-delegatee.mjs | 276 -------- e2e-nodejs/index.mjs | 196 ------ e2e-nodejs/loader.mjs | 160 ----- e2e-nodejs/polyfills.mjs | 2 - e2e-nodejs/template.mjs | 30 - package.json | 2 - tools/scripts/tools.mjs | 22 +- tools/scripts/utils.mjs | 69 -- yarn.lock | 23 +- 80 files changed, 28 insertions(+), 6953 deletions(-) delete mode 100644 e2e-nodejs/00-setup.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-block-has-update-after-exp.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-concurrent-signing-2-parallel-sigs.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-epoch-cache.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-lit-action-2-sigs.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-lit-action-run-target-node.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-pkp-ethers-integrations-tableland.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-pkp-sui.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-recap.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-relayer-mint.mjs delete mode 100644 e2e-nodejs/0_manual-tests/test-rli-should-fail-without-rli-when-state-is-recorded.mjs delete mode 100644 e2e-nodejs/README.md delete mode 100644 e2e-nodejs/group-concurrent-signing/test-concurrent-signing-1-parallel-sigs.mjs delete mode 100644 e2e-nodejs/group-connection/test-connection-cert-caching.mjs delete mode 100644 e2e-nodejs/group-connection/test-connection-multi-network.mjs delete mode 100644 e2e-nodejs/group-connection/test-connection-threshold.mjs delete mode 100644 e2e-nodejs/group-connection/test-connection.mjs delete mode 100644 e2e-nodejs/group-connection/test-latest-blockhash.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-get-read-validators.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-read-mint-cost.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-read-with-pkp-ethers.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-read-with-private-key.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-read-with-provider.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-2-easy.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-advanced.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-then-set-scope-1.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-a-pkp-with-no-permissions.mjs delete mode 100644 e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-no-permissions.mjs delete mode 100644 e2e-nodejs/group-custom-network/resolver.data.js delete mode 100644 e2e-nodejs/group-custom-network/test-custom-contract-passthrough-resolver.mjs delete mode 100644 e2e-nodejs/group-hotwallet-with-blockhash/test-hotwallet-with-blockhash.mjs delete mode 100644 e2e-nodejs/group-latest-blockhash-update/test-block-has-update-after-exp.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-1-sig.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-claim-key.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-get-ipfsid.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-grouped-claims.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-json-response.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-log.mjs delete mode 100644 e2e-nodejs/group-lit-actions/test-lit-action-no-params.mjs delete mode 100644 e2e-nodejs/group-lit-auth-client/test-should-init-with-correct-properties.mjs delete mode 100644 e2e-nodejs/group-pkp-auth-method/test-pkp-auth-meth-authentication-no-methods.mjs delete mode 100644 e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-authentication.mjs delete mode 100644 e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-multiple-auth-method-mint.mjs delete mode 100644 e2e-nodejs/group-pkp-auth-method/test-pkp-eth-wallet-provider.mjs delete mode 100644 e2e-nodejs/group-pkp-client/test-pkp-client-with-rpc.mjs delete mode 100644 e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-message.mjs delete mode 100644 e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-tx.mjs delete mode 100644 e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-send-tx.mjs delete mode 100644 e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-stargate-client.mjs delete mode 100644 e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-acc-schema.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-file.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-file.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-string.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-nodes.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-string.mjs delete mode 100644 e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-zip-string.mjs delete mode 100644 e2e-nodejs/group-pkp-session-sigs/test-pkp-multiple-auth-contexts.mjs delete mode 100644 e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-eth-wallet-auth-method.mjs delete mode 100644 e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-session-cache.mjs delete mode 100644 e2e-nodejs/group-pkp-sign/test-pkp-sign.mjs delete mode 100644 e2e-nodejs/group-pkp-sui/test-pkp-sui-send-tx.mjs delete mode 100644 e2e-nodejs/group-rli-mint/test-rli-mint-day.mjs delete mode 100644 e2e-nodejs/group-rli-mint/test-rli-mint-kilosecond.mjs delete mode 100644 e2e-nodejs/group-rli-mint/test-rli-mint-second.mjs delete mode 100644 e2e-nodejs/group-rli/test-rli-from-lit-node-client-diff-delegatee.mjs delete mode 100644 e2e-nodejs/group-rli/test-rli-from-lit-node-client-no-delegatee.mjs delete mode 100644 e2e-nodejs/group-rli/test-rli-from-lit-node-client-optional-capacity-token-id.mjs delete mode 100644 e2e-nodejs/group-rli/test-rli-from-lit-node-client-self-delegatee.mjs delete mode 100644 e2e-nodejs/group-rli/test-rli-pkp-as-delegatee.mjs delete mode 100644 e2e-nodejs/index.mjs delete mode 100644 e2e-nodejs/loader.mjs delete mode 100644 e2e-nodejs/polyfills.mjs delete mode 100644 e2e-nodejs/template.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73748b98a8..09ba122ff2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: '18' + node-version: '19' - name: Install project dependencies run: yarn install - name: Build packages @@ -54,4 +54,6 @@ jobs: run: yarn build - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: yarn test:e2e:node --group=connection --group=lit-actions --group=pkp-auth-method --group=pkp-ethers --group=pkp-encryption-decryption --group=pkp-session-sigs --group=lit-auth-client \ No newline at end of file + run: NETWORK=cayenne yarn test:local --filtertestUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning, + testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs, + testEthAuthSigToEncryptDecryptString \ No newline at end of file diff --git a/README.md b/README.md index bed20d7b87..aa955c07f2 100644 --- a/README.md +++ b/README.md @@ -154,15 +154,10 @@ yarn nx run nodejs:serve yarn test:unit ``` -## Run E2E tests +## Run E2E tests in nodejs ``` - -// -- web -yarn test:e2e:web - -// -- node -yarn test:e2e:node +yarn test:local ``` # Advanced @@ -248,7 +243,7 @@ You must have at least nodejs v18 to do this. 3. Build all the packages with `yarn build` -4. Run the unit tests with `yarn test:unit` & e2e node tests `yarn test:e2e:nodejs` locally & ensure that they pass +4. Run the unit tests with `yarn test:unit` & e2e node tests `yarn test:local` locally & ensure that they pass 5. Update the docs with `yarn gen:docs --push` @@ -272,9 +267,7 @@ yarn node ./tools/scripts/pub.mjs --tag serrano-jalapeno The following will serve the react testing app and launch the cypress e2e testing after ```sh -yarn test:e2e:web -or -yarn test:e2e:node +yarn test:local ``` ### Environments diff --git a/e2e-nodejs/00-setup.mjs b/e2e-nodejs/00-setup.mjs deleted file mode 100644 index 4bcf0afa43..0000000000 --- a/e2e-nodejs/00-setup.mjs +++ /dev/null @@ -1,33 +0,0 @@ -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import LITCONFIG from '../lit.config.json' assert { type: 'json' }; -import { fail } from '../tools/scripts/utils.mjs'; -import { LocalStorage } from 'node-localstorage'; -import crypto from './polyfills.mjs'; - -// -- This is to fix CI "ReferenceError: crypto is not defined" error -if (typeof globalThis.crypto === 'undefined') { - globalThis.crypto = crypto; -} - -const client = new LitNodeClient({ - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - minNodeCount: globalThis.LitCI.minNodeCount, - checkNodeAttestation: globalThis.LitCI.sevAttestation, - storageProvider: { - provider: new LocalStorage('./storage.test.db'), - }, -}); -await client.connect(); - -// ==================== Validation ==================== -if (client.ready !== true) { - fail('client not ready'); -} - -if (LITCONFIG.CONTROLLER_AUTHSIG === undefined) { - fail('Controller authSig cannot be empty'); -} - -// ==================== Success ==================== -export { client }; diff --git a/e2e-nodejs/0_manual-tests/test-block-has-update-after-exp.mjs b/e2e-nodejs/0_manual-tests/test-block-has-update-after-exp.mjs deleted file mode 100644 index 010864d571..0000000000 --- a/e2e-nodejs/0_manual-tests/test-block-has-update-after-exp.mjs +++ /dev/null @@ -1,55 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LocalStorage } from 'node-localstorage'; - -export async function main() { - const client = new LitNodeClient({ - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - minNodeCount: globalThis.LitCI.minNodeCount, - checkNodeAttestation: globalThis.LitCI.sevAttestation, - storageProvider: { - provider: new LocalStorage('./storage.test.db'), - }, - }); - - await client.connect(); - console.log(client.hdRootPubkeys); - let subnetKey = '' + client.subnetPubKey; - let rootKeys = client.hdRootPubkeys; - let blockhash = await client.getLatestBlockhash(); - await new Promise((resolve, _reject) => { - setTimeout(resolve, 35_000); - }); - - let updatedBlockhash = await client.getLatestBlockhash(); - - if (blockhash === updatedBlockhash) { - return fail('block hash should be updated from handshake'); - } - - if ( - rootKeys.filter((item) => client.hdRootPubkeys.includes(item) === false) - .length > 0 || - subnetKey != client.subnetPubKey - ) { - console.log( - 'current root keys: ', - client.hdRootPubkeys, - 'old root keys: ', - rootKeys - ); - console.log( - 'old subnet key: ', - subnetKey, - 'current subnnet key: ', - client.subnetPubKey - ); - return fail('network properties do not match after syncing'); - } - console.log('block hashes: ', blockhash, updatedBlockhash); - return success('block hash updates after expiration period'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-concurrent-signing-2-parallel-sigs.mjs b/e2e-nodejs/0_manual-tests/test-concurrent-signing-2-parallel-sigs.mjs deleted file mode 100644 index 686bf80c8b..0000000000 --- a/e2e-nodejs/0_manual-tests/test-concurrent-signing-2-parallel-sigs.mjs +++ /dev/null @@ -1,196 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Test Logic ==================== - let results = await Promise.all([ - (async () => { - console.time('request 1'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - - async function signMultipleSigs(numSigs, toSign, publicKey) { - const sigShares = []; - for(let i = 0; i < numSigs; i++) { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig" + i, - }); - sigShares.push(sigShare); - } - return sigShares; - } - - const sigShares = await signMultipleSigs(numberOfSigs, dataToSign, publicKey); - })();`, - authMethods: [], - jsParams: { - numberOfSigs: 2, - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 1'); - return res; - })(), - (async () => { - console.time('request 2'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - - async function signMultipleSigs(numSigs, toSign, publicKey) { - const sigShares = []; - for(let i = 0; i < numSigs; i++) { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig" + i, - }); - sigShares.push(sigShare); - } - return sigShares; - } - - const sigShares = await signMultipleSigs(numberOfSigs, dataToSign, publicKey); - })();`, - authMethods: [], - jsParams: { - numberOfSigs: 2, - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 2'); - return res; - })(), - (async () => { - console.time('request 3'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - - async function signMultipleSigs(numSigs, toSign, publicKey) { - const sigShares = []; - for(let i = 0; i < numSigs; i++) { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig" + i, - }); - sigShares.push(sigShare); - } - return sigShares; - } - - const sigShares = await signMultipleSigs(numberOfSigs, dataToSign, publicKey); - })();`, - authMethods: [], - jsParams: { - numberOfSigs: 2, - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 3'); - return res; - })(), - (async () => { - console.time('request 4'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - - async function signMultipleSigs(numSigs, toSign, publicKey) { - const sigShares = []; - for(let i = 0; i < numSigs; i++) { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig" + i, - }); - sigShares.push(sigShare); - } - return sigShares; - } - - const sigShares = await signMultipleSigs(numberOfSigs, dataToSign, publicKey); - })();`, - authMethods: [], - jsParams: { - numberOfSigs: 2, - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 4'); - return res; - })(), - (async () => { - console.time('request 5'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - - async function signMultipleSigs(numSigs, toSign, publicKey) { - const sigShares = []; - for(let i = 0; i < numSigs; i++) { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig" + i, - }); - sigShares.push(sigShare); - } - return sigShares; - } - - const sigShares = await signMultipleSigs(numberOfSigs, dataToSign, publicKey); - })();`, - authMethods: [], - jsParams: { - numberOfSigs: 2, - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 5'); - return res; - })(), - ]); - // ==================== Post-Validation ==================== - for (const res of results) { - Object.entries(res.signatures).forEach(([key, sig]) => { - if (key !== 'sig0' && key !== 'sig1') { - return fail(`sig name ${key} is not expected`); - } - - ['r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (sig[key] === undefined) { - return fail(`sig.${key} is undefined, empty, or null`); - } - } - ); - }); - } - - // ==================== Success ==================== - return success('Lit Action should log sign x1 sig in parallel'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-epoch-cache.mjs b/e2e-nodejs/0_manual-tests/test-epoch-cache.mjs deleted file mode 100644 index 08d1f7cdfb..0000000000 --- a/e2e-nodejs/0_manual-tests/test-epoch-cache.mjs +++ /dev/null @@ -1,39 +0,0 @@ -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import crypto from '../polyfills.mjs'; - -if (typeof globalThis.crypto === 'undefined') { - globalThis.crypto = crypto; -} - -globalThis.litConfig = { - debug: true, -}; - -const DATA_TO_SIGN = new Uint8Array( - await crypto.subtle.digest('SHA-256', new TextEncoder().encode('Hello world')) -); - -export async function main() { - try { - const litNodeClient = new LitNodeClient({ - litNetwork: 'cayenne', - debug: true, - }); - - await litNodeClient.connect(); - - // for every second, get new epoch number - setInterval(async () => { - try { - const epochNumber = litNodeClient.currentEpochNumber; - console.log('epochNumber:', epochNumber); - } catch (e) { - console.log(e); - } - }, 1000); - } catch (e) { - console.log(e); - } -} - -main(); diff --git a/e2e-nodejs/0_manual-tests/test-lit-action-2-sigs.mjs b/e2e-nodejs/0_manual-tests/test-lit-action-2-sigs.mjs deleted file mode 100644 index e7c88e42f3..0000000000 --- a/e2e-nodejs/0_manual-tests/test-lit-action-2-sigs.mjs +++ /dev/null @@ -1,72 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - async function signMultipleSigs(numSigs, toSign, publicKey) { - const sigShares = []; - for(let i = 0; i < numSigs; i++) { - const DATA_TO_SIGN = new Uint8Array( - await crypto.subtle.digest('SHA-256', new TextEncoder().encode('Hello world' + i)) - ); - const sigShare = await LitActions.signEcdsa({ - toSign: DATA_TO_SIGN, - publicKey, - sigName: "sig" + i, - }); - sigShares.push(sigShare); - } - return sigShares; - } - - const sigShares = await signMultipleSigs(numberOfSigs, signatureData, publicKey); - - })();`, - authMethods: [], - jsParams: { - numberOfSigs: 5, - signatureData: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - sigName: 'fooSig', - }, - }); - - // ==================== Post-Validation ==================== - if (!res.signatures || Object.keys(res.signatures).length !== 5) { - return fail( - `should have 2 signatures but received ${ - Object.keys(res.signatures).length ?? 0 - }` - ); - } - - // Checking each sig in the signatures array - Object.entries(res.signatures).forEach(([key, sig]) => { - if (key !== 'sig0' && key !== 'sig1') { - return fail(`sig name ${key} is not expected`); - } - - ['r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (sig[key] === undefined) { - return fail(`sig.${key} is undefined, empty, or null`); - } - } - ); - }); - - // ==================== Success ==================== - return success('Lit Action should be able to sign data x2 sigs'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-lit-action-run-target-node.mjs b/e2e-nodejs/0_manual-tests/test-lit-action-run-target-node.mjs deleted file mode 100644 index a0d9903e07..0000000000 --- a/e2e-nodejs/0_manual-tests/test-lit-action-run-target-node.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - targetNodeRange: 2, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - - // ==================== Post-Validation ==================== - - if (!res.signatures || Object.keys(res.signatures).length <= 0) { - return fail( - `should have at least 1 signature but received ${ - Object.keys(res.signatures).length - }` - ); - } - - ['sig', 'r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (!res.signatures.sig[key]) { - return fail(`sig.${key} is undefined, empty, or null`); - } - } - ); - // ==================== Success ==================== - return success('Lit Action should log sign x1 sig using target node 2'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-pkp-ethers-integrations-tableland.mjs b/e2e-nodejs/0_manual-tests/test-pkp-ethers-integrations-tableland.mjs deleted file mode 100644 index ec3b5495db..0000000000 --- a/e2e-nodejs/0_manual-tests/test-pkp-ethers-integrations-tableland.mjs +++ /dev/null @@ -1,105 +0,0 @@ -/** - * ========== !!! NOTE !!! ========== - * Make sure you have topped up your account with ETH. In this case, we are using - * the Polygon Mumbai testnet. You can get some testnet ETH here: - * https://mumbaifaucet.com/ - * https://faucet.quicknode.com/polygon/mumbai - */ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethRequestHandler } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; - -// -- Integration -import { Database } from '@tableland/sdk'; - -export async function main() { - // ==================== Setup ==================== - const pkpEthersWallet = new PKPEthersWallet({ - controllerAuthSig: LITCONFIG.CONTROLLER_AUTHSIG, - pkpPubKey: LITCONFIG.PKP_PUBKEY, - rpc: LITCONFIG.CHRONICLE_RPC, - }); - - // ==================== Test Logic ==================== - - // -- 1. set wallet rpc - pkpEthersWallet.setRpc('https://polygon-mumbai-bor.publicnode.com'); - await pkpEthersWallet.init(); - - // -- 2. init db - const db = new Database({ signer: pkpEthersWallet }); - - // -- 3. create a table - let tableName = ''; - let tbReceipt = null; - try { - const prefix = 'my_table'; - const { meta: create } = await db - .prepare(`CREATE TABLE ${prefix} (id integer primary key, val text);`) - .run(); - - tableName = create.txn?.name ?? ''; // e.g., my_table_80001_8085 - - tbReceipt = await create.txn?.wait(); - } catch (e) { - return fail(`Failed to create table: ${e}`); - } - - if (!tbReceipt) { - return fail('should create a tableland database & table'); - } - - // -- 4 - set gas price & limit - // This should fix "replacement fee too low" - // If a current transaction exists with the same nonce, increment the gas price - pkpEthersWallet.setGasPrice( - (await pkpEthersWallet.getGasPrice()).mul(900).div(100) - ); - pkpEthersWallet.setGasLimit(ethers.utils.hexlify(600000)); - - // -- 5. write to table - let writeReceipt = null; - try { - const { meta: insert } = await db - .prepare(`INSERT INTO ${tableName} (id, val) VALUES (?, ?);`) - .bind(0, 'Lit-Tableland') - .run(); - - writeReceipt = await insert.txn?.wait(); - } catch (e) { - return fail(`Failed to write to table: ${e}`); - } - - if (!writeReceipt) { - return fail('should write to table'); - } - - // -- 5. read from table - let readResult; - try { - const { results } = await db.prepare(`SELECT * FROM ${tableName};`).run(); - readResult = results; - } catch (e) { - return fail(`Failed to read from table: ${e}`); - } - - // ==================== Post-Validation ==================== - - // if (!res.logs.includes('hello world')) { - // return fail('lit action client should be ready'); - // } - // if (!res.success) { - // return fail('response should be success'); - // } - // ==================== Success ==================== - return success(`should create a tableland database, write & read the table -table name: ${tableName} -table hash: ${tbReceipt?.transactionHash} -write hash: ${writeReceipt?.transactionHash} -read value: ${readResult[0].val}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-pkp-sui.mjs b/e2e-nodejs/0_manual-tests/test-pkp-sui.mjs deleted file mode 100644 index 78c220e0ec..0000000000 --- a/e2e-nodejs/0_manual-tests/test-pkp-sui.mjs +++ /dev/null @@ -1,71 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPSuiWallet } from '@lit-protocol/pkp-sui'; - -import { JsonRpcProvider, devnetConnection } from '@mysten/sui.js'; - -// NOTE: You can check your tx using https://suiexplorer.com/?network=devnet -export async function main() { - // ==================== Setup ==================== - const provider = new JsonRpcProvider(devnetConnection); - - const suiWallet = new PKPSuiWallet( - { - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - provider - ); - - await suiWallet.init(); - - // ==================== Test Logic ==================== - const pkpSuiAddress = await suiWallet.getAddress(); - const balance = await provider.getBalance({ - owner: pkpSuiAddress, - }); - - if (balance.totalBalance <= 0) { - try { - const response = await fetch('https://faucet.devnet.sui.io/gas', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - FixedAmountRequest: { recipient: pkpSuiAddress }, // Replace with your SUI address - }), - }); - - if (!response.ok) throw Error(response.statusText); - - const data = await response.json(); - console.log('Success:', data); - } catch (error) { - console.error('Error:', error); - } - } - - const newBalance = await provider.getBalance({ - owner: pkpSuiAddress, - }); - - // ==================== Post-Validation ==================== - if (!suiWallet.litNodeClientReady) { - return fail('litNodeClient should be ready'); - } - - if (pkpSuiAddress !== LITCONFIG.PKP_SUI_ADDRESS) { - return fail(`Expected ${pkpSuiAddress} to be ${LITCONFIG.PKP_SUI_ADDRESS}`); - } - - if (newBalance.totalBalance <= 0) { - return fail(`balance should have totalBalance > 0`); - } - - // ==================== Success ==================== - return success( - `PKPSuiWallet should get address and balance ${newBalance.totalBalance} ` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-recap.mjs b/e2e-nodejs/0_manual-tests/test-recap.mjs deleted file mode 100644 index 7bbbc616b5..0000000000 --- a/e2e-nodejs/0_manual-tests/test-recap.mjs +++ /dev/null @@ -1,47 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -// import { client } from '../00-setup.mjs'; -import { RecapSessionCapabilityObject } from '@lit-protocol/auth-helpers'; - -export async function main() { - // ==================== Setup ==================== - - const att = { - someResource: { - 'lit-ratelimitincrease/1337': [{}], - }, - }; - - const recapSessionCapabilityObject = new RecapSessionCapabilityObject( - att, - [] - ); - - const mockAuthSig = { - sig: '0x137b66529678d1fc58ab5b340ad036082af5b9912f823ba22c2851b8f50990a666ad8f2ab2328e8c94414c0a870163743bde91a5f96e9f967fd45d5e0c17c3911b', - derivedVia: 'web3.eth.personal.sign', - signedMessage: - 'localhost wants you to sign in with your Ethereum account:\n0xeF71c2604f17Ec6Fc13409DF24EfdC440D240d37\n\nTESTING TESTING 123\n\nURI: https://localhost/login\nVersion: 1\nChain ID: 1\nNonce: eoeo0dsvyLL2gcHsC\nIssued At: 2023-11-17T15:04:20.324Z\nExpiration Time: 2215-07-14T15:04:20.323Z', - address: '0xeF71c2604f17Ec6Fc13409DF24EfdC440D240d37', - }; - - await recapSessionCapabilityObject.addRateLimitAuthSig(mockAuthSig); - - // ==================== Test Logic ==================== - const proof = recapSessionCapabilityObject.proofs[0]; - const expectedResult = 'QmQiy7M88uboUkSF68Hv73NWL8dnrbMNZmbstVVi3UVrgM'; - - // ==================== Post-Validation ==================== - if (proof === expectedResult) { - return success( - `Recap Session Capability has proof at index 0 of ${expectedResult}` - ); - } - - return fail( - `Failed to get proof from Recap Session Capability, it should be ${expectedResult} but is ${proof}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-relayer-mint.mjs b/e2e-nodejs/0_manual-tests/test-relayer-mint.mjs deleted file mode 100644 index abb34520f9..0000000000 --- a/e2e-nodejs/0_manual-tests/test-relayer-mint.mjs +++ /dev/null @@ -1,118 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; -import { LocalStorage } from 'node-localstorage'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; -import { AuthMethodScope } from '@lit-protocol/constants'; - -async function getAuthSig(wallet, litNodeClient) { - const domain = 'localhost'; - const origin = 'https://localhost/login'; - const statement = - 'This is a test statement. You can put anything you want here.'; - - const address = await wallet.getAddress(); - - const nonce = await litNodeClient.getLatestBlockhash(); - - const siweMessage = new siwe.SiweMessage({ - domain, - address, - statement, - uri: origin, - version: '1', - chainId: 1, - nonce, - expirationTime: new Date(Date.now() + 60_000 * 60).toISOString(), - }); - - const messageToSign = siweMessage.prepareMessage(); - - // Sign the message and format the authSig - const signature = await wallet.signMessage(messageToSign); - - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: address, - }; - - return authSig; -} - -export async function main() { - // ==================== Setup ==================== - - if (!process.env.NETWORK) { - return fail(`NETWORK env var not set.`); - } - - if (!['cayenne', 'habanero', 'manzano'].includes(process.env.NETWORK)) { - return fail( - `Invalid NETWORK env var set. It has to be either 'manzano', 'habanero', or 'cayenne'` - ); - } - - // -- setting up lit node client - const litNodeClient = new LitNodeClient({ - litNetwork: process.env.NETWORK, - debug: true, - checkNodeAttestation: true, - storageProvider: { - provider: new LocalStorage('./storage.test.db'), - }, - }); - - await litNodeClient.connect(); - - // -- controller wallet - const wallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ); - - // -- setting up lit auth client, which uses - // the lit node client so that it knows which network to use - const litAuthClient = new LitAuthClient({ - litNodeClient, - litRelayConfig: { - relayApiKey: '...', - }, - debug: true, - }); - - console.log( - 'litAuthClient.litNodeClient.config:', - litAuthClient.litNodeClient.config - ); - - // -- setting up auth provider - const authSig = await getAuthSig(wallet, litNodeClient); - - const authMethod = { - authMethodType: 1, - accessToken: JSON.stringify(authSig), - }; - - console.log('authMethod', authMethod); - - // ==================== Test Logic ==================== - let res = await litAuthClient.mintPKPWithAuthMethods([authMethod], { - pkpPermissionScopes: [[AuthMethodScope.SignAnything]], - sendPkpToitself: true, - addPkpEthAddressAsPermittedAddress: true, - }); - - if (!res) { - return fail(`Res is empty, expected a response from the relayer`); - } - - // ==================== Post-Validation ==================== - return success(`Minted PKP via the relayer with auth methods`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/0_manual-tests/test-rli-should-fail-without-rli-when-state-is-recorded.mjs b/e2e-nodejs/0_manual-tests/test-rli-should-fail-without-rli-when-state-is-recorded.mjs deleted file mode 100644 index 15bedbd040..0000000000 --- a/e2e-nodejs/0_manual-tests/test-rli-should-fail-without-rli-when-state-is-recorded.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; -import { LitContracts } from '@lit-protocol/contracts-sdk'; - -// NETWORK=habanero E2E_CACHE=true MINT_NEW=false DEBUG=true yarn test:e2e:node --filter=test-recap-should -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -async function getAuthSig(wallet, litNodeClient) { - const domain = 'localhost'; - const origin = 'https://localhost/login'; - const statement = - 'This is a test statement. You can put anything you want here.'; - - const address = await wallet.getAddress(); - - const nonce = await litNodeClient.getLatestBlockhash(); - - const siweMessage = new siwe.SiweMessage({ - domain, - address, - statement, - uri: origin, - version: '1', - chainId: 1, - nonce, - expirationTime: new Date(Date.now() + 60_000 * 60).toISOString(), - }); - - const messageToSign = siweMessage.prepareMessage(); - - // Sign the message and format the authSig - const signature = await wallet.signMessage(messageToSign); - - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: address, - }; - - return authSig; -} - -export async function main() { - // ==================== Test Logic ==================== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const walletNoRLI = new ethers.Wallet( - '0x89faea1d1a74d9de8a807771d17c7cce20cce496244b5f8350330742ba37d099', - provider - ); - - const authSig = await getAuthSig(walletNoRLI, client); - console.log('authSig:', authSig); - - let contractClient = new LitContracts({ - signer: walletNoRLI, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - let pkpMintRes = await contractClient.pkpNftContractUtils.write.mint(); - - const pkpInfo = pkpMintRes.pkp; - - try { - await client.executeJs({ - authSig: authSig, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: pkpInfo.publicKey, - }, - }); - } catch (e) { - console.log('e:', e.errorCode); - - if (e.errorCode === 'rate_limit_exceeded') { - return success('should fail when no Capacity Credits NFT'); - } - - return fail('should fail when no Capacity Credits NFT'); - } - - return fail( - 'shouldnt reach here at fresh state, but if nodes have recoded your state then this test will fail' - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/README.md b/e2e-nodejs/README.md deleted file mode 100644 index 1f2c58f068..0000000000 --- a/e2e-nodejs/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# End to End NodeJS testing - -End to end testing environment for different operations on the Lit Network - -- Message singing -- Transaction signing -- Session signature generation / signing -- Lit Action api testing -- LitContracts testing -- Concurrency operation tests - - 1 signature tests - - multi signature tests - -## Usage - -To run all tests in all groups you can use the command -`yarn test:e2e:node` - -Each test suite is contained in a single folder which is called a `group` groups can be filtered by the `filter` flag - -`yarn test:e2e:node --group=lit-actions` -In the above example, only tests in the `group-lit-actions` will run as group flags omit the `group` prefix - -`yarn test:e2e:node --group=lit-actions --filter=1-sig` -In the above example, we only run the `lit-actions` test group with a filter on the `test-lit-action-1-sig` which is reduced to `1-sig` from the `group` flag - -## environment Configuration - -``` -NETWORK = cayenne | internalDev #Configures the network context for the test run -DEBUG = true | false # Turns on or off logging -CHECK_SEV = true | false # Configures checking of sev snp attestation reports -MINT_NEW = true | false # Enables provisioning of new keys for the test run -``` diff --git a/e2e-nodejs/group-concurrent-signing/test-concurrent-signing-1-parallel-sigs.mjs b/e2e-nodejs/group-concurrent-signing/test-concurrent-signing-1-parallel-sigs.mjs deleted file mode 100644 index 2ad6ec8055..0000000000 --- a/e2e-nodejs/group-concurrent-signing/test-concurrent-signing-1-parallel-sigs.mjs +++ /dev/null @@ -1,138 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Test Logic ==================== - let results = await Promise.all([ - (async () => { - console.time('request 1'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 1'); - return res; - })(), - (async () => { - console.time('request 2'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 2'); - return res; - })(), - (async () => { - console.time('request 3'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 3'); - return res; - })(), - (async () => { - console.time('request 4'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 4'); - return res; - })(), - (async () => { - console.time('request 5'); - let res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - console.timeEnd('request 5'); - return res; - })(), - ]); - // ==================== Post-Validation ==================== - for (const res of results) { - if (Object.keys(res.signatures).length <= 0) { - return fail( - `should have at least 1 signature but received ${ - Object.keys(res.signatures).length - }` - ); - } - - ['sig', 'r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (!res.signatures.sig[key]) { - return fail(`sig.${key} is undefined, empty, or null`); - } - } - ); - } - - // ==================== Success ==================== - return success('Lit Action should log sign x1 sig in parallel'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-connection/test-connection-cert-caching.mjs b/e2e-nodejs/group-connection/test-connection-cert-caching.mjs deleted file mode 100644 index 8c0cdd4df2..0000000000 --- a/e2e-nodejs/group-connection/test-connection-cert-caching.mjs +++ /dev/null @@ -1,53 +0,0 @@ -import path from 'path'; -import { success, fail, testThis, log } from '../../tools/scripts/utils.mjs'; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LocalStorage } from 'node-localstorage'; -export async function main() { - const networks = ['habanero', 'manzano']; - const storageProvider = new LocalStorage('./storage.test.db'); - for (const network of networks) { - // ==================== Test Logic ==================== - const client = new LitNodeClient({ - litNetwork: network, - debug: globalThis.LitCI.debug, - storageProvider: { - provider: storageProvider, - }, - }); - log(`connecting to ${network.toUpperCase()}...`); - await client.connect(); - - // ==================== Post-Validation ==================== - if (!client.ready) { - return fail('client not ready'); - } - if (client.config.litNetwork !== network) { - return fail(`client not connected to ${network}`); - } - - if (storageProvider.length < 1) { - fail(`cache is not hydrated with certificates`); - } - - if (storageProvider.length < client.config.bootstrapUrls) { - fail( - `cache is not hydrated with enough certificates found: ${storageProvider.length} need ${client.config.bootstrapUrls.length}` - ); - } - for (let i = 0; i < storageProvider.length; i++) { - const key = storageProvider.key(i); - if (!key.includes('https://kdsintf.amd.com/')) { - fail( - 'found cache item which does not match indexing schema should contain: https://kdsintf.amd.com/vcek/v1/Milan/' - ); - } - } - } - - // ==================== Success ==================== - return success( - `Connected to ${networks.join(', ')} and found certs in cache` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-connection/test-connection-multi-network.mjs b/e2e-nodejs/group-connection/test-connection-multi-network.mjs deleted file mode 100644 index 2e721d5c7b..0000000000 --- a/e2e-nodejs/group-connection/test-connection-multi-network.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import path from 'path'; -import { success, fail, testThis, log } from '../../tools/scripts/utils.mjs'; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; - -export async function main() { - const networks = ['cayenne', 'habanero', 'manzano']; - - for (const network of networks) { - // ==================== Test Logic ==================== - const client = new LitNodeClient({ - litNetwork: network, - debug: globalThis.LitCI.debug, - }); - log(`connecting to ${network.toUpperCase()}...`); - await client.connect(); - - // ==================== Post-Validation ==================== - if (!client.ready) { - return fail('client not ready'); - } - if (client.config.litNetwork !== network) { - return fail(`client not connected to ${network}`); - } - } - - // ==================== Success ==================== - return success(`Connected to ${networks.join(', ')}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-connection/test-connection-threshold.mjs b/e2e-nodejs/group-connection/test-connection-threshold.mjs deleted file mode 100644 index 40ed3ddad5..0000000000 --- a/e2e-nodejs/group-connection/test-connection-threshold.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LitContracts } from '@lit-protocol/contracts-sdk'; - -export async function main() { - // ==================== Test Logic ==================== - const client = new LitNodeClient({ - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - checkNodeAttestation: globalThis.LitCI.sevAttestation, - }); - await client.connect(); - - // ==================== Post-Validation ==================== - if (!client.ready) { - return fail('client not ready'); - } - if (client.config.litNetwork !== globalThis.LitCI.network) { - return fail(`client not connected to ${globalThis.LitCI.network}`); - } - - let threshold = await LitContracts.getMinNodeCount(globalThis.LitCI.network); - console.log(`threshold ${threshold}`); - console.log(`config threshold ${client.config.minNodeCount}`); - - if (parseInt(client.config.minNodeCount, 10) !== parseInt(threshold, 10)) { - return fail( - `threshold does not match config threshold, network state diverged` - ); - } - - // ==================== Success ==================== - return success(`Connected to ${globalThis.LitCI.network}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-connection/test-connection.mjs b/e2e-nodejs/group-connection/test-connection.mjs deleted file mode 100644 index eaffb2ab7b..0000000000 --- a/e2e-nodejs/group-connection/test-connection.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; - -const LIT_NETWORK = 'cayenne'; - -export async function main() { - // ==================== Test Logic ==================== - const client = new LitNodeClient({ - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - checkNodeAttestation: globalThis.LitCI.sevAttestation, - }); - await client.connect(); - - // ==================== Post-Validation ==================== - if (!client.ready) { - return fail('client not ready'); - } - if (client.config.litNetwork !== globalThis.LitCI.network) { - return fail(`client not connected to ${globalThis.LitCI.network}`); - } - - // ==================== Success ==================== - return success(`Connected to ${globalThis.LitCI.network}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-connection/test-latest-blockhash.mjs b/e2e-nodejs/group-connection/test-latest-blockhash.mjs deleted file mode 100644 index 13e6161533..0000000000 --- a/e2e-nodejs/group-connection/test-latest-blockhash.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; - -const LIT_NETWORK = 'cayenne'; - -export async function main() { - // ==================== Test Logic ==================== - const client = new LitNodeClient({ - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - checkNodeAttestation: globalThis.LitCI.sevAttestation, - }); - await client.connect(); - - const latestBlockhash = await litNodeClient.getLatestBlockhash(); - - // ==================== Post-Validation ==================== - if (!latestBlockhash) { - return fail('latest blockhash not found'); - } - - if (!latestBlockhash.startsWith('0x')) { - return fail('latest blockhash not in hex format'); - } - - // ==================== Success ==================== - return success(`Latest blockhash found: ${latestBlockhash}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-get-read-validators.mjs b/e2e-nodejs/group-contracts/test-contracts-get-read-validators.mjs deleted file mode 100644 index 720f073d32..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-get-read-validators.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; - -export async function main() { - // ==================== Setup ==================== - const cayenneValidators = await LitContracts.getValidators('cayenne'); - const manzanoValidators = await LitContracts.getValidators('manzano'); - const habaneroValidators = await LitContracts.getValidators('habanero'); - - // ==================== Post-Validation ==================== - for (const validator of [ - ...cayenneValidators, - ...manzanoValidators, - ...habaneroValidators, - ]) { - if ( - !validator.includes(':') || - (!validator.includes('http://') && !validator.includes('https://')) - ) { - return fail('validator should contain ":" and "http://" or "https://"'); - } - } - - // ==================== Success ==================== - return success('ContractsSDK should get validators'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-read-mint-cost.mjs b/e2e-nodejs/group-contracts/test-contracts-read-mint-cost.mjs deleted file mode 100644 index 237c663edf..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-read-mint-cost.mjs +++ /dev/null @@ -1,23 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; - -export async function main() { - // ==================== Setup ==================== - const contractClient = new LitContracts(); - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - // ==================== Success ==================== - return success('ContractsSDK should read mintCost'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-read-with-pkp-ethers.mjs b/e2e-nodejs/group-contracts/test-contracts-read-with-pkp-ethers.mjs deleted file mode 100644 index 6bc2abf526..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-read-with-pkp-ethers.mjs +++ /dev/null @@ -1,40 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; - -export async function main() { - // ========== PKP WALLET SETUP =========== - const pkpWallet = new PKPEthersWallet({ - pkpPubKey: LITCONFIG.PKP_PUBKEY, - controllerAuthSig: LITCONFIG.CONTROLLER_AUTHSIG, - rpc: LITCONFIG.CHRONICLE_RPC, - }); - - await pkpWallet.init(); - - if (pkpWallet._isSigner !== true) { - return fail('pkpWallet should be signer'); - } - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer: pkpWallet, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - // ==================== Success ==================== - return success('ContractsSDK should read mintCost with PKP'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-read-with-private-key.mjs b/e2e-nodejs/group-contracts/test-contracts-read-with-private-key.mjs deleted file mode 100644 index 41c00e9815..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-read-with-private-key.mjs +++ /dev/null @@ -1,35 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; - -export async function main() { - // ========== PKP WALLET SETUP =========== - const privateKey = - '0x4cc303e56f1ff14e762a33534d7fbaa8a76e52509fd96373f24045baae99cc38'; - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - const signer = new ethers.Wallet(privateKey, provider); - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - // ==================== Success ==================== - return success('ContractsSDK should read mintCost with private key'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-read-with-provider.mjs b/e2e-nodejs/group-contracts/test-contracts-read-with-provider.mjs deleted file mode 100644 index 34a0e8ccc3..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-read-with-provider.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; - -export async function main() { - // ========== PKP WALLET SETUP =========== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - provider, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - // ==================== Success ==================== - return success('ContractsSDK should read mintCost with provider'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-2-easy.mjs b/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-2-easy.mjs deleted file mode 100644 index 644cb58237..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-2-easy.mjs +++ /dev/null @@ -1,83 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import { AuthMethodType, AuthMethodScope } from '@lit-protocol/constants'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; - -export async function main() { - // ========== Controller Setup =========== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const controllerWallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer: controllerWallet, - network: LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - - const authMethod = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(LITCONFIG.CONTROLLER_AUTHSIG), - }; - - const mintInfo = await contractClient.mintWithAuth({ - authMethod, - scopes: [ - // AuthMethodScope.NoPermissions, - AuthMethodScope.SignAnything, - AuthMethodScope.PersonalSign, - ], - }); - - if (!mintInfo.tx.transactionHash) { - return fail(`failed to mint a PKP`); - } - - const authId = LitAuthClient.getAuthIdByAuthMethod(authMethod); - - // ==================== Post-Validation ==================== - // NOTE: When using other auth methods, you might need to wait for a block to be mined before you can read the scopes - // -- get the scopes - const scopes = - await contractClient.pkpPermissionsContract.read.getPermittedAuthMethodScopes( - mintInfo.pkp.tokenId, - AuthMethodType.EthWallet, - authId, - 3 - ); - - const signAnythingScope = scopes[1]; - const PersonalSignScope = scopes[2]; - - if (!signAnythingScope) { - return fail(`signAnythingScope should be true`); - } - - if (!PersonalSignScope) { - return fail(`PersonalSignScope should be true`); - } - - // ==================== Success ==================== - return success(`ContractsSDK mints a PKP and set scope 1 and 2 -Logs: ---- -tokenId: ${mintInfo.pkp.tokenId} -transactionHash: ${mintInfo.tx.transactionHash} -signAnythingScope: ${signAnythingScope} -PersonalSignScope: ${PersonalSignScope} -`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-advanced.mjs b/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-advanced.mjs deleted file mode 100644 index 5e2eb38b44..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-and-set-scope-1-advanced.mjs +++ /dev/null @@ -1,86 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import { AuthMethodType } from '@lit-protocol/constants'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; - -export async function main() { - // ========== Controller Setup =========== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const controllerWallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer: controllerWallet, - network: LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - const authMethod = { - authMethodType: 1, - accessToken: JSON.stringify(LITCONFIG.CONTROLLER_AUTHSIG), - }; - - const authId = LitAuthClient.getAuthIdByAuthMethod(authMethod); - - // -- minting a PKP - const mintTx = - await contractClient.pkpHelperContract.write.mintNextAndAddAuthMethods( - 2, - [AuthMethodType.EthWallet], - [authId], - ['0x'], // only for web3auth atm - [[1]], - true, // addPkpEthAddressAsPermittedAddress, - true, // sendPkpToItself, - { - value: mintCost, - } - ); - - const mintTxReceipt = await mintTx.wait(); - - const tokenId = mintTxReceipt.events[0].topics[1]; - - // -- get the scopes - const scopes = - await contractClient.pkpPermissionsContract.read.getPermittedAuthMethodScopes( - tokenId, - AuthMethodType.EthWallet, - authId, - 3 - ); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - if (scopes[1] !== true) { - return fail('scope 1 (sign anything) should be true'); - } - - // ==================== Success ==================== - return success(`ContractsSDK mints a PKP -Logs: ---- -mintHash: ${mintTxReceipt.transactionHash} -tokenId: ${tokenId} -scope 1 (sign anything): ${scopes[1]} -scope 2 (only sign messages): ${scopes[2]} -`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-then-set-scope-1.mjs b/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-then-set-scope-1.mjs deleted file mode 100644 index 9476c6cd61..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-then-set-scope-1.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import { AuthMethodType, AuthMethodScope } from '@lit-protocol/constants'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; - -export async function main() { - // ========== Controller Setup =========== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const controllerWallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer: controllerWallet, - network: LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // -- minting a PKP using a PKP - const mintTx = await contractClient.pkpNftContract.write.mintNext(2, { - value: mintCost, - }); - - const mintTxReceipt = await mintTx.wait(); - - const tokenId = mintTxReceipt.events[0].topics[1]; - console.log('tokenId', tokenId); - - const authMethod = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(LITCONFIG.CONTROLLER_AUTHSIG), - }; - - const authId = LitAuthClient.getAuthIdByAuthMethod(authMethod); - - // -- get the scopes - const scopes = - await contractClient.pkpPermissionsContract.read.getPermittedAuthMethodScopes( - tokenId, - AuthMethodType.EthWallet, - authId, - 3 - ); - - // -- validate both scopes should be false - if (scopes[AuthMethodScope.SignAnything] !== false) { - return fail('scope 1 (sign anything) should be false'); - } - - if (scopes[AuthMethodScope.PersonalSign] !== false) { - return fail('scope 2 (personal sign) should be false'); - } - - // -- set the scope - const setScopeTx = - await contractClient.pkpPermissionsContract.write.addPermittedAuthMethodScope( - tokenId, - AuthMethodType.EthWallet, - LITCONFIG.CONTROLLER_AUTHSIG.address, // auth id - AuthMethodScope.SignAnything - ); - - const setScopeTxReceipt = await setScopeTx.wait(); - - // -- check the scopes again - const scopes2 = - await contractClient.pkpPermissionsContract.read.getPermittedAuthMethodScopes( - tokenId, - AuthMethodType.EthWallet, - LITCONFIG.CONTROLLER_AUTHSIG.address, // auth id - 3 - ); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - if (scopes2[1] !== true) { - return fail('scope 1 (sign anything) should be true'); - } - - // ==================== Success ==================== - return success(`ContractsSDK mints a PKP -Logs: ---- -mintHash: ${mintTxReceipt.transactionHash} -tokenId: ${tokenId} -setScopeHash: ${setScopeTxReceipt.transactionHash} -scope 1 (sign anything): ${scopes2[1]} -scope 2 (only sign messages): ${scopes2[2]} -`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-a-pkp-with-no-permissions.mjs b/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-a-pkp-with-no-permissions.mjs deleted file mode 100644 index 0af7488f9c..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-a-pkp-with-no-permissions.mjs +++ /dev/null @@ -1,104 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import { ethers } from 'ethers'; - -async function getFundsFromPKPController(ethAddress) { - // ========== Controller Setup =========== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const controllerWallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - - // get the fund - console.log( - 'Controller Balance:', - (await controllerWallet.getBalance()).toString() - ); - - // send some funds to the pkp - const amount = '0.000001'; - - const tx = await controllerWallet.sendTransaction({ - to: ethAddress, - value: ethers.utils.parseEther(amount), - }); - - await tx.wait(); - - const newBalance = (await controllerWallet.getBalance()).toString(); - - console.log('New Controller Balance:', newBalance); - - if (newBalance <= 0) { - console.log('Controller Balance is still 0'); - process.exit(); - } - console.log(`Sent ${amount} ETH to ${LITCONFIG.PKP_ETH_ADDRESS}`); -} - -export async function main() { - // We no longer allow - - // ========== PKP WALLET SETUP =========== - const pkpWallet = new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - rpc: LITCONFIG.CHRONICLE_RPC, - }); - - await pkpWallet.init(); - - const pkpBalance = parseFloat(await pkpWallet.getBalance()); - - if (pkpBalance <= 0) { - console.log( - `PKP Balance is ${pkpBalance}. Getting funds from controller...` - ); - const pkpAddress = await pkpWallet.getAddress(); - console.log('pkpAddress:', pkpAddress); - await getFundsFromPKPController(pkpAddress); - console.log('New PKP Balance:', (await pkpWallet.getBalance()).toString()); - } - - if (pkpWallet._isSigner !== true) { - return fail('pkpWallet should be signer'); - } - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer: pkpWallet, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // -- minting a PKP using a PKP - const mintTx = - await contractClient.pkpNftContract.write.populateTransaction.mintNext(2, { - value: mintCost, - }); - - const signedMintTx = await pkpWallet.signTransaction(mintTx); - - const sentTx = await pkpWallet.sendTransaction(signedMintTx); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - // ==================== Success ==================== - return success(`ContractsSDK mint a PKP using PKP Ethers wallet -hash: ${sentTx.hash}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-no-permissions.mjs b/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-no-permissions.mjs deleted file mode 100644 index f7fc0a860f..0000000000 --- a/e2e-nodejs/group-contracts/test-contracts-write-mint-a-pkp-with-no-permissions.mjs +++ /dev/null @@ -1,45 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; - -export async function main() { - // ========== Controller Setup =========== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const controllerWallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - - // ==================== LitContracts Setup ==================== - const contractClient = new LitContracts({ - signer: controllerWallet, - network: LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - - // -- minting a PKP using a PKP - const mintTx = await contractClient.pkpNftContract.write.mintNext(2, { - value: mintCost, - }); - - const mintTxReceipt = await mintTx.wait(); - - // ==================== Post-Validation ==================== - if (mintCost === undefined || mintCost === null) { - return fail('mintCost should not be empty'); - } - - // ==================== Success ==================== - return success(`ContractsSDK mints a PKP ${mintTxReceipt.transactionHash}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-custom-network/resolver.data.js b/e2e-nodejs/group-custom-network/resolver.data.js deleted file mode 100644 index d02aaf56c6..0000000000 --- a/e2e-nodejs/group-custom-network/resolver.data.js +++ /dev/null @@ -1,604 +0,0 @@ -module.exports.resolverAbi = [ - { - inputs: [ - { - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [], - name: 'AdminRoleRequired', - type: 'error', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - ], - name: 'AllowedEnvAdded', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - ], - name: 'AllowedEnvRemoved', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - indexed: true, - internalType: 'bytes32', - name: 'previousAdminRole', - type: 'bytes32', - }, - { - indexed: true, - internalType: 'bytes32', - name: 'newAdminRole', - type: 'bytes32', - }, - ], - name: 'RoleAdminChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - indexed: true, - internalType: 'address', - name: 'account', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'sender', - type: 'address', - }, - ], - name: 'RoleGranted', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - indexed: true, - internalType: 'address', - name: 'account', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'sender', - type: 'address', - }, - ], - name: 'RoleRevoked', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'bytes32', - name: 'typ', - type: 'bytes32', - }, - { - indexed: false, - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - { - indexed: false, - internalType: 'address', - name: 'addr', - type: 'address', - }, - ], - name: 'SetContract', - type: 'event', - }, - { - inputs: [], - name: 'ADMIN_ROLE', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'ALLOWLIST_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'BACKUP_RECOVERY_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'DEFAULT_ADMIN_ROLE', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'DOMAIN_WALLET_ORACLE', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'DOMAIN_WALLET_REGISTRY', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'HD_KEY_DERIVER_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'LIT_TOKEN_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'MULTI_SENDER_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'PKP_HELPER_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'PKP_NFT_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'PKP_NFT_METADATA_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'PKP_PERMISSIONS_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'PUB_KEY_ROUTER_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'RATE_LIMIT_NFT_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'RELEASE_REGISTER_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'STAKING_BALANCES_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'STAKING_CONTRACT', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - ], - name: 'addAllowedEnv', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'typ', - type: 'bytes32', - }, - { - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - ], - name: 'getContract', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - ], - name: 'getRoleAdmin', - outputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'grantRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'hasRole', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - ], - name: 'removeAllowedEnv', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'renounceRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'revokeRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'newAdmin', - type: 'address', - }, - ], - name: 'setAdmin', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'typ', - type: 'bytes32', - }, - { - internalType: 'enum ContractResolver.Env', - name: 'env', - type: 'uint8', - }, - { - internalType: 'address', - name: 'addr', - type: 'address', - }, - ], - name: 'setContract', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes4', - name: 'interfaceId', - type: 'bytes4', - }, - ], - name: 'supportsInterface', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: '', - type: 'bytes32', - }, - { - internalType: 'enum ContractResolver.Env', - name: '', - type: 'uint8', - }, - ], - name: 'typeAddresses', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, -]; diff --git a/e2e-nodejs/group-custom-network/test-custom-contract-passthrough-resolver.mjs b/e2e-nodejs/group-custom-network/test-custom-contract-passthrough-resolver.mjs deleted file mode 100644 index 4414693c8e..0000000000 --- a/e2e-nodejs/group-custom-network/test-custom-contract-passthrough-resolver.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import { fail, success, testThis } from '../../tools/scripts/utils.mjs'; -import path from 'path'; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { resolverAbi } from './resolver.data.js'; - -export async function main() { - const contractContext = { - resolverAddress: '0x9F0Ede26261451C5E784DC799D71ECf766EB7562', - abi: resolverAbi, - environment: 0, - }; - - const client = new LitNodeClient({ - // litNetwork: 'cayenne', - litNetwork: 'custom', - bootstrapUrls: [], - debug: globalThis.LitCI.debug, - contractContext: contractContext, - }); - await client.connect(); - - if (client.config.bootstrapUrls.length > 1) { - fail('Should have more than 0 urls bootstrapped'); - } - - return success( - `Can connect to custom network current urls from contract resolver: ${client.config.bootstrapUrls.length}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-hotwallet-with-blockhash/test-hotwallet-with-blockhash.mjs b/e2e-nodejs/group-hotwallet-with-blockhash/test-hotwallet-with-blockhash.mjs deleted file mode 100644 index 0770662b5d..0000000000 --- a/e2e-nodejs/group-hotwallet-with-blockhash/test-hotwallet-with-blockhash.mjs +++ /dev/null @@ -1,133 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; - -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { - LitAccessControlConditionResource, - LitAbility, -} from '@lit-protocol/auth-helpers'; -import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'; -import ethers from 'ethers'; -import { SiweMessage } from 'siwe'; - -async function hashBytes({ bytes }) { - const hashOfBytes = await crypto.subtle.digest('SHA-256', bytes); - const hashOfBytesStr = LitJsSdk.uint8arrayToString( - new Uint8Array(hashOfBytes), - 'base16' - ); - return hashOfBytesStr; -} - -function checkNonceInEachSessionSig(sessionSig, nonce) { - return Object.keys(sessionSig).every((key) => { - const signedMessage = sessionSig[key].signedMessage; - return signedMessage.includes(nonce); - }); -} - -export async function main() { - // ==================== Setup ==================== - - const privKey = - '3dfb4f70b15b6fccc786347aaea445f439a7f10fd10c55dd50cafc3d5a0abac1'; - const privKeyBuffer = uint8arrayFromString(privKey, 'base16'); - const wallet = new ethers.Wallet(privKeyBuffer); - - const chain = 'ethereum'; - const domain = 'localhost'; - const statement = - 'This is a test statement. You can put anything you want here.'; - - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - ]; - - // ==================== Test Logic ==================== - - const litNodeClient = new LitJsSdk.LitNodeClient({ - // litNetwork: 'cayenne', - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - }); - await litNodeClient.connect(); - - let nonce = await litNodeClient.getLatestBlockhash(); - console.log('Eth blockhash nonce- ', nonce); - - if (!nonce) { - fail('Latest Eth blockhash is undefined'); - } - - const authNeededCallback = async ({ resources, expiration, uri }) => { - const message = new SiweMessage({ - domain, - address: wallet.address, - statement, - uri, - version: '1', - chainId: '1', - expirationTime: expiration, - resources, - nonce, - }); - - const toSign = message.prepareMessage(); - const signature = await wallet.signMessage(toSign); - - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: toSign, - address: wallet.address, - }; - - return authSig; - }; - - const hashedEncryptedSymmetricKeyStr = await hashBytes({ - bytes: new Uint8Array(accessControlConditions), - }); - - const litResource = new LitAccessControlConditionResource( - hashedEncryptedSymmetricKeyStr - ); - - // ==================== Post-Validation ==================== - - // NOTE: `getSessionSigs` will fail if the nonce is not a valid Eth blockhash - const sessionSigs = await litNodeClient.getSessionSigs({ - chain, - resourceAbilityRequests: [ - { - resource: litResource, - ability: LitAbility.AccessControlConditionDecryption, - }, - ], - authNeededCallback, - }); - - console.log(sessionSigs); - - if (!checkNonceInEachSessionSig(sessionSigs, nonce)) { - return fail("sessionSig doesn't contain the blockhash"); - } - - // ==================== Success ==================== - - return success( - 'Can create an authSig with the latest blockhash as its nonce' - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-latest-blockhash-update/test-block-has-update-after-exp.mjs b/e2e-nodejs/group-latest-blockhash-update/test-block-has-update-after-exp.mjs deleted file mode 100644 index 010864d571..0000000000 --- a/e2e-nodejs/group-latest-blockhash-update/test-block-has-update-after-exp.mjs +++ /dev/null @@ -1,55 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LocalStorage } from 'node-localstorage'; - -export async function main() { - const client = new LitNodeClient({ - litNetwork: globalThis.LitCI.network, - debug: globalThis.LitCI.debug, - minNodeCount: globalThis.LitCI.minNodeCount, - checkNodeAttestation: globalThis.LitCI.sevAttestation, - storageProvider: { - provider: new LocalStorage('./storage.test.db'), - }, - }); - - await client.connect(); - console.log(client.hdRootPubkeys); - let subnetKey = '' + client.subnetPubKey; - let rootKeys = client.hdRootPubkeys; - let blockhash = await client.getLatestBlockhash(); - await new Promise((resolve, _reject) => { - setTimeout(resolve, 35_000); - }); - - let updatedBlockhash = await client.getLatestBlockhash(); - - if (blockhash === updatedBlockhash) { - return fail('block hash should be updated from handshake'); - } - - if ( - rootKeys.filter((item) => client.hdRootPubkeys.includes(item) === false) - .length > 0 || - subnetKey != client.subnetPubKey - ) { - console.log( - 'current root keys: ', - client.hdRootPubkeys, - 'old root keys: ', - rootKeys - ); - console.log( - 'old subnet key: ', - subnetKey, - 'current subnnet key: ', - client.subnetPubKey - ); - return fail('network properties do not match after syncing'); - } - console.log('block hashes: ', blockhash, updatedBlockhash); - return success('block hash updates after expiration period'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-1-sig.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-1-sig.mjs deleted file mode 100644 index 1cb940b204..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-1-sig.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - - // ==================== Post-Validation ==================== - - if (!res.signatures || Object.keys(res.signatures).length <= 0) { - return fail( - `should have at least 1 signature but received ${ - Object.keys(res.signatures).length - }` - ); - } - - ['sig', 'r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (!res.signatures.sig[key]) { - return fail(`sig.${key} is undefined, empty, or null`); - } - } - ); - // ==================== Success ==================== - return success('Lit Action should log sign x1 sig'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-claim-key.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-claim-key.mjs deleted file mode 100644 index c4cd36d114..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-claim-key.mjs +++ /dev/null @@ -1,59 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - Lit.Actions.claimKey({keyId: "foo"}); - })();`, - authMethods: [], - jsParams: { - // Nada! - }, - }); - - // ==================== Post-Validation ==================== - if (!res.success && !res.claims) { - return fail(`response should be success`); - } - - // -- should have claimData - if ( - res.claims === undefined || - res.claims === null || - Object.keys(res.claims).length === 0 - ) { - return fail(`claimData should not be empty`); - } - - if (res.claims['foo'] === undefined) { - return fail(`claimData should have "foo" key`); - } - - ['signature', 'derivedKeyId'].forEach((key) => { - if (!res.claims.foo[key]) { - return fail(`claimData.foo should have ${key}`); - } - }); - const key = 'foo'; - for (let i = 0; i < res.claims[key].signatures.length; i++) { - if ( - !res.claims[key].signatures[i].r || - !res.claims[key].signatures[i].s || - !res.claims[key].signatures[i].v - ) { - return fail( - `signature data misformed, should be of ethers signature format` - ); - } - } - - // ==================== Success ==================== - return success('Lit Action should return claim'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-get-ipfsid.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-get-ipfsid.mjs deleted file mode 100644 index 53d323bda0..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-get-ipfsid.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Test Logic ==================== - const ipfsCid = await client.getIpfsId({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - dataToHash: 'Hakuna Matata', - }); - - console.log('ipfsCid:', ipfsCid); - - // ==================== Post-Validation ==================== - if (!ipfsCid) { - return fail('Lit Action failed to return IPFS CID'); - } - - // ==================== Success ==================== - return success('Lit Action return IPFS CID successfully'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-grouped-claims.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-grouped-claims.mjs deleted file mode 100644 index 638db802da..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-grouped-claims.mjs +++ /dev/null @@ -1,75 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - Lit.Actions.claimKey({keyId: "foo"}); - Lit.Actions.claimKey({keyId: "bar"}); - })();`, - jsParams: { - // Nada! - }, - }); - - // ==================== Post-Validation ==================== - if (!res.success && !res.claims) { - return fail(`response should be success`); - } - - // -- should have claims - Object.entries(res.claims).forEach(([key, value]) => { - if (key !== 'foo' || key !== 'bar') { - return fail(`claims should have "foo" or "bar" key`); - } - - if ( - res.claims === undefined || - res.claims === null || - Object.keys(res.claims).length === 0 - ) { - return fail(`claims should not be empty`); - } - - if (res.claims[key] === undefined) { - return fail(`claims should have "${key}" key`); - } - - if ( - res.claims[key].signature === undefined || - res.claims[key].signature === null || - res.claims[key].signature.length < 1 - ) { - return fail(`claims[${key}] should have signature`); - } - - if ( - res.claims[key].derivedKeyId === undefined || - res.claims[key].derivedKeyId === null || - res.claims[key].derivedKeyId === '' - ) { - return fail(`claims[${key}] should have derivedKeyId`); - } - - for (let i = 0; i < res.claims[key].signatures.length; i++) { - if ( - !res.claims[key].signatures[i].r || - !res.claims[key].signatures[i].s || - res.claims[key].signatures[i].v - ) { - return fail( - `signature data mis formed, should be of ethers signature format` - ); - } - } - }); - - // ==================== Success ==================== - return success('Lit Action should return grouped claims'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-json-response.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-json-response.mjs deleted file mode 100644 index 121a7f793d..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-json-response.mjs +++ /dev/null @@ -1,60 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - - LitActions.setResponse({ - response: JSON.stringify({hello: 'world'}) - }); - - })();`, - jsParams: { - toSign: [1, 2, 3, 4, 5], - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - sigName: 'fooSig', - }, - }); - - // ==================== Post-Validation ==================== - if (!res.success) { - return fail(`response should be success`); - } - - if (Object.keys(res.signedData).length > 0) { - return fail(`signedData should be empty`); - } - - if (Object.keys(res.decryptedData).length > 0) { - return fail(`decryptedData should be empty`); - } - - if (Object.keys(res.claimData).length > 0) { - return fail(`claimData should be empty`); - } - - let jsonRes; - - try { - jsonRes = JSON.parse(res.response); - } catch (e) { - return fail(`response should be a valid JSON`); - } - - if (jsonRes.hello !== 'world') { - return fail( - `jsonRes.hello should be "world" but received "${jsonRes.hello}"` - ); - } - - // ==================== Success ==================== - return success('Lit Action should be able reply with a JSON response'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-log.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-log.mjs deleted file mode 100644 index d433bb3078..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-log.mjs +++ /dev/null @@ -1,31 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - console.log('hello world') - })();`, - jsParams: { - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - - // ==================== Post-Validation ==================== - if (!res.logs.includes('hello world')) { - return fail('lit action client should be ready'); - } - - if (!res.success) { - return fail('response should be success'); - } - - // ==================== Success ==================== - return success('Lit Action should log "hello world"'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-actions/test-lit-action-no-params.mjs b/e2e-nodejs/group-lit-actions/test-lit-action-no-params.mjs deleted file mode 100644 index 293704b9b1..0000000000 --- a/e2e-nodejs/group-lit-actions/test-lit-action-no-params.mjs +++ /dev/null @@ -1,42 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Test Logic ==================== - const res = await client.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - code: `(async () => { - LitActions.setResponse({ - response: JSON.stringify({success: true}) - }); - })();`, - authMethods: [], - }); - - // ==================== Post-Validation ==================== - let jsonRes; - - try { - jsonRes = JSON.parse(res.response); - } catch (e) { - return fail(`response should be a valid JSON`); - } - - if (jsonRes.success !== true) { - return fail( - `jsonRes.success should be true but received "${jsonRes.success}"` - ); - } - - // ==================== Success ==================== - return success('Lit action should return response with no params given'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-lit-auth-client/test-should-init-with-correct-properties.mjs b/e2e-nodejs/group-lit-auth-client/test-should-init-with-correct-properties.mjs deleted file mode 100644 index 75a6cbc692..0000000000 --- a/e2e-nodejs/group-lit-auth-client/test-should-init-with-correct-properties.mjs +++ /dev/null @@ -1,38 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; - -export async function main() { - const authClient = new LitAuthClient({ - litRelayConfig: { - relayApiKey: 'abc1234', - }, - litNodeClient: client, - }); - switch (client.config.litNetwork) { - case 'cayenne': - if ( - authClient.relay.getUrl() !== - 'https://relayer-server-staging-cayenne.getlit.dev' - ) { - throw new Error('wrong url for network'); - } - break; - case 'habanero': - if (authClient.relay.getUrl() !== 'https://habanero-relayer.getlit.dev') { - throw new Error('wrong url for network'); - } - break; - case 'manzano': - if (authClient.relay.getUrl() !== 'https://manzano-relayer.getlit.dev') { - throw new Error('wrong url for network'); - } - break; - } - - console.log('relayUrl', authClient.relay.getUrl()); - return success('should initalize with correct relay url for network'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-meth-authentication-no-methods.mjs b/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-meth-authentication-no-methods.mjs deleted file mode 100644 index 19ed58fdf4..0000000000 --- a/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-meth-authentication-no-methods.mjs +++ /dev/null @@ -1,80 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; -import { AuthMethodType, ProviderType } from '@lit-protocol/constants'; -import { ethers } from 'ethers'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = new Uint8Array( - await crypto.subtle.digest('SHA-256', new TextEncoder().encode('meow')) -); - -export async function main() { - // ==================== Setup ==================== - - const pkpSignRes = await client?.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - authMethods: [], - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig", - }); - LitActions.setResponse({response: JSON.stringify(Lit.Auth)}); - })();`, - jsParams: { - toSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - - // ==================== Post-Validation ==================== - - if (!pkpSignRes) { - return fail( - 'Failed to sign data with sessionSigs generated by eth wallet auth method' - ); - } - - let missingKeys = []; - - if (pkpSignRes) { - ['r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (pkpSignRes.signatures['sig'][key] === undefined) { - missingKeys.push(key); - } - } - ); - } - - if (missingKeys.length > 0) { - return fail(`Missing keys: ${missingKeys.join(', ')}`); - } - - if ( - !pkpSignRes.response.authSigAddress == - LITCONFIG.CONTROLLER_AUTHSIG_2.address - ) { - return fail(`Missing or non matching auth sig address in Lit.Auth context`); - } - - if (pkpSignRes.response.authMethodContexts.length > 0) { - return fail('should not have auth methods only authSigAddress'); - } - - // ==================== Success ==================== - return success( - `it should use sessionSigs generated by eth wallet auth method to sign data. Signature is ${ - pkpSignRes.signatures - } and pkpSignRes is ${JSON.stringify(pkpSignRes)}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-authentication.mjs b/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-authentication.mjs deleted file mode 100644 index 13e68ed2e8..0000000000 --- a/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-authentication.mjs +++ /dev/null @@ -1,81 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { AuthMethodType } from '@lit-protocol/constants'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -const TO_SIGN = new Uint8Array( - await crypto.subtle.digest('SHA-256', new TextEncoder().encode('meow')) -); - -export async function main() { - // ==================== Setup ==================== - - const authMethod = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }; - - const pkpSignRes = await client?.executeJs({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - authMethods: [authMethod], - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign, - publicKey, - sigName: "sig", - }); - LitActions.setResponse({response: JSON.stringify(Lit.Auth)}); - })();`, - jsParams: { - toSign: TO_SIGN, - publicKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - }); - - // ==================== Post-Validation ==================== - - if (!pkpSignRes) { - return fail( - 'Failed to sign data with sessionSigs generated by eth wallet auth method' - ); - } - - let missingKeys = []; - - if (pkpSignRes) { - ['r', 's', 'recid', 'signature', 'publicKey', 'dataSigned'].forEach( - (key) => { - if (pkpSignRes.signatures['sig'][key] === undefined) { - missingKeys.push(key); - } - } - ); - } - - if (missingKeys.length > 0) { - return fail(`Missing keys: ${missingKeys.join(', ')}`); - } - - if ( - !pkpSignRes.response.authSigAddress == - LITCONFIG.CONTROLLER_AUTHSIG_2.address - ) { - return fail(`Missing or non matching auth sig address in Lit.Auth context`); - } - - if (pkpSignRes.response.authMethodContexts.length < 1) { - return fail('not enough authentication material in Lit.Auth context'); - } - - // ==================== Success ==================== - return success( - `it should use sessionSigs generated by eth wallet auth method to sign data. Signature is ${ - pkpSignRes.signatures - } and pkpSignRes is ${JSON.stringify(pkpSignRes)}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-multiple-auth-method-mint.mjs b/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-multiple-auth-method-mint.mjs deleted file mode 100644 index ff5f35ce43..0000000000 --- a/e2e-nodejs/group-pkp-auth-method/test-pkp-auth-method-multiple-auth-method-mint.mjs +++ /dev/null @@ -1,88 +0,0 @@ -import { client } from '../00-setup.mjs'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { AuthMethodType } from '@lit-protocol/constants'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import path from 'path'; -import { LitContracts } from '@lit-protocol/contracts-sdk'; - -export async function main() { - const authMethod1 = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }; - - const authMethod2 = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(LITCONFIG.CONTROLLER_AUTHSIG_2), - }; - - let authClient = new LitAuthClient({ - litRelayConfig: { - relayApiKey: 'aasdasdasdasd', - }, - litNodeClient: client, - }); - - let res = await authClient.mintPKPWithAuthMethods( - [authMethod1, authMethod2], - { - pkpPermissionScopes: [[1], [1]], - sendPkpToitself: true, - addPkpEthAddressAsPermittedAddress: true, - } - ); - - if (typeof res != 'object') { - fail('Type of mint response is not of type string'); - } - - const authNeededCallback = async (params) => { - const response = await client.signSessionKey({ - sessionKey: params.sessionKeyPair, - statement: params.statement, - authMethods: [ - { - authMethodType: 1, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }, - ], - pkpPublicKey: `0x${globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey}`, - expiration: params.expiration, - resources: params.resources, - chainId: 1, - }); - return response.authSig; - }; - - const resourceAbilities = [ - { - resource: new LitActionResource('*'), - ability: LitAbility.PKPSigning, - }, - ]; - - // ==================== Test Logic ==================== - - const sessionSigs = await client.getSessionSigs({ - chain: 'ethereum', - expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - resourceAbilityRequests: resourceAbilities, - authNeededCallback, - }); - - console.log(sessionSigs); - - if (!sessionSigs) { - fail('session signatures have not been signed'); - } - - if (Object.keys(sessionSigs).length < client.config.minNodeCount) { - fail('Session key map is not at least the same as the node threshold.'); - } - - return success('mint returned type of string with multiple auth methods'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-auth-method/test-pkp-eth-wallet-provider.mjs b/e2e-nodejs/group-pkp-auth-method/test-pkp-eth-wallet-provider.mjs deleted file mode 100644 index 450588eda2..0000000000 --- a/e2e-nodejs/group-pkp-auth-method/test-pkp-eth-wallet-provider.mjs +++ /dev/null @@ -1,33 +0,0 @@ -// Test command: -// DEBUG=true NETWORK=cayenne yarn test:e2e:nodejs --filter=test-pkp-eth-wallet-provider.mjs - -import { client } from '../00-setup.mjs'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import path from 'path'; -import { EthWalletProvider } from '@lit-protocol/lit-auth-client'; -import { ethers } from 'ethers'; - -export async function main() { - const PRIVATE_KEY = LITCONFIG.CONTROLLER_PRIVATE_KEY; - - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const wallet = new ethers.Wallet(PRIVATE_KEY, provider); - - const authMethod = await EthWalletProvider.authenticate({ - signer: wallet, - litNodeClient: client, - }); - - if (!authMethod) { - fail('Unable to authenticate with eth wallet provider'); - } - - return success(`authMethod created: ${JSON.stringify(authMethod)}`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-client/test-pkp-client-with-rpc.mjs b/e2e-nodejs/group-pkp-client/test-pkp-client-with-rpc.mjs deleted file mode 100644 index 8f7fcbf03a..0000000000 --- a/e2e-nodejs/group-pkp-client/test-pkp-client-with-rpc.mjs +++ /dev/null @@ -1,72 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPClient } from '@lit-protocol/pkp-client'; -import { ethers } from 'ethers'; - -export async function main() { - // ==================== Setup ==================== - const pkpClient = new PKPClient({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpcs: { - eth: LITCONFIG.CHRONICLE_RPC, - cosmos: LITCONFIG.COSMOS_RPC, - }, - litNetwork: globalThis.LitCI.network, - cosmosAddressPrefix: 'cosmos', - }); - - await pkpClient.connect(); - - // ==================== Test Logic ==================== - const PAYLOAD = { - to: LITCONFIG.PKP_ETH_ADDRESS, - value: 0, - data: '0x', - }; - - const rawSignedTx = await pkpClient.getEthWallet().signTransaction(PAYLOAD); - - const parsedTransaction = ethers.utils.parseTransaction(rawSignedTx); - - const signature = ethers.utils.joinSignature({ - r: parsedTransaction.r, - s: parsedTransaction.s, - v: parsedTransaction.v, - }); - - const rawTx = { - nonce: parsedTransaction.nonce, - gasPrice: parsedTransaction.gasPrice, - gasLimit: parsedTransaction.gasLimit, - to: parsedTransaction.to, - value: parsedTransaction.value, - data: parsedTransaction.data, - chainId: parsedTransaction.chainId, // Include chainId if the transaction is EIP-155 - }; - - const txHash = ethers.utils.keccak256( - ethers.utils.serializeTransaction(rawTx) - ); - - const { v, r, s } = parsedTransaction; - - const recoveredAddress = ethers.utils.recoverAddress(txHash, { r, s, v }); - // ==================== Post-Validation ==================== - - if (signature.length !== 132) { - return fail('signature should be defined'); - } - - if (recoveredAddress !== globalThis.LitCI.PKP_INFO.ethAddress) { - return fail( - `recoveredAddres should be ${globalThis.LitCI.PKP_INFO.ethAddress}, got ${recoveredAddress}` - ); - } - - // ==================== Success ==================== - return success('(Without RPC) PKPClient should sign tx using eth wallet'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-message.mjs b/e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-message.mjs deleted file mode 100644 index ab4b0b1cef..0000000000 --- a/e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-message.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { PKPClient } from '@lit-protocol/pkp-client'; - -export async function main() { - // ==================== Setup ==================== - const pkpClient = new PKPClient({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - litNetwork: globalThis.LitCI.network, - cosmosAddressPrefix: 'cosmos', - }); - - await pkpClient.connect(); - - // ==================== Test Logic ==================== - const MESSAGE_TO_SIGN = 'HEY THERE!'; - const signature = await pkpClient.getEthWallet().signMessage(MESSAGE_TO_SIGN); - - // ==================== Post-Validation ==================== - - if (signature.length !== 132) { - return fail('signature should be defined'); - } - - // ==================== Success ==================== - return success( - '(Without RPC) PKPClient should sign message using eth wallet' - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-tx.mjs b/e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-tx.mjs deleted file mode 100644 index a636dbd2fa..0000000000 --- a/e2e-nodejs/group-pkp-client/test-pkp-client-without-rpc-sign-tx.mjs +++ /dev/null @@ -1,68 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { PKPClient } from '@lit-protocol/pkp-client'; -import { ethers } from 'ethers'; - -export async function main() { - // ==================== Setup ==================== - const pkpClient = new PKPClient({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - litNetwork: globalThis.LitCI.network, - cosmosAddressPrefix: 'cosmos', - }); - - await pkpClient.connect(); - - // ==================== Test Logic ==================== - const PAYLOAD = { - to: LITCONFIG.PKP_ETH_ADDRESS, - value: 0, - data: '0x', - }; - - const rawSignedTx = await pkpClient.getEthWallet().signTransaction(PAYLOAD); - - const parsedTransaction = ethers.utils.parseTransaction(rawSignedTx); - - const signature = ethers.utils.joinSignature({ - r: parsedTransaction.r, - s: parsedTransaction.s, - v: parsedTransaction.v, - }); - - const rawTx = { - nonce: parsedTransaction.nonce, - gasPrice: parsedTransaction.gasPrice, - gasLimit: parsedTransaction.gasLimit, - to: parsedTransaction.to, - value: parsedTransaction.value, - data: parsedTransaction.data, - chainId: parsedTransaction.chainId, // Include chainId if the transaction is EIP-155 - }; - - const txHash = ethers.utils.keccak256( - ethers.utils.serializeTransaction(rawTx) - ); - - const { v, r, s } = parsedTransaction; - - const recoveredAddress = ethers.utils.recoverAddress(txHash, { r, s, v }); - // ==================== Post-Validation ==================== - - if (signature.length !== 132) { - return fail('signature should be defined'); - } - - if (recoveredAddress !== globalThis.LitCI.PKP_INFO.ethAddress) { - return fail( - `recoveredAddres should be ${globalThis.LitCI.PKP_INFO.ethAddress}, got ${recoveredAddress}` - ); - } - // ==================== Success ==================== - return success('(Without RPC) PKPClient should sign tx using eth wallet'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-send-tx.mjs b/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-send-tx.mjs deleted file mode 100644 index 4a7f3b639d..0000000000 --- a/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-send-tx.mjs +++ /dev/null @@ -1,77 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPCosmosWallet } from '@lit-protocol/pkp-cosmos'; - -import { - SigningStargateClient, - // StdFee, - calculateFee, - GasPrice, - coins, -} from '@cosmjs/stargate'; - -// Note: You can check your TX using https://www.mintscan.io/ -export async function main() { - // ==================== Setup ==================== - const cosmosWallet = new PKPCosmosWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.COSMOS_RPC, - // debug: true, - addressPrefix: 'cosmos', - }); - - await cosmosWallet.init(); - - const [pkpAccount] = await cosmosWallet.getAccounts(); - - // ==================== Test Logic ==================== - const amount = coins(LITCONFIG.AMOUNT, LITCONFIG.DENOM); - const defaultGasPrice = GasPrice.fromString( - `${LITCONFIG.DEFAULT_GAS}${LITCONFIG.DENOM}` - ); - const defaultSendFee = calculateFee(80_000, defaultGasPrice); - - const stargateClient = await SigningStargateClient.connectWithSigner( - LITCONFIG.COSMOS_RPC, - cosmosWallet - ); - - // ==================== Post-Validation ==================== - if (cosmosWallet.litNodeClientReady !== true) { - return fail('litNodeClient should be ready'); - } - - if ( - process.env.REAL_TX === 'true' ?? - LITCONFIG.test.sendRealTxThatCostsMoney - ) { - let tx; - - try { - tx = await stargateClient.sendTokens( - pkpAccount.address, - pkpAccount.address, - amount, - defaultSendFee, - 'Transaction' - ); - } catch (e) { - const _error = JSON.parse(JSON.stringify(e)); - - if (_error.log.includes('insufficient funds')) { - return success( - `PKPCosmosWallet in theory should be able to send tx [❗️${e.log}]` - ); - } else { - return success(`PKPCosmosWallet should be able to send tx`); - } - } - } - - // ==================== Success ==================== - return success('PKPCosmosWallet should be able to send tx (❗️DRY-RUN)'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-stargate-client.mjs b/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-stargate-client.mjs deleted file mode 100644 index 76ddb5acf5..0000000000 --- a/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos-stargate-client.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPCosmosWallet } from '@lit-protocol/pkp-cosmos'; - -import { - SigningStargateClient, - // StdFee, - // calculateFee, - // GasPrice, - // coins, -} from '@cosmjs/stargate'; - -const TX_HASH = - '6E7CA7AC2A30FAA852DB67E85284E7EE670E581CBFD06DE104AF00C2A1796A1B'; - -// Note: You can check your TX using https://www.mintscan.io/ -export async function main() { - // ==================== Setup ==================== - const cosmosWallet = new PKPCosmosWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.COSMOS_RPC, - debug: true, - addressPrefix: 'cosmos', - }); - - await cosmosWallet.init(); - - // ==================== Test Logic ==================== - const stargateClient = await SigningStargateClient.connectWithSigner( - LITCONFIG.COSMOS_RPC, - cosmosWallet - ); - - console.log('stargateClient:', stargateClient); - - let tx; - - try { - tx = await stargateClient.getTx(TX_HASH); - } catch (e) { - console.log('error:', e); - process.exit(); - } - - // ==================== Post-Validation ==================== - - if (!tx) { - return fail('tx should exist'); - } - - if (cosmosWallet.litNodeClientReady !== true) { - return fail('litNodeClient should be ready'); - } - - if (tx.hash !== TX_HASH) { - return fail('tx hash should be', TX_HASH); - } - - // ==================== Success ==================== - return success( - 'PKPCosmosWallet should be able to get balances using Stargate' - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos.mjs b/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos.mjs deleted file mode 100644 index f4c2aedab6..0000000000 --- a/e2e-nodejs/group-pkp-cosmos/test-pkp-cosmos.mjs +++ /dev/null @@ -1,46 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { PKPCosmosWallet } from '@lit-protocol/pkp-cosmos'; - -export async function main() { - // ==================== Setup ==================== - const cosmosWallet = new PKPCosmosWallet({ - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.COSMOS_RPC, - // debug: true, - addressPrefix: 'cosmos', - }); - - await cosmosWallet.init(); - - // ==================== Test Logic ==================== - const [pkpAccount] = await cosmosWallet.getAccounts(); - - // ==================== Post-Validation ==================== - if (cosmosWallet.litNodeClientReady !== true) { - return fail('litNodeClient should be ready'); - } - - if (!pkpAccount.address.includes('cosmos')) { - return fail(`expecting account address to include "cosmos"`); - } - if (pkpAccount.algo != 'secp256k1') { - return fail('algo does not match: ', 'secp256k1'); - } - - if (pkpAccount.pubkey.length !== 33) { - return fail( - 'pubkey buffer expected length is incorrect recieved: ', - pkpAccount.pubkey.length, - 'expected', - 33 - ); - } - // ==================== Success ==================== - return success('PKPCosmosWallet should be able to getAccounts'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-acc-schema.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-acc-schema.mjs deleted file mode 100644 index 55dd51090b..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-acc-schema.mjs +++ /dev/null @@ -1,608 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { success, fail, testThese } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -const chain = 'ethereum'; - -const accessControlConditionsTestSuccess = - (testName, accessControlConditions) => async () => { - // ==================== Test Logic ==================== - try { - await LitJsSdk.encryptString( - { - ...accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - dataToEncrypt: 'Hello world', - }, - client - ); - } catch (e) { - // ==================== Fail ==================== - return fail( - `${testName} failed validating access control conditions schemas` - ); - } - - // ==================== Post-Validation ==================== - return success( - `${testName} validated access control conditions schemas successfully` - ); - }; - -const accessControlConditionsTestFailure = - (testName, accessControlConditions) => async () => { - // ==================== Test Logic ==================== - try { - await LitJsSdk.encryptString( - { - ...accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - dataToEncrypt: 'Hello world', - }, - client - ); - } catch (e) { - if (e.errorKind === 'Validation') { - // ==================== Success ==================== - return success( - `${testName} validated access control conditions schemas successfully` - ); - } - } - - // ==================== Post-Validation ==================== - return fail( - `${testName} should reject access control conditions with incorrect schemas` - ); - }; - -// Success cases -const evmBasicAccessControlConditions = [ - { - contractAddress: '0x7C7757a9675f06F3BE4618bB68732c4aB25D2e88', - standardContractType: 'ERC1155', - chain, - method: 'balanceOf', - parameters: [':userAddress', '8'], - returnValueTest: { - comparator: '>', - value: '0', - }, - }, -]; -const evmBasicBooleanAccessControlConditions = [ - { - contractAddress: '0x22C1f6050E56d2876009903609a2cC3fEf83B415', - standardContractType: 'POAP', - chain: 'xdai', - method: 'eventId', - parameters: [], - returnValueTest: { - comparator: '=', - value: '37582', - }, - }, - { - operator: 'or', - }, - { - contractAddress: '0x22C1f6050E56d2876009903609a2cC3fEf83B415', - standardContractType: 'POAP', - chain: 'ethereum', - method: 'eventId', - parameters: [], - returnValueTest: { - comparator: '=', - value: '37582', - }, - }, -]; -const evmBasicNestedAccessControlConditions = [ - ...evmBasicAccessControlConditions, - { - operator: 'or', - }, - evmBasicBooleanAccessControlConditions, -]; -const evmContractAccessControlConditions = [ - { - contractAddress: '0x7C7757a9675f06F3BE4618bB68732c4aB25D2e88', - functionName: 'balanceOf', - functionParams: [':userAddress', '8'], - functionAbi: { - type: 'function', - stateMutability: 'view', - outputs: [ - { - type: 'uint256', - name: '', - internalType: 'uint256', - }, - ], - name: 'balanceOf', - inputs: [ - { - type: 'address', - name: 'account', - internalType: 'address', - }, - { - type: 'uint256', - name: 'id', - internalType: 'uint256', - }, - ], - }, - chain, - returnValueTest: { - key: '', - comparator: '>', - value: '0', - }, - }, -]; -const solAccessControlConditions = [ - { - method: 'getBalance', - params: [':userAddress'], - pdaParams: [], - pdaInterface: { offset: 0, fields: {} }, - pdaKey: '', - chain: 'solanaTestnet', - returnValueTest: { - key: '', - comparator: '>=', - value: '100000000', // equals 0.1 SOL - }, - }, -]; -const cosmosAccessControlConditions = [ - { - conditionType: 'cosmos', - path: ':userAddress', - chain: 'cosmos', - returnValueTest: { - key: '', - comparator: '=', - value: 'cosmos1vn6zl0924yj86jrp330wcwjclzdharljq03a8h', - }, - }, -]; -const unifiedAccessControlConditions = [ - { - conditionType: 'solRpc', - method: 'getBalance', - params: [':userAddress'], - chain: 'solana', - pdaParams: [], - pdaInterface: { offset: 0, fields: {} }, - pdaKey: '', - returnValueTest: { - key: '', - comparator: '>=', - value: '100000000', // equals 0.1 SOL - }, - }, - { operator: 'or' }, - { - conditionType: 'evmBasic', - contractAddress: '', - standardContractType: '', - chain: 'ethereum', - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '10000000000000', - }, - }, - { operator: 'or' }, - { - conditionType: 'evmContract', - contractAddress: '0x7C7757a9675f06F3BE4618bB68732c4aB25D2e88', - functionName: 'balanceOf', - functionParams: [':userAddress', '8'], - functionAbi: { - type: 'function', - stateMutability: 'view', - outputs: [ - { - type: 'uint256', - name: '', - internalType: 'uint256', - }, - ], - name: 'balanceOf', - inputs: [ - { - type: 'address', - name: 'account', - internalType: 'address', - }, - { - type: 'uint256', - name: 'id', - internalType: 'uint256', - }, - ], - }, - chain: 'polygon', - returnValueTest: { - key: '', - comparator: '>', - value: '0', - }, - }, -]; -// Failing cases -const noConditions = []; -const evmBasicAccessControlConditionsWithMissingFields = [ - { - contractAddress: '', - // standardContractType: '', - // chain, - // method: 'eth_getBalance', - // parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, -]; -const evmBasicNestedAccessControlConditionsWithMissingFields = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - { - operator: 'and', - }, - [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '1', - }, - }, - { - operator: 'and', - }, - { - contractAddress: '', - // standardContractType: '', - // chain, - // method: 'eth_getBalance', - // parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '2', - }, - }, - ], -]; -const evmBasicAccessControlConditionsWithInvalidFields = [ - { - contractAddress: 0x7a250d5630b4cf539739df2c5dacb4c659f2488d, - standardContractType: 'AMM', - chain: 'bitcoin', - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, -]; -const evmContractAccessControlConditionsWithMissingFields = [ - { - // contractAddress: '0x7C7757a9675f06F3BE4618bB68732c4aB25D2e88', - functionName: 'balanceOf', - // functionParams: [':userAddress', '8'], - functionAbi: { - type: 'function', - stateMutability: 'view', - outputs: [ - { - type: 'uint256', - name: '', - internalType: 'uint256', - }, - ], - name: 'balanceOf', - inputs: [ - { - type: 'address', - name: 'account', - internalType: 'address', - }, - { - type: 'uint256', - name: 'id', - internalType: 'uint256', - }, - ], - }, - // chain: 'polygon', - returnValueTest: { - key: '', - comparator: '>', - value: '0', - }, - }, -]; -const evmContractNestedAccessControlConditionsWithInvalidFields = [ - { - contractAddress: 0x7c7757a9675f06f3be4618bb68732c4ab25d2e88, - functionName: 'balanceOf', - functionParams: [':userAddress', '8'], - functionAbi: { - type: 'function', - stateMutability: 'view', - outputs: [ - { - type: 'uint256', - name: '', - internalType: 'uint256', - }, - ], - name: 'balanceOf', - inputs: [ - { - type: 'address', - name: 'account', - internalType: 'address', - }, - { - type: 'uint256', - name: 'id', - internalType: 'uint256', - }, - ], - }, - chain: 'eth', - returnValueTest: { - key: '', - comparator: '>', - value: '0', - }, - }, -]; -const solAccessControlConditionsWithMissingFields = [ - { - method: 'getBalance', - params: [':userAddress'], - chain: 'solana', - pdaParams: [], - // pdaInterface: { offset: 0, fields: {} }, - // pdaKey: '', - returnValueTest: { - key: '', - comparator: '>=', - value: '100000000', // equals 0.1 SOL - }, - }, -]; -const invalidUnifiedAccessControlConditions = [ - { - conditionType: 'solRpc', - method: 'getBalance', - params: [':userAddress'], - // chain: 'solana', - pdaParams: [], - pdaInterface: { offset: 0, fields: {} }, - pdaKey: '', - returnValueTest: { - key: '', - comparator: '>=', - value: '100000000', // equals 0.1 SOL - }, - }, - { operator: 'or' }, - { - conditionType: 'evmBasic', - contractAddress: '', - standardContractType: '', - chain: 'ethereum', - // method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '10000000000000', - }, - }, - { operator: 'or' }, - { - conditionType: 'evmContract', - contractAddress: '0x7C7757a9675f06F3BE4618bB68732c4aB25D2e88', - // functionName: 'balanceOf', - functionParams: [':userAddress', '8'], - functionAbi: { - type: 'function', - stateMutability: 'view', - outputs: [ - { - type: 'uint256', - name: '', - internalType: 'uint256', - }, - ], - name: 'balanceOf', - inputs: [ - { - type: 'address', - name: 'account', - internalType: 'address', - }, - { - type: 'uint256', - name: 'id', - internalType: 'uint256', - }, - ], - }, - // chain: 'polygon', - returnValueTest: { - key: '', - comparator: '>', - value: '0', - }, - }, -]; -const invalidConditionUnifiedAccessControlConditions = [ - { - conditionType: 'zkSync', // Does not exist - contractAddress: '', - standardContractType: '', - chain: 'ethereum', - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '10000000000000', - }, - }, -]; -const noTypeUnifiedAccessControlConditions = [ - { - // conditionType: 'evmBasic', - contractAddress: '', - standardContractType: '', - chain: 'ethereum', - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '10000000000000', - }, - }, -]; - -await testThese([ - // Success cases - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('evmBasic', { - accessControlConditions: evmBasicAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('evmBasicBoolean', { - accessControlConditions: evmBasicBooleanAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('evmBasicNested', { - accessControlConditions: evmBasicNestedAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('evmContract', { - evmContractConditions: evmContractAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('sol', { - solRpcConditions: solAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('cosmos', { - unifiedAccessControlConditions: cosmosAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestSuccess('unified', { - unifiedAccessControlConditions: unifiedAccessControlConditions, - }), - }, - // Failing cases - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('noConditions', {}), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('emptyArrayConditions', { - accessControlConditions: noConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('evmBasicMissingFields', { - accessControlConditions: evmBasicAccessControlConditionsWithMissingFields, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('evmBasicMissingNestedFields', { - accessControlConditions: - evmBasicNestedAccessControlConditionsWithMissingFields, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('evmBasicInvalidFields', { - accessControlConditions: evmBasicAccessControlConditionsWithInvalidFields, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('evmContractMissingFields', { - evmContractConditions: - evmContractAccessControlConditionsWithMissingFields, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('evmContractInvalidFields', { - evmContractConditions: - evmContractNestedAccessControlConditionsWithInvalidFields, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('solMissingFields', { - solRpcConditions: solAccessControlConditionsWithMissingFields, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('unifiedMissingFields', { - unifiedAccessControlConditions: invalidUnifiedAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('unifiedInvalidSchema', { - unifiedAccessControlConditions: - invalidConditionUnifiedAccessControlConditions, - }), - }, - { - name: path.basename(import.meta.url), - fn: accessControlConditionsTestFailure('unifiedNoType', { - unifiedAccessControlConditions: noTypeUnifiedAccessControlConditions, - }), - }, -]); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-file.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-file.mjs deleted file mode 100644 index a0e2ec8a17..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-file.mjs +++ /dev/null @@ -1,63 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const chain = 'ethereum'; - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - ]; - const message = 'Hello world'; - const blob = new Blob([message], { type: 'text/plain' }); - const blobArray = new Uint8Array(await blob.arrayBuffer()); - - // ==================== Test Logic ==================== - const { ciphertext, dataToEncryptHash } = await LitJsSdk.encryptFile( - { - accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - file: blob, - }, - client - ); - const decriptedFile = await LitJsSdk.decryptToFile( - { - accessControlConditions, - ciphertext, - dataToEncryptHash, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - }, - client - ); - - // ==================== Post-Validation ==================== - if (blobArray.length !== decriptedFile.length) { - return fail( - `decrypted file should match the original file but received ${decriptedFile}` - ); - } - for (let i = 0; i < blobArray.length; i++) { - if (blobArray[i] !== decriptedFile[i]) { - return fail(`decrypted file should match the original file`); - } - } - - // ==================== Success ==================== - return success('File was encrypted and then decrypted successfully'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-file.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-file.mjs deleted file mode 100644 index 369ba7d234..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-file.mjs +++ /dev/null @@ -1,57 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const chain = 'ethereum'; - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - ]; - const message = 'Hello world'; - const blob = new Blob([message], { type: 'text/plain' }); - const blobArray = new Uint8Array(await blob.arrayBuffer()); - - // ==================== Test Logic ==================== - const encryptedJsonStr = await LitJsSdk.encryptToJson({ - accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - file: blob, - litNodeClient: client, - }); - - const decryptedFile = await LitJsSdk.decryptFromJson({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - parsedJsonData: JSON.parse(encryptedJsonStr), - litNodeClient: client, - }); - - // ==================== Post-Validation ==================== - if (blobArray.length !== decryptedFile.length) { - return fail( - `decrypted file should match the original file but received ${decryptedFile}` - ); - } - for (let i = 0; i < blobArray.length; i++) { - if (blobArray[i] !== decryptedFile[i]) { - return fail(`decrypted file should match the original file`); - } - } - - // ==================== Success ==================== - return success('File was encrypted and then decrypted successfully'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-string.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-string.mjs deleted file mode 100644 index c53d2143b5..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-json-string.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const chain = 'ethereum'; - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - ]; - const message = 'Hello world'; - - // ==================== Test Logic ==================== - const encryptedJsonStr = await LitJsSdk.encryptToJson({ - accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - string: message, - litNodeClient: client, - }); - - const decryptedMessage = await LitJsSdk.decryptFromJson({ - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - parsedJsonData: JSON.parse(encryptedJsonStr), - litNodeClient: client, - }); - - // ==================== Post-Validation ==================== - if (message !== decryptedMessage) { - return fail( - `decryptedMessage should be ${message} but received ${decryptedMessage}` - ); - } - - // ==================== Success ==================== - return success('Message was encrypted and then decrypted successfully'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-nodes.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-nodes.mjs deleted file mode 100644 index 8790a72750..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-nodes.mjs +++ /dev/null @@ -1,127 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import * as siwe from 'siwe'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ========== PKP WALLET SETUP =========== - // Getting the session signatures that will control the PKP - const authNeededCallback = async (params) => { - const response = await client.signSessionKey({ - statement: params.statement, - authMethods: [ - { - authMethodType: 1, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }, - ], - pkpPublicKey: `0x${globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey}`, - expiration: params.expiration, - resources: params.resources, - chainId: 1, - }); - return response.authSig; - }; - const resourceAbilities = [ - { - resource: new LitActionResource('*'), - ability: LitAbility.AccessControlConditionDecryption, - }, - ]; - - const pkpWallet = new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - authContext: { - client, - getSessionSigsProps: { - chain: 'ethereum', - // expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - resourceAbilityRequests: resourceAbilities, - authNeededCallback, - }, - }, - }); - - // Using the PKP to get an authentication signature for it - const statement = - 'This is a test statement. You can put anything you want here.'; - const siweMessage = new siwe.SiweMessage({ - domain: 'localhost', - address: pkpWallet.address, - statement, - uri: 'https://localhost/login', - version: '1', - chainId: 1, - nonce: await litNodeClient.getLatestBlockhash(), - expirationTime: new Date(Date.now() + 60_000 * 60).toISOString(), - }); - const messageToSign = siweMessage.prepareMessage(); - const signature = await pkpWallet.signMessage(messageToSign); - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: pkpWallet.address, - }; - - // ==================== Test Setup ==================== - const chain = 'ethereum'; - - // Control the address of the user that will be able to encrypt/decrypt the message - // In this case, the PKP is the user - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: '', - parameters: [':userAddress'], - returnValueTest: { - comparator: '=', - value: pkpWallet.address, - }, - }, - ]; - const message = 'Hello world'; - - // ==================== Test Logic ==================== - const { ciphertext, dataToEncryptHash } = await LitJsSdk.encryptString( - { - accessControlConditions, - authSig, - chain, - dataToEncrypt: message, - }, - client - ); - const decryptedMessage = await LitJsSdk.decryptToString( - { - accessControlConditions, - ciphertext, - dataToEncryptHash, - authSig, - chain, - }, - client - ); - - // ==================== Post-Validation ==================== - if (message !== decryptedMessage) { - return fail( - `decryptedMessage should be ${message} but received ${decryptedMessage}` - ); - } - - // ==================== Success ==================== - return success( - 'Message was encrypted and then decrypted using the pkp successfully' - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-string.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-string.mjs deleted file mode 100644 index cf243543d1..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-string.mjs +++ /dev/null @@ -1,56 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const chain = 'ethereum'; - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - ]; - const message = 'Hello world'; - - // ==================== Test Logic ==================== - const { ciphertext, dataToEncryptHash } = await LitJsSdk.encryptString( - { - accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - dataToEncrypt: message, - }, - client - ); - const decryptedMessage = await LitJsSdk.decryptToString( - { - accessControlConditions, - ciphertext, - dataToEncryptHash, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - }, - client - ); - - // ==================== Post-Validation ==================== - if (message !== decryptedMessage) { - return fail( - `decryptedMessage should be ${message} but received ${decryptedMessage}` - ); - } - - // ==================== Success ==================== - return success('Message was encrypted and then decrypted successfully'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-zip-string.mjs b/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-zip-string.mjs deleted file mode 100644 index 7a0be082bc..0000000000 --- a/e2e-nodejs/group-pkp-encryption-decryption/test-pkp-encryption-decryption-zip-string.mjs +++ /dev/null @@ -1,60 +0,0 @@ -import path from 'path'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - const chain = 'ethereum'; - const accessControlConditions = [ - { - contractAddress: '', - standardContractType: '', - chain, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>=', - value: '0', - }, - }, - ]; - const message = 'Hello world'; - - // ==================== Test Logic ==================== - const { ciphertext, dataToEncryptHash } = await LitJsSdk.zipAndEncryptString( - { - accessControlConditions, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - dataToEncrypt: message, - }, - client - ); - const decryptedZip = await LitJsSdk.decryptToZip( - { - accessControlConditions, - ciphertext, - dataToEncryptHash, - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - chain, - }, - client - ); - - const decryptedMessage = await decryptedZip['string.txt'].async('string'); - - // ==================== Post-Validation ==================== - if (message !== decryptedMessage) { - return fail( - `decryptedMessage should be ${message} but received ${decryptedMessage}` - ); - } - - // ==================== Success ==================== - return success( - 'Message was zipped and encrypted, then decrypted successfully' - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-session-sigs/test-pkp-multiple-auth-contexts.mjs b/e2e-nodejs/group-pkp-session-sigs/test-pkp-multiple-auth-contexts.mjs deleted file mode 100644 index afa665dc87..0000000000 --- a/e2e-nodejs/group-pkp-session-sigs/test-pkp-multiple-auth-contexts.mjs +++ /dev/null @@ -1,143 +0,0 @@ -import path from 'path'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; -import { success, fail, testThese } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; - -export async function noAuthContext() { - // ==================== Test Logic ==================== - try { - new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - } catch (e) { - if ( - e - .toString() - .includes( - 'Multiple authentications are defined, can only use one at a time' - ) - ) { - return success( - 'It should validate that only no auth context is defined.' - ); - } - } - - return fail( - 'Should have thrown an error for having no auth context defined.' - ); -} - -export async function authSigAndAuthContext() { - // ==================== Test Logic ==================== - try { - new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - authContext: { - client, - getSessionSigsProps: { - chain: 'ethereum', - expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - resourceAbilityRequests: [], - authNeededCallback: () => {}, - }, - }, - }); - } catch (e) { - if ( - e - .toString() - .includes( - 'Multiple authentications are defined, can only use one at a time' - ) - ) { - return success( - 'It should validate that only one of authSig and authContext is defined.' - ); - } - } - - return fail( - 'Should have thrown an error for having both authSig and authContext defined.' - ); -} - -export async function sessionSigsAndAuthContext() { - // ==================== Test Logic ==================== - const sessionKeyPair = client.getSessionKey(); - const resourceAbilities = [ - { - resource: new LitActionResource('*'), - ability: LitAbility.AccessControlConditionDecryption, - }, - ]; - const authNeededCallback = async (params) => { - const response = await client.signSessionKey({ - statement: params.statement, - authMethods: [ - { - authMethodType: 1, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }, - ], - pkpPublicKey: `0x${globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey}`, - expiration: params.expiration, - resources: params.resources, - chainId: 1, - }); - return response.authSig; - }; - const sessionSigs = await client.getSessionSigs({ - chain: 'ethereum', - expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - resourceAbilityRequests: resourceAbilities, - sessionKey: sessionKeyPair, - authNeededCallback, - }); - try { - new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - controllerSessionSigs: sessionSigs, - authContext: { - client, - getSessionSigsProps: { - chain: 'ethereum', - expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - resourceAbilityRequests: [], - authNeededCallback: () => {}, - }, - }, - }); - } catch (e) { - if ( - e - .toString() - .includes( - 'Multiple authentications are defined, can only use one at a time' - ) - ) { - return success( - 'It should validate that only one of sessionSigs and authContext is defined.' - ); - } - } - - return fail( - 'Should have thrown an error for having both sessionSigs and authContext defined.' - ); -} - -await testThese([ - { name: path.basename(import.meta.url), fn: noAuthContext }, - { name: path.basename(import.meta.url), fn: authSigAndAuthContext }, - { name: path.basename(import.meta.url), fn: sessionSigsAndAuthContext }, -]); diff --git a/e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-eth-wallet-auth-method.mjs b/e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-eth-wallet-auth-method.mjs deleted file mode 100644 index 626b3461f8..0000000000 --- a/e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-eth-wallet-auth-method.mjs +++ /dev/null @@ -1,81 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; -import { ethers } from 'ethers'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -// We can also simply use crypto.subtile like this: -// const TO_SIGN = new Uint8Array( -// await crypto.subtle.digest('SHA-256', new TextEncoder().encode('meow')) -// ); -const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])); - -export async function main() { - // ==================== Setup ==================== - const authNeededCallback = async (params) => { - const response = await client.signSessionKey({ - statement: params.statement, - authMethods: [ - { - authMethodType: 1, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }, - ], - pkpPublicKey: `0x${globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey}`, - expiration: params.expiration, - resources: params.resources, - chainId: 1, - }); - return response.authSig; - }; - - const resourceAbilities = [ - { - resource: new LitActionResource('*'), - ability: LitAbility.PKPSigning, - }, - ]; - - // ==================== Test Logic ==================== - const pkpWallet = new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - authContext: { - client: client, - getSessionSigsProps: { - chain: 'ethereum', - resourceAbilityRequests: resourceAbilities, - authNeededCallback, - }, - }, - }); - - await pkpWallet.init(); - - const signature = await pkpWallet.signMessage(TO_SIGN); - - // ==================== Post-Validation ==================== - // check if the given signature is a valid signature using ethers - const isValid = ethers.utils.verifyMessage( - TO_SIGN, - signature, - pkpWallet.address - ); - - if (!isValid) { - return fail( - `it should use sessionSigs generated by eth wallet auth method to sign data. Signature is ${signature} and pkpWallet.address is ${pkpWallet.address}` - ); - } - - // ==================== Success ==================== - return success( - `it should use sessionSigs generated by eth wallet auth method to sign data. Signature is ${signature} and pkpWallet.address is ${pkpWallet.address} and isValid is ${isValid}` - ); -} -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-session-cache.mjs b/e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-session-cache.mjs deleted file mode 100644 index 31d1239df0..0000000000 --- a/e2e-nodejs/group-pkp-session-sigs/test-pkp-sign-with-session-sigs-session-cache.mjs +++ /dev/null @@ -1,92 +0,0 @@ -import path from 'path'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import { client } from '../00-setup.mjs'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; -import { ethers } from 'ethers'; -import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; - -// NOTE: you need to hash data before you send it in. -// If you send something that isn't 32 bytes, the nodes will return an error. -// PKPEthersWallet::signMessage does this for you before passing it to the lit client. -const message = [1, 2, 3, 4, 5]; -// const TO_SIGN = ethers.utils.arrayify(ethers.utils.keccak256(message)); - -export async function main() { - // ==================== Setup ==================== - const resourceAbilities = [ - { - resource: new LitActionResource('*'), - ability: LitAbility.LitActionExecution, - // ability: LitAbility.PKPSigning, - }, - ]; - - const authNeededCallback = async (params) => { - const response = await client.signSessionKey({ - statement: params.statement, - // authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - authMethods: [ - { - authMethodType: 1, - accessToken: JSON.stringify(globalThis.LitCI.CONTROLLER_AUTHSIG), - }, - ], - pkpPublicKey: `0x${globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey}`, - expiration: params.expiration, - resources: params.resources, - chainId: 1, - resourceAbilityRequests: resourceAbilities, - }); - return response.authSig; - }; - - // ==================== Test Logic ==================== - - // const sessionSigs = await client.getSessionSigs({ - // chain: 'ethereum', - // expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - // resourceAbilityRequests: resourceAbilities, - // sessionKey: sessionKeyPair, - // authNeededCallback, - // }); - - // console.log('sessionSigs:', sessionSigs); - - // const pkpSignRes = await client?.pkpSign({ - // toSign: TO_SIGN, - // pubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - // sessionSigs: sessionSigs, - // }); - // console.log(`====================== ${JSON.stringify(pkpSignRes)}`); - - const pkpWallet = new PKPEthersWallet({ - pkpPubKey: globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - authContext: { - client, - getSessionSigsProps: { - chain: 'ethereum', - expiration: new Date(Date.now() + 60_000 * 60).toISOString(), - resourceAbilityRequests: resourceAbilities, - authNeededCallback, - }, - }, - }); - await pkpWallet.init(); - - const signature = await pkpWallet.signMessage(message); - - // ==================== Post-Validation ==================== - - if (!signature) { - return fail('Failed to sign data with sessionSigs generated previously'); - } - - // ==================== Success ==================== - return success( - `it should get sessionSigs on demand from client and sign data with it` - ); -} -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-sign/test-pkp-sign.mjs b/e2e-nodejs/group-pkp-sign/test-pkp-sign.mjs deleted file mode 100644 index 0d4313dc3d..0000000000 --- a/e2e-nodejs/group-pkp-sign/test-pkp-sign.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; -import { ethers } from 'ethers'; - -const DATA_TO_SIGN = new Uint8Array( - await crypto.subtle.digest('SHA-256', new TextEncoder().encode('Hello world')) -); - -export async function main() { - // ==================== Test Logic ==================== - - const sig = await client.pkpSign({ - toSign: DATA_TO_SIGN, - authMethod: [], - authSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pubKey: globalThis.LitCI.PKP_INFO.publicKey, - rpc: LITCONFIG.CHRONICLE_RPC, - litNetwork: globalThis.LitCI.network, - }); - - const recoveredPk = ethers.utils.recoverPublicKey( - DATA_TO_SIGN, - sig.signature - ); - - const recoveredAddr = ethers.utils.computeAddress(recoveredPk); - - // ==================== Post-Validation ==================== - - ['r', 's', 'signature', 'publicKey', 'dataSigned', 'recid'].forEach((key) => { - if (!sig[key]) { - return fail(`sig.${key} is undefined, empty, or null`); - } - }); - - if (recoveredAddr !== globalThis.LitCI.PKP_INFO.ethAddress) { - return fail( - `recovered address ${recoveredAddr} should be ${LITCONFIG.PKP_ETH_ADDRESS}` - ); - } - - // ==================== Success ==================== - return success( - `PKP sign endpoint should sign message. recoveredAddr: ${recoveredAddr}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-pkp-sui/test-pkp-sui-send-tx.mjs b/e2e-nodejs/group-pkp-sui/test-pkp-sui-send-tx.mjs deleted file mode 100644 index 03bf199dc9..0000000000 --- a/e2e-nodejs/group-pkp-sui/test-pkp-sui-send-tx.mjs +++ /dev/null @@ -1,102 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { PKPSuiWallet } from '@lit-protocol/pkp-sui'; - -import { - JsonRpcProvider, - devnetConnection, - TransactionBlock, -} from '@mysten/sui.js'; - -// NOTE: You can check your tx using https://suiexplorer.com/?network=devnet -export async function main() { - // ==================== Setup ==================== - const provider = new JsonRpcProvider(devnetConnection); - - const suiWallet = new PKPSuiWallet( - { - controllerAuthSig: globalThis.LitCI.CONTROLLER_AUTHSIG, - pkpPubKey: globalThis.LitCI.PKP_INFO.publicKey, - }, - provider - ); - - await suiWallet.init(); - - const pkpSuiAddress = await suiWallet.getAddress(); - const balance = await provider.getBalance({ - owner: pkpSuiAddress, - }); - - if (balance.totalBalance <= 0) { - try { - const response = await fetch('https://faucet.devnet.sui.io/gas', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - FixedAmountRequest: { recipient: pkpSuiAddress }, // Replace with your SUI address - }), - }); - - if (!response.ok) throw Error(response.statusText); - - const data = await response.json(); - console.log('Success:', data); - } catch (error) { - console.error('Error:', error); - } - } - - // ==================== Test Logic ==================== - const tx = new TransactionBlock(); - const [coin] = tx.splitCoins(tx.gas, [tx.pure(1000)]); - tx.transferObjects([coin], tx.pure(pkpSuiAddress)); - - // ************************************************* - // * REAL TX * - // ************************************************* - if ( - process.env.REAL_TX === 'true' ?? - LITCONFIG.test.sendRealTxThatCostsMoney - ) { - const transferTx = await suiWallet.signAndExecuteTransactionBlock({ - transactionBlock: tx, - }); - - console.log('transferTx', transferTx); - - // ==================== Post-Validation ==================== - if (!transferTx.digest) { - return fail('transferTx should have digest'); - } - - // ==================== Success ==================== - - return success( - `PKPSuiWallet should be able to send tx https://suiexplorer.com/txblock/${transferTx.digest}?network=devnet` - ); - } - - // ************************************************* - // * MOCK TX * - // ************************************************* - else { - const transferTx = await suiWallet.dryRunTransactionBlock({ - transactionBlock: tx, - }); - - // ==================== Post-Validation ==================== - if (!suiWallet.litNodeClientReady) { - return fail('litNodeClient should be ready'); - } - - if (!transferTx.effects.status.status === 'success') { - return fail('transferTx should be success'); - } - - return success(`PKPSuiWallet should be able to send tx(❗️DRY-RUN)`); - } -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli-mint/test-rli-mint-day.mjs b/e2e-nodejs/group-rli-mint/test-rli-mint-day.mjs deleted file mode 100644 index a05095168f..0000000000 --- a/e2e-nodejs/group-rli-mint/test-rli-mint-day.mjs +++ /dev/null @@ -1,62 +0,0 @@ -// Usage: -// DEBUG=true NETWORK=manzano yarn test:e2e:nodejs --filter=test-rli-mint-day.mjs -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - // ==================== Setup ==================== - // convert to requests per second - const REQUESTS_PER_DAY = 20000; - const REQUESTS_PER_KILLOSECOND = REQUESTS_PER_DAY * (1 / 24 / 60 / 60) * 1000; // 20000 requests per day - - // 5% of the expected upper bound - const EXPECTED_UPPER_BOUND = REQUESTS_PER_KILLOSECOND * 1.05; - - let contractClient = new LitContracts({ - signer: new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ), - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - // -- mint new Capacity Credits NFT - const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - requestsPerDay: REQUESTS_PER_DAY, - daysUntilUTCMidnightExpiration: 1, - }); - - const rateLimit = await contractClient.rateLimitNftContract.read.capacity( - capacityTokenIdStr - ); - - const requestsPerKilosecond = rateLimit.requestsPerKilosecond.toNumber(); - - console.log('capacityTokenIdStr:', capacityTokenIdStr); - console.log('requestsPerKilosecond:', requestsPerKilosecond); - console.log('EXPECTED_UPPER_BOUND:', EXPECTED_UPPER_BOUND); - - // ==================== Post-Validation ==================== - if (requestsPerKilosecond <= EXPECTED_UPPER_BOUND) { - return success( - `Successfully minted a capacity credits nft with id: ${capacityTokenIdStr} and rate limit: ${requestsPerKilosecond} which is less than or equal to the expected upper bound: ${EXPECTED_UPPER_BOUND}` - ); - } - - return fail( - `Failed to mint a capacity credits nft with id: ${capacityTokenIdStr} and rate limit: ${requestsPerKilosecond} which is greater than the expected upper bound: ${EXPECTED_UPPER_BOUND}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli-mint/test-rli-mint-kilosecond.mjs b/e2e-nodejs/group-rli-mint/test-rli-mint-kilosecond.mjs deleted file mode 100644 index a7a0067a2c..0000000000 --- a/e2e-nodejs/group-rli-mint/test-rli-mint-kilosecond.mjs +++ /dev/null @@ -1,60 +0,0 @@ -// Usage: -// DEBUG=true NETWORK=manzano yarn test:e2e:nodejs --filter=test-rli-mint-kilosecond.mjs -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - // ==================== Setup ==================== - const REQUESTS_PER_KILLOSECOND = 1000; - - // 5% of the expected upper bound - const EXPECTED_UPPER_BOUND = REQUESTS_PER_KILLOSECOND * 1.05; - - let contractClient = new LitContracts({ - signer: new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ), - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - // -- mint new Capacity Credits NFT - const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - requestsPerKilosecond: REQUESTS_PER_KILLOSECOND, - daysUntilUTCMidnightExpiration: 1, - }); - - const rateLimit = await contractClient.rateLimitNftContract.read.capacity( - capacityTokenIdStr - ); - - const requestsPerKilosecond = rateLimit.requestsPerKilosecond.toNumber(); - - console.log('capacityTokenIdStr:', capacityTokenIdStr); - console.log('requestsPerKilosecond:', requestsPerKilosecond); - console.log('EXPECTED_UPPER_BOUND:', EXPECTED_UPPER_BOUND); - - // ==================== Post-Validation ==================== - if (requestsPerKilosecond <= EXPECTED_UPPER_BOUND) { - return success( - `Successfully minted a capacity credits nft with id: ${capacityTokenIdStr} and rate limit: ${requestsPerKilosecond} which is less than or equal to the expected upper bound: ${EXPECTED_UPPER_BOUND}` - ); - } - - return fail( - `Failed to mint a capacity credits nft with id: ${capacityTokenIdStr} and rate limit: ${requestsPerKilosecond} which is greater than the expected upper bound: ${EXPECTED_UPPER_BOUND}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli-mint/test-rli-mint-second.mjs b/e2e-nodejs/group-rli-mint/test-rli-mint-second.mjs deleted file mode 100644 index b1c093eaa1..0000000000 --- a/e2e-nodejs/group-rli-mint/test-rli-mint-second.mjs +++ /dev/null @@ -1,62 +0,0 @@ -// Usage: -// DEBUG=true NETWORK=manzano yarn test:e2e:nodejs --filter=test-rli-mint-second.mjs -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - // ==================== Setup ==================== - // convert to requests per second - const REQUESTS_PER_SECOND = 1; - const REQUESTS_PER_KILLOSECOND = REQUESTS_PER_SECOND * 1000; // 1000 requests per kilosecond - - // 5% of the expected upper bound - const EXPECTED_UPPER_BOUND = REQUESTS_PER_KILLOSECOND * 1.05; - - let contractClient = new LitContracts({ - signer: new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ), - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // ==================== Test Logic ==================== - // -- mint new Capacity Credits NFT - const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - requestsPerSecond: REQUESTS_PER_SECOND, - daysUntilUTCMidnightExpiration: 1, - }); - - const rateLimit = await contractClient.rateLimitNftContract.read.capacity( - capacityTokenIdStr - ); - - const requestsPerKilosecond = rateLimit.requestsPerKilosecond.toNumber(); - - console.log('capacityTokenIdStr:', capacityTokenIdStr); - console.log('requestsPerKilosecond:', requestsPerKilosecond); - console.log('EXPECTED_UPPER_BOUND:', EXPECTED_UPPER_BOUND); - - // ==================== Post-Validation ==================== - if (requestsPerKilosecond <= EXPECTED_UPPER_BOUND) { - return success( - `Successfully minted a capacity credits nft with id: ${capacityTokenIdStr} and rate limit: ${requestsPerKilosecond} which is less than or equal to the expected upper bound: ${EXPECTED_UPPER_BOUND}` - ); - } - - return fail( - `Failed to mint a capacity credits nft with id: ${capacityTokenIdStr} and rate limit: ${requestsPerKilosecond} which is greater than the expected upper bound: ${EXPECTED_UPPER_BOUND}` - ); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-diff-delegatee.mjs b/e2e-nodejs/group-rli/test-rli-from-lit-node-client-diff-delegatee.mjs deleted file mode 100644 index 3040380e95..0000000000 --- a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-diff-delegatee.mjs +++ /dev/null @@ -1,232 +0,0 @@ -// Usage: -// DEBUG=true NETWORK=habanero MINT_NEW=true yarn test:e2e:nodejs --filter=test-rli-from-lit-node-client-diff-delegatee.mjs -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; - -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - - // NOTE: In this example, the dApp owner would be both the Capacity Credits NFT delegator and the delegatee (end user) - // for ease of testing. - // ==================== Setup ==================== - - // ==================================================== - // = dApp Owner's Perspetive = - // ==================================================== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - globalThis.LitCI.wallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - const dAppOwnerWallet = globalThis.LitCI.wallet; - - const dAppOwnerWallet_address = globalThis.LitCI.wallet.address; - const dAppOwnerWallet_authSig = globalThis.LitCI.CONTROLLER_AUTHSIG; - const dAppOwnerWallet_pkpPublicKey = globalThis.LitCI.PKP_INFO.publicKey; - - console.log('dAppOwnerWallet_authSig:', dAppOwnerWallet_authSig); - console.log('dAppOwnerWallet_address:', dAppOwnerWallet_address); - console.log('dAppOwnerWallet_pkpPublicKey:', dAppOwnerWallet_pkpPublicKey); - - const delegatedWalletB = new ethers.Wallet( - '0xe1090085b352120867ea7b154ceeee30654903a6c37afa1d5c5bcabc63c96676', - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ); - - const delegatedWalletB_address = delegatedWalletB.address; - - // As a dApp owner, I want to mint a Rate Limit Increase NFT so he who owns or delegated to - // would be able to perform 14400 requests per day - let contractClient = new LitContracts({ - signer: dAppOwnerWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // -- mint Capacity Credits NFT - - // -- static to test faster - // const capacityTokenIdStr = '2'; - - // -- mint new Capacity Credits NFT - const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - requestsPerDay: 14400, // 10 request per minute - daysUntilUTCMidnightExpiration: 2, - }); - - console.log('capacityTokenIdStr:', capacityTokenIdStr); - console.log('dAppOwnerWallet:', dAppOwnerWallet); - - const litNodeClient = new LitNodeClient({ - litNetwork: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - minNodeCount: undefined, - checkNodeAttestation: process.env.CHECK_SEV ?? false, - }); - - await litNodeClient.connect(); - - // we will create an delegation auth sig, which internally we will create - // a recap object, add the resource "lit-ratelimitincrease://{tokenId}" to it, and add it to the siwe - // message. We will then sign the siwe message with the dApp owner's wallet. - const { capacityDelegationAuthSig, litResource } = - await litNodeClient.createCapacityDelegationAuthSig({ - uses: '1', - dAppOwnerWallet: dAppOwnerWallet, - capacityTokenId: capacityTokenIdStr, - delegateeAddresses: [delegatedWalletB_address], - }); - - console.log('capacityDelegationAuthSig:', capacityDelegationAuthSig); - console.log('litResource:', JSON.stringify(litResource)); - - // ==================================================== - // = As an end user = - // ==================================================== - const endUserContractClient = new LitContracts({ - signer: delegatedWalletB, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await endUserContractClient.connect(); - - let endUserPkpMintRes = - await endUserContractClient.pkpNftContractUtils.write.mint(); - - const endUserPkpInfo = endUserPkpMintRes.pkp; - - console.log('endUserPkpInfo:', endUserPkpInfo); - - // We need to setup a generic siwe auth callback that will be called by the lit-node-client - const endUserControllerAuthNeededCallback = async ({ - resources, - expiration, - uri, - }) => { - console.log('resources:', resources); - console.log('expiration:', expiration); - - const litResource = new LitActionResource('*'); - - const recapObject = - await litNodeClient.generateSessionCapabilityObjectWithWildcards([ - litResource, - ]); - - recapObject.addCapabilityForResource( - litResource, - LitAbility.LitActionExecution - ); - - const verified = recapObject.verifyCapabilitiesForResource( - litResource, - LitAbility.LitActionExecution - ); - - if (!verified) { - throw new Error('Failed to verify capabilities for resource'); - } - - console.log('authCallback verified:', verified); - - let siweMessage = new siwe.SiweMessage({ - domain: 'localhost:3000', - address: delegatedWalletB_address, - statement: 'Some custom statement.', - uri, - version: '1', - chainId: '1', - expirationTime: expiration, - resources, - }); - - siweMessage = recapObject.addToSiweMessage(siweMessage); - console.log('authCallback siwe:', siweMessage); - - const messageToSign = siweMessage.prepareMessage(); - const signature = await delegatedWalletB.signMessage(messageToSign); - - const authSig = { - sig: signature.replace('0x', ''), - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - // address: delegatedWalletB_address, - address: delegatedWalletB_address, - // algo: null, - }; - - console.log('authCallback authSig:', authSig); - - return authSig; - }; - - // - When generating a session sigs, we need to specify the resourceAbilityRequests, which - // is a list of resources and abilities that we want to be able to perform. - // "lit-ratelimitincrease://{tokenId}" that the dApp owner has delegated to us. - // - We also included the capacityDelegationAuthSig that we created earlier, which would be - // added to the capabilities array in the signing template. - let sessionSigs = await litNodeClient.getSessionSigs({ - expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours - chain: 'ethereum', - resourceAbilityRequests: [ - { - resource: new LitActionResource('*'), - ability: LitAbility.LitActionExecution, - }, - ], - authNeededCallback: endUserControllerAuthNeededCallback, - capacityDelegationAuthSig, - }); - - console.log('YY sessionSigs:', sessionSigs); - - // write to current directory sessionSigs.json - // fs.writeFileSync( - // path.join(process.cwd(), 'sessionSigs.json'), - // JSON.stringify(sessionSigs) - // ); - - // process.exit(); - - // /web/execute - const res = await litNodeClient.executeJs({ - sessionSigs, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: ethers.utils.arrayify( - ethers.utils.keccak256([1, 2, 3, 4, 5]) - ), - publicKey: endUserPkpInfo.publicKey, - }, - }); - - if (res) { - return success('delegatee able to sign'); - } - - return fail(`Failed to get proof from Recap Session Capability`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-no-delegatee.mjs b/e2e-nodejs/group-rli/test-rli-from-lit-node-client-no-delegatee.mjs deleted file mode 100644 index aa35694e46..0000000000 --- a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-no-delegatee.mjs +++ /dev/null @@ -1,184 +0,0 @@ -// Usage: -// DEBUG=true NETWORK=manzano MINT_NEW=true yarn test:e2e:nodejs --filter=test-rli-from-lit-node-client-no-delegatee.mjs -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; - -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - - // NOTE: In this example, there will be no delegatees in the array - // ==================== Setup ==================== - - // ==================================================== - // = dApp Owner's Perspetive = - // ==================================================== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - globalThis.LitCI.wallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - const dAppOwnerWallet = globalThis.LitCI.wallet; - - // As a dApp owner, I want to mint a Rate Limit Increase NFT so he who owns or delegated to - // would be able to perform 14400 requests per day - let contractClient = new LitContracts({ - signer: dAppOwnerWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // -- mint new Capacity Credits NFT - const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - requestsPerDay: 14400, // 10 request per minute - daysUntilUTCMidnightExpiration: 2, - }); - - const litNodeClient = new LitNodeClient({ - litNetwork: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - minNodeCount: undefined, - checkNodeAttestation: process.env.CHECK_SEV ?? false, - }); - - await litNodeClient.connect(); - - // we will create an delegation auth sig, which internally we will create - // a recap object, add the resource "lit-ratelimitincrease://{tokenId}" to it, and add it to the siwe - // message. We will then sign the siwe message with the dApp owner's wallet. - const { capacityDelegationAuthSig } = - await litNodeClient.createCapacityDelegationAuthSig({ - uses: '1', - dAppOwnerWallet: dAppOwnerWallet, - capacityTokenId: capacityTokenIdStr, - }); - - // ==================================================== - // = As an end user = - // ==================================================== - const endUserContractClient = new LitContracts({ - signer: dAppOwnerWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await endUserContractClient.connect(); - - let endUserPkpMintRes = - await endUserContractClient.pkpNftContractUtils.write.mint(); - - const endUserPkpInfo = endUserPkpMintRes.pkp; - - // We need to setup a generic siwe auth callback that will be called by the lit-node-client - const endUserControllerAuthNeededCallback = async ({ - resources, - expiration, - uri, - }) => { - const litResource = new LitActionResource('*'); - - const recapObject = - await litNodeClient.generateSessionCapabilityObjectWithWildcards([ - litResource, - ]); - - recapObject.addCapabilityForResource( - litResource, - LitAbility.LitActionExecution - ); - - const verified = recapObject.verifyCapabilitiesForResource( - litResource, - LitAbility.LitActionExecution - ); - - if (!verified) { - throw new Error('Failed to verify capabilities for resource'); - } - - console.log('authCallback verified:', verified); - - let siweMessage = new siwe.SiweMessage({ - domain: 'localhost:3000', - address: dAppOwnerWallet.address, - statement: 'Some custom statement.', - uri, - version: '1', - chainId: '1', - expirationTime: expiration, - resources, - }); - - siweMessage = recapObject.addToSiweMessage(siweMessage); - - const messageToSign = siweMessage.prepareMessage(); - const signature = await dAppOwnerWallet.signMessage(messageToSign); - - const authSig = { - sig: signature.replace('0x', ''), - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: dAppOwnerWallet.address, - }; - - return authSig; - }; - - // - When generating a session sigs, we need to specify the resourceAbilityRequests, which - // is a list of resources and abilities that we want to be able to perform. - // "lit-ratelimitincrease://{tokenId}" that the dApp owner has delegated to us. - // - We also included the capacityDelegationAuthSig that we created earlier, which would be - // added to the capabilities array in the signing template. - let sessionSigs = await litNodeClient.getSessionSigs({ - expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours - chain: 'ethereum', - resourceAbilityRequests: [ - { - resource: new LitActionResource('*'), - ability: LitAbility.LitActionExecution, - }, - ], - authNeededCallback: endUserControllerAuthNeededCallback, - capacityDelegationAuthSig, - }); - - // /web/execute - const res = await litNodeClient.executeJs({ - sessionSigs, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: ethers.utils.arrayify( - ethers.utils.keccak256([1, 2, 3, 4, 5]) - ), - publicKey: endUserPkpInfo.publicKey, - }, - }); - - if (res) { - return success('delegatee able to sign'); - } - - return fail(`Failed to get proof from Recap Session Capability`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-optional-capacity-token-id.mjs b/e2e-nodejs/group-rli/test-rli-from-lit-node-client-optional-capacity-token-id.mjs deleted file mode 100644 index cab5303ef1..0000000000 --- a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-optional-capacity-token-id.mjs +++ /dev/null @@ -1,209 +0,0 @@ -// Usage: -// DEBUG=true NETWORK=habanero MINT_NEW=true yarn test:e2e:nodejs --filter=test-rli-from-lit-node-client-optional-capacity-token-id.mjs -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; - -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - - // NOTE: In this example, the dApp owner would be both the Capacity Credits NFT delegator and the delegatee (end user) - // for ease of testing. - // ==================== Setup ==================== - - // ==================================================== - // = dApp Owner's Perspetive = - // ==================================================== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - globalThis.LitCI.wallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - const dAppOwnerWallet = globalThis.LitCI.wallet; - - const dAppOwnerWallet_address = globalThis.LitCI.wallet.address; - const dAppOwnerWallet_authSig = globalThis.LitCI.CONTROLLER_AUTHSIG; - const dAppOwnerWallet_pkpPublicKey = globalThis.LitCI.PKP_INFO.publicKey; - - console.log('dAppOwnerWallet_authSig:', dAppOwnerWallet_authSig); - console.log('dAppOwnerWallet_address:', dAppOwnerWallet_address); - console.log('dAppOwnerWallet_pkpPublicKey:', dAppOwnerWallet_pkpPublicKey); - - const delegatedWalletB = new ethers.Wallet( - '0xe1090085b352120867ea7b154ceeee30654903a6c37afa1d5c5bcabc63c96676', - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ); - - const delegatedWalletB_address = delegatedWalletB.address; - - // As a dApp owner, I want to mint a Rate Limit Increase NFT so he who owns or delegated to - // would be able to perform 14400 requests per day - let contractClient = new LitContracts({ - signer: dAppOwnerWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - console.log('dAppOwnerWallet:', dAppOwnerWallet); - - const litNodeClient = new LitNodeClient({ - litNetwork: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - minNodeCount: undefined, - checkNodeAttestation: process.env.CHECK_SEV ?? false, - }); - - await litNodeClient.connect(); - - // we will create an delegation auth sig, which internally we will create - // a recap object, add the resource "lit-ratelimitincrease://{tokenId}" to it, and add it to the siwe - // message. We will then sign the siwe message with the dApp owner's wallet. - const { capacityDelegationAuthSig, litResource } = - await litNodeClient.createCapacityDelegationAuthSig({ - uses: '1', - dAppOwnerWallet: dAppOwnerWallet, - delegateeAddresses: [delegatedWalletB_address], - }); - - console.log('capacityDelegationAuthSig:', capacityDelegationAuthSig); - console.log('litResource:', JSON.stringify(litResource)); - - // ==================================================== - // = As an end user = - // ==================================================== - const endUserContractClient = new LitContracts({ - signer: delegatedWalletB, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await endUserContractClient.connect(); - - let endUserPkpMintRes = - await endUserContractClient.pkpNftContractUtils.write.mint(); - - const endUserPkpInfo = endUserPkpMintRes.pkp; - - console.log('endUserPkpInfo:', endUserPkpInfo); - - // We need to setup a generic siwe auth callback that will be called by the lit-node-client - const endUserControllerAuthNeededCallback = async ({ - resources, - expiration, - uri, - }) => { - console.log('resources:', resources); - console.log('expiration:', expiration); - - const litResource = new LitActionResource('*'); - - const recapObject = - await litNodeClient.generateSessionCapabilityObjectWithWildcards([ - litResource, - ]); - - recapObject.addCapabilityForResource( - litResource, - LitAbility.LitActionExecution - ); - - const verified = recapObject.verifyCapabilitiesForResource( - litResource, - LitAbility.LitActionExecution - ); - - if (!verified) { - throw new Error('Failed to verify capabilities for resource'); - } - - console.log('authCallback verified:', verified); - - let siweMessage = new siwe.SiweMessage({ - domain: 'localhost:3000', - address: delegatedWalletB_address, - statement: 'Some custom statement.', - uri, - version: '1', - chainId: '1', - expirationTime: expiration, - resources, - }); - - siweMessage = recapObject.addToSiweMessage(siweMessage); - console.log('authCallback siwe:', siweMessage); - - const messageToSign = siweMessage.prepareMessage(); - const signature = await delegatedWalletB.signMessage(messageToSign); - - const authSig = { - sig: signature.replace('0x', ''), - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - // address: delegatedWalletB_address, - address: delegatedWalletB_address, - // algo: null, - }; - - console.log('authCallback authSig:', authSig); - - return authSig; - }; - - // - When generating a session sigs, we need to specify the resourceAbilityRequests, which - // is a list of resources and abilities that we want to be able to perform. - // "lit-ratelimitincrease://{tokenId}" that the dApp owner has delegated to us. - // - We also included the capacityDelegationAuthSig that we created earlier, which would be - // added to the capabilities array in the signing template. - let sessionSigs = await litNodeClient.getSessionSigs({ - expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours - chain: 'ethereum', - resourceAbilityRequests: [ - { - resource: new LitActionResource('*'), - ability: LitAbility.LitActionExecution, - }, - ], - authNeededCallback: endUserControllerAuthNeededCallback, - capacityDelegationAuthSig, - }); - - // /web/execute - const res = await litNodeClient.executeJs({ - sessionSigs, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: ethers.utils.arrayify( - ethers.utils.keccak256([1, 2, 3, 4, 5]) - ), - publicKey: endUserPkpInfo.publicKey, - }, - }); - - if (res) { - return success('delegatee able to sign'); - } - - return fail(`Failed to get proof from Recap Session Capability`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-self-delegatee.mjs b/e2e-nodejs/group-rli/test-rli-from-lit-node-client-self-delegatee.mjs deleted file mode 100644 index 4ebd884357..0000000000 --- a/e2e-nodejs/group-rli/test-rli-from-lit-node-client-self-delegatee.mjs +++ /dev/null @@ -1,201 +0,0 @@ -// Usage: DEBUG=true NETWORK=manzano yarn test:e2e:nodejs --filter=test-recap-from-lit -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { - LitAbility, - LitRLIResource, - LitActionResource, -} from '@lit-protocol/auth-helpers'; - -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; - -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - - // NOTE: In this example, the dApp owner would be both the Capacity Credits NFT delegator and the delegatee (end user) - // for ease of testing. - // ==================== Setup ==================== - - // ==================================================== - // = dApp Owner's Perspetive = - // ==================================================== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - globalThis.LitCI.wallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - provider - ); - const dAppOwnerWallet = globalThis.LitCI.wallet; - - const dAppOwnerWallet_address = globalThis.LitCI.wallet.address; - const dAppOwnerWallet_authSig = globalThis.LitCI.CONTROLLER_AUTHSIG; - const dAppOwnerWallet_pkpPublicKey = globalThis.LitCI.PKP_INFO.publicKey; - - console.log('dAppOwnerWallet_authSig:', dAppOwnerWallet_authSig); - console.log('dAppOwnerWallet_address:', dAppOwnerWallet_address); - console.log('dAppOwnerWallet_pkpPublicKey:', dAppOwnerWallet_pkpPublicKey); - - const delegatedWalletB = new ethers.Wallet.createRandom(); - const delegatedWalletB_address = delegatedWalletB.address; - - // As a dApp owner, I want to mint a Rate Limit Increase NFT so he who owns or delegated to - // would be able to perform 14400 requests per day - let contractClient = new LitContracts({ - signer: dAppOwnerWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - const capacityTokenIdStr = '2'; - // const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - // requestsPerDay: 14400, // 10 request per minute - // daysUntilUTCMidnightExpiration: 2, - // }); - - console.log('capacityTokenIdStr:', capacityTokenIdStr); - - console.log('dAppOwnerWallet:', dAppOwnerWallet); - - const litNodeClient = new LitNodeClient({ - litNetwork: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - minNodeCount: undefined, - checkNodeAttestation: process.env.CHECK_SEV ?? false, - }); - - await litNodeClient.connect(); - - // we will create an delegation auth sig, which internally we will create - // a recap object, add the resource "lit-ratelimitincrease://{tokenId}" to it, and add it to the siwe - // message. We will then sign the siwe message with the dApp owner's wallet. - const { capacityDelegationAuthSig, litResource } = - await litNodeClient.createCapacityDelegationAuthSig({ - uses: '1', - dAppOwnerWallet: dAppOwnerWallet, - capacityTokenId: capacityTokenIdStr, - delegateeAddresses: [dAppOwnerWallet_address, delegatedWalletB_address], - }); - - console.log('YY capacityDelegationAuthSig:', capacityDelegationAuthSig); - console.log('litResource:', JSON.stringify(litResource)); - - // ==================================================== - // = As an end user = - // ==================================================== - // We need to setup a generic siwe auth callback that will be called by the lit-node-client - const authNeededCallback = async ({ resources, expiration, uri }) => { - console.log('XX resources:', resources); - console.log('XX expiration:', expiration); - - const litResource = new LitActionResource('*'); - - const recapObject = - await litNodeClient.generateSessionCapabilityObjectWithWildcards([ - litResource, - ]); - - recapObject.addCapabilityForResource( - litResource, - LitAbility.LitActionExecution - ); - - const verified = recapObject.verifyCapabilitiesForResource( - litResource, - LitAbility.LitActionExecution - ); - - if (!verified) { - throw new Error('Failed to verify capabilities for resource'); - } - - console.log('authCallback verified:', verified); - - let siweMessage = new siwe.SiweMessage({ - domain: 'localhost:3000', - address: dAppOwnerWallet_address, - statement: 'Some custom statement.', - uri, - version: '1', - chainId: '1', - expirationTime: expiration, - resources, - }); - - siweMessage = recapObject.addToSiweMessage(siweMessage); - console.log('authCallback siwe:', siweMessage); - - const messageToSign = siweMessage.prepareMessage(); - const signature = await dAppOwnerWallet.signMessage(messageToSign); - - const authSig = { - sig: signature.replace('0x', ''), - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: dAppOwnerWallet_address, - algo: null, - }; - - console.log('authCallback authSig:', authSig); - - return authSig; - }; - - // - When generating a session sigs, we need to specify the resourceAbilityRequests, which - // is a list of resources and abilities that we want to be able to perform. - // "lit-ratelimitincrease://{tokenId}" that the dApp owner has delegated to us. - // - We also included the capacityDelegationAuthSig that we created earlier, which would be - // added to the capabilities array in the signing template. - let sessionSigs = await litNodeClient.getSessionSigs({ - expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours - chain: 'ethereum', - resourceAbilityRequests: [ - { - resource: new LitActionResource('*'), - ability: LitAbility.LitActionExecution, - }, - ], - authNeededCallback, - capacityDelegationAuthSig, - }); - - console.log('XX sessionSigs:', sessionSigs); - - // /web/execute - const res = await litNodeClient.executeJs({ - // authSig: regularAuthSig, - // authSig: sessionSigs['https://64.131.85.108:443'], - sessionSigs, // lit:session:xxx or lit:capability:delegation doesn't URI which is not accepted. - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: ethers.utils.arrayify( - ethers.utils.keccak256([1, 2, 3, 4, 5]) - ), - publicKey: dAppOwnerWallet_pkpPublicKey, - }, - }); - - if (res) { - return success('recap works'); - } - - return fail(`Failed to get proof from Recap Session Capability`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/group-rli/test-rli-pkp-as-delegatee.mjs b/e2e-nodejs/group-rli/test-rli-pkp-as-delegatee.mjs deleted file mode 100644 index 314179a9e0..0000000000 --- a/e2e-nodejs/group-rli/test-rli-pkp-as-delegatee.mjs +++ /dev/null @@ -1,276 +0,0 @@ -// Usage: DEBUG=true NETWORK=habanero MINT_NEW=true yarn test:e2e:nodejs --filter=test-rli-pkp-as-delegatee -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { LitNodeClient } from '@lit-protocol/lit-node-client'; -import { LocalStorage } from 'node-localstorage'; -import { LitAbility, LitPKPResource } from '@lit-protocol/auth-helpers'; -import { AuthMethodType, AuthMethodScope } from '@lit-protocol/constants'; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { ethers } from 'ethers'; -import * as siwe from 'siwe'; -import { LitAuthClient } from '@lit-protocol/lit-auth-client'; - -async function getAuthSig(wallet, litNodeClient) { - const domain = 'localhost'; - const origin = 'https://localhost/login'; - const statement = - 'This is a test statement. You can put anything you want here.'; - - const address = await wallet.getAddress(); - - const nonce = await litNodeClient.getLatestBlockhash(); - - const siweMessage = new siwe.SiweMessage({ - domain, - address, - statement, - uri: origin, - version: '1', - chainId: 1, - nonce, - expirationTime: new Date(Date.now() + 60_000 * 60).toISOString(), - }); - - const messageToSign = siweMessage.prepareMessage(); - - // Sign the message and format the authSig - const signature = await wallet.signMessage(messageToSign); - - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: address, - }; - - return authSig; -} - -// ==================== Story ==================== -// - The dApp owner would be the Capacity Credits delegator -// - The PKP would be the delegatee whom the dApp owner has delegated to -export async function main() { - if (process.env.LOAD_ENV === 'false') { - console.log('❗️ This test cannot be run with LOAD_ENV=false'); - process.exit(); - } - - // ==================== Setup ==================== - const litNodeClient = new LitNodeClient({ - litNetwork: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - minNodeCount: undefined, - checkNodeAttestation: process.env.CHECK_SEV ?? false, - storageProvider: { - provider: new LocalStorage('./storage.test.db'), - }, - }); - - await litNodeClient.connect(); - - // ********************************************************* - // 1. As a dApp Owner, I want to mint a Capacity Credits NFT - // ********************************************************* - - // -- setup dApp owner wallet - const dAppOwnerWallet = new ethers.Wallet( - LITCONFIG.CONTROLLER_PRIVATE_KEY, - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ); - - // -- connect to contract client - let contractClient = new LitContracts({ - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - signer: dAppOwnerWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - }); - - await contractClient.connect(); - - // -- static to test faster - // const capacityTokenIdStr = '2'; - - // -- mint a new Capacity Credits NFT - const { capacityTokenIdStr } = await contractClient.mintCapacityCreditsNFT({ - requestsPerDay: 14400, // 10 request per minute - daysUntilUTCMidnightExpiration: 2, - }); - - console.log('capacityTokenIdStr:', capacityTokenIdStr); - console.log('dAppOwnerWallet:', dAppOwnerWallet); - - // ***************************************************** - // 2. As a second wallet owner, I want to mint a PKP NFT - // ***************************************************** - const secondWallet = new ethers.Wallet( - '0xe1090085b352120867ea7b154ceeee30654903a6c37afa1d5c5bcabc63c96676', - new ethers.providers.JsonRpcProvider(LITCONFIG.CHRONICLE_RPC) - ); - - console.log('secondWallet:', secondWallet.address); - - // -- connect to contract client - let contractClient2 = new LitContracts({ - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - signer: secondWallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - }); - - await contractClient2.connect(); - - const secondWalletControllerAuthSig = await getAuthSig( - secondWallet, - litNodeClient - ); - - // -- scopes - const authMethod = { - authMethodType: AuthMethodType.EthWallet, - accessToken: JSON.stringify(secondWalletControllerAuthSig), - }; - - const mintInfo = await contractClient2.mintWithAuth({ - authMethod: authMethod, - scopes: [ - // AuthMethodScope.NoPermissions, - AuthMethodScope.SignAnything, - ], - }); - - const authId = await LitAuthClient.getAuthIdByAuthMethod(authMethod); - - const scopes = - await contractClient.pkpPermissionsContract.read.getPermittedAuthMethodScopes( - mintInfo.pkp.tokenId, - AuthMethodType.EthWallet, - authId, - 3 - ); - - if (!scopes[1]) { - return fail('signAnythingScope is not true'); - } - - const secondWalletPKPInfo = { - tokenId: mintInfo.pkp.tokenId, - publicKey: `0x${mintInfo.pkp.publicKey}`, - ethAddress: mintInfo.pkp.ethAddress, - }; - - console.log('secondWalletPKPInfo', secondWalletPKPInfo); - - // *********************************************************************** - // 3. As a dApp owner, I want to create a Capacity Delegation AuthSig - // that delegates the Capacity Credits NFT to the PKP NFT so that the - // PKP NFT can benefit from the Capacity Credits NFT's rate limit increase - // when signing. - // ************************************************************************ - - const { capacityDelegationAuthSig } = - await litNodeClient.createCapacityDelegationAuthSig({ - uses: '1', - dAppOwnerWallet: dAppOwnerWallet, - capacityTokenId: capacityTokenIdStr, - delegateeAddresses: [secondWalletPKPInfo.ethAddress], - }); - - console.log('capacityDelegationAuthSig:', capacityDelegationAuthSig); - - // *************************************************************** - // 4. As a PKP, I want to benefit from the Capacity Credits NFT's - // rate limit increase when signing. - // *************************************************************** - - // -- define the authMethod of the delegatee's controller auth sig (second wallet controller auth sig) - const secondWalletControllerAuthMethod = { - authMethodType: 1, - accessToken: JSON.stringify(secondWalletControllerAuthSig), - }; - - const pkpAuthNeededCallback = async ({ - expiration, - resources, - resourceAbilityRequests, - }) => { - // -- validate - if (!expiration) { - throw new Error('expiration is required'); - } - - if (!resources) { - throw new Error('resources is required'); - } - - if (!resourceAbilityRequests) { - throw new Error('resourceAbilityRequests is required'); - } - - const response = await litNodeClient.signSessionKey({ - statement: 'Some custom statement.', - authMethods: [secondWalletControllerAuthMethod], - pkpPublicKey: secondWalletPKPInfo.publicKey, - expiration: expiration, - resources: resources, - chainId: 1, - - // optional (this would use normal siwe lib, without it, it would use siwe-recap) - resourceAbilityRequests: resourceAbilityRequests, - }); - - console.log('response:', response); - - return response.authSig; - }; - - // *************************************************************** - // 5. As a PKP, I want to get the session sigs - // *************************************************************** - const pkpSessionSigs = await litNodeClient.getSessionSigs({ - pkpPublicKey: secondWalletPKPInfo.publicKey, - expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours - chain: 'ethereum', - resourceAbilityRequests: [ - { - resource: new LitPKPResource('*'), - ability: LitAbility.PKPSigning, - }, - ], - authNeededCallback: pkpAuthNeededCallback, - capacityDelegationAuthSig, - }); - - console.log('pkpSessionSigs:', pkpSessionSigs); - - // *************************************************************** - // 7. Finally sign the message using the PKP's PKP - // *************************************************************** - // const pkpsPKPPublicKey = ''; - - // -- Mint a PKP using a PKP - const res = await litNodeClient.executeJs({ - sessionSigs: pkpSessionSigs, - code: `(async () => { - const sigShare = await LitActions.signEcdsa({ - toSign: dataToSign, - publicKey, - sigName: "sig", - }); - })();`, - authMethods: [], - jsParams: { - dataToSign: ethers.utils.arrayify( - ethers.utils.keccak256([1, 2, 3, 4, 5]) - ), - publicKey: secondWalletPKPInfo.publicKey, - }, - }); - - if (res) { - return success('pkp able to sign as a delegatee'); - } - - return fail(`Failed to get proof from Recap Session Capability`); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/e2e-nodejs/index.mjs b/e2e-nodejs/index.mjs deleted file mode 100644 index e76f1508ef..0000000000 --- a/e2e-nodejs/index.mjs +++ /dev/null @@ -1,196 +0,0 @@ -// runner.mjs -import fs from 'fs'; -import { fileURLToPath } from 'url'; -import path from 'path'; -import { formatNxLikeLine, greenLog } from '../tools/scripts/utils.mjs'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const ROOT_DIR = path.resolve(__dirname, '../'); -const DIR = ROOT_DIR + '/e2e-nodejs/'; -const ENV_LOADER_PATH = path.resolve(__dirname, 'loader.mjs'); - -const IGNORE_LIST = [ - 'index.mjs', - 'template.mjs', - '00-setup.mjs', - 'loader.mjs', - 'README.md', -]; -const IGNORE_DIRS = ['0_manual-tests']; -/** - * Function to get all files from the directory excluding 'index' - * @param {string} dir - The directory path - * @returns {Array} - An array of file names - */ -const getFilesFromDir = (dir) => { - let results = []; - const list = fs.readdirSync(dir); - - list.forEach((file) => { - const filePath = path.join(dir, file); - const stat = fs.statSync(filePath); - if (stat && stat.isDirectory()) { - /* Recurse into a subdirectory */ - results = results.concat(getFilesFromDir(filePath)); - } else { - /* Is a file */ - results.push(filePath); - } - }); - - return results.filter((file) => { - if (IGNORE_LIST.includes(path.basename(file))) { - return false; - } - return true; - }); -}; - -async function main() { - greenLog(` - 💡 Usage: yarn test:e2e:node - - 🌍 ENVs: - DEBUG=true (Enables debug mode) - NETOWRK= (Choose your network) - CHECK_SEV=true (enable sev attestation checks) - MINT_NEW=true (mint new pkp resources for test run) - REAL_TX=true yarn (Enables real tx that costs gas) - E2E_CACHE=true (Use cached config) - LOAD_ENV=false (Loads environment context) - - 🚩 Flags: - --filter= (Filters files by keyword) - --group= (Group is directory prefix, e.g., --group=pkp-ethers uses group-pkp-ethers)`); - - const mode = process.argv.includes('--parallel') ? 'parallel' : 'async'; - const args = process.argv.slice(2); - const filesArg = args.find((arg) => arg.startsWith('--filter')); - const groupArgs = args.filter((arg) => arg.startsWith('--group')); - - let filesValue = filesArg ? filesArg.split('=')[1] : null; - - let groupValues = groupArgs - ? groupArgs.map((group) => group.split('=')[1]) - : []; - - filesValue = filesValue ? filesValue.split(',') : null; - - let files = getFilesFromDir(DIR).filter((file) => { - return filesValue ? filesValue.some((value) => file.includes(value)) : true; - }); - - if (groupValues.length > 0) { - let filteredFiles = []; - for (const groupValue of groupValues) { - console.log('group ', groupValue); - filteredFiles = filteredFiles.concat( - files.filter((file) => file.includes(`group-${groupValue}`)) - ); - } - files = filteredFiles; - } - - if (files.length <= 0) { - console.log('❌ No files to run'); - return; - } - - console.log(); - console.log(`${formatNxLikeLine('test:e2e:node', files.length)}`); - files.forEach((file) => { - greenLog(` - ${file}`, true); - }); - - console.log( - '\n --------------------------------------------------------------------------------' - ); - - if (groupValues) { - console.log(`\n🚀 Running tests in group: ${groupValues}`); - } - let currentGroup = null; - let errorCounter = 0; - let logs = []; - - // load environment context and init global state - try { - await import('./loader.mjs'); - } catch (e) { - errorCounter += 1; - logs.push( - `------------------- -- [${errorCounter}] Error happened in environment loading, see below for details 👇 \n${e}` - ); - console.log(e); - } - - // -- async mode - if (mode === 'async') { - for (const file of files) { - if (IGNORE_DIRS.includes(file)) { - return; - } - - const group = file.split('/')[file.split('/').length - 2]; // Assuming group is the second last part of the file path - - // skip the for loop if group is in IGNORE_DIRS - if (IGNORE_DIRS.includes(group)) { - continue; - } - - if (group !== currentGroup) { - console.log(`\nRunning tests in ${group}`); - currentGroup = group; - } - - try { - await import(file); - } catch (e) { - errorCounter += 1; - logs.push( - `------------------- -- [${errorCounter}] Error happened in ${file}, see below for details 👇 \n${e}` - ); - console.log(e); - } - } - } - - if (mode === 'parallel') { - const promises = files.map(async (file) => { - const group = file.split('/')[file.split('/').length - 2]; - - if (group !== currentGroup) { - console.log(`\nRunning tests in ${group}`); - currentGroup = group; - } - - await import(file); - }); - - try { - await Promise.all(promises); - } catch (error) { - console.error('Parallel Execution Error:', error); - } - } - - console.log(); - - if (errorCounter > 0) { - console.log(`❌ ${errorCounter} test(s) failed`); - logs.forEach((log) => { - console.log(log); - }); - - process.exit(1); - } - process.exit(0); -} - -main().catch((error) => { - console.error('Error:', error); -}); diff --git a/e2e-nodejs/loader.mjs b/e2e-nodejs/loader.mjs deleted file mode 100644 index fecfaca878..0000000000 --- a/e2e-nodejs/loader.mjs +++ /dev/null @@ -1,160 +0,0 @@ -import LITCONFIG from '../lit.config.json' assert { type: 'json' }; -import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { uint8arrayFromString } from '@lit-protocol/uint8arrays'; -import { BigNumber, ethers } from 'ethers'; -import * as siwe from 'siwe'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import fs from 'fs'; - -// ==================== ENV Loading ==================== -const network = process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork; -const debug = process.env.DEBUG === 'true' ? true : false; -const checkSevAttestation = process.env.CHECK_SEV === 'true' ?? false; -const mintNew = process.env.MINT_NEW === 'true' ? true : false; -const useCache = process.env.E2E_CACHE === 'true' ? true : false; -const loadEnv = process.env.LOAD_ENV === 'true' ? false : true; // default to true - -if (loadEnv) { - if (mintNew && useCache) { - console.log('cannot mint new and use cache at the same time'); - process.exit(); - } - - // ==================== SIWE Gen ==================== - const provider = new ethers.providers.JsonRpcProvider( - LITCONFIG.CHRONICLE_RPC - ); - - const wallet = new ethers.Wallet(LITCONFIG.CONTROLLER_PRIVATE_KEY, provider); - const address = ethers.utils.getAddress(await wallet.getAddress()); - - // Craft the SIWE message - const litNodeClient = new LitJsSdk.LitNodeClient({ - litNetwork: network, - debug, - }); - - await litNodeClient.connect(); - - let nonce = await litNodeClient.getLatestBlockhash(); - console.log('GENERATED NONCE: ', nonce); - - const domain = 'localhost'; - const origin = 'https://localhost/login'; - const statement = - 'This is a test statement. You can put anything you want here.'; - const siweMessage = new siwe.SiweMessage({ - domain, - address: address, - statement, - uri: origin, - version: '1', - chainId: 1, - nonce, - expirationTime: new Date(Date.now() + 60_000 * 60).toISOString(), - }); - const messageToSign = siweMessage.prepareMessage(); - - // Sign the message and format the authSig - const signature = await wallet.signMessage(messageToSign); - - const authSig = { - sig: signature, - derivedVia: 'web3.eth.personal.sign', - signedMessage: messageToSign, - address: address, - }; - - // ==================== Global Vars ==================== - if (useCache) { - globalThis.LitCI = LITCONFIG.CACHE; - } else { - globalThis.LitCI = {}; - globalThis.LitCI.wallet = wallet; - globalThis.LitCI.network = network; - globalThis.LitCI.debug = debug; - globalThis.LitCI.sevAttestation = checkSevAttestation; - globalThis.LitCI.CONTROLLER_AUTHSIG = authSig; - globalThis.LitCI.CONTROLLER_WALLET = wallet; - - globalThis.LitCI.PKP_INFO = {}; - globalThis.LitCI.PKP_INFO.publicKey = LITCONFIG.PKP_PUBKEY; - } - - if (mintNew) { - let contractClient = new LitContracts({ - signer: wallet, - debug: process.env.DEBUG === 'true' ?? LITCONFIG.TEST_ENV.debug, - network: process.env.NETWORK ?? LITCONFIG.TEST_ENV.litNetwork, - }); - - await contractClient.connect(); - - // -- mint a new Capacity Credits NFT - // we only need to do this because if the pkp controller has the capactiy - // credits NFT, then we should be able to use it without delegating it - // to the pkp - const ccNFT = await contractClient.mintCapacityCreditsNFT({ - requestsPerDay: 14400, - daysUntilUTCMidnightExpiration: 2, - }); - - console.log('ccNFT:', ccNFT); - - let res = await contractClient.pkpNftContractUtils.write.mint(); - - globalThis.LitCI.PKP_INFO = res.pkp; - - const mintCost = await contractClient.pkpNftContract.read.mintCost(); - let authMethodId = ethers.utils.keccak256( - uint8arrayFromString(`${authSig.address}:lit`) - ); - res = - await contractClient.pkpHelperContract.write.mintNextAndAddAuthMethods( - 2, - [1], - [authMethodId], - [BigNumber.from(0)], - [[BigNumber.from(1)]], - true, - true, - { - value: mintCost, - } - ); - - let tx = await res.wait(); - let tokenId = tx.events ? tx.events[0].topics[1] : tx.logs[0].topics[1]; - let pubkeyWithAuthMethod = - await contractClient.pkpNftContract.read.getPubkey(tokenId); - let ethAddr = ethers.utils.computeAddress(pubkeyWithAuthMethod); - - globalThis.LitCI.AUTH_METHOD_PKP_INFO = {}; - globalThis.LitCI.AUTH_METHOD_PKP_INFO.publicKey = - pubkeyWithAuthMethod.slice(2); - globalThis.LitCI.AUTH_METHOD_PKP_INFO.ethAddress = ethAddr; - globalThis.LitCI.AUTH_METHOD_PKP_INFO.authMethod = { - authMethodId, - authMethodType: 1, - }; - } - - console.log('environment Arguments'); - console.log(globalThis.LitCI); - - // -- write to lit.config.json - if (!useCache) { - let litConfigJson; - - try { - const file = 'lit.config.json'; - litConfigJson = JSON.parse(fs.readFileSync(file, 'utf8')); - litConfigJson.CACHE = globalThis.LitCI; - delete litConfigJson.CACHE.wallet; - fs.writeFileSync(file, JSON.stringify(litConfigJson, null, 2), 'utf8'); - } catch (e) { - console.log('could not parse or write to lit.config.json'); - console.log(e); - } - } -} diff --git a/e2e-nodejs/polyfills.mjs b/e2e-nodejs/polyfills.mjs deleted file mode 100644 index 5031ccc4fd..0000000000 --- a/e2e-nodejs/polyfills.mjs +++ /dev/null @@ -1,2 +0,0 @@ -import crypto from 'crypto'; -export default crypto; diff --git a/e2e-nodejs/template.mjs b/e2e-nodejs/template.mjs deleted file mode 100644 index 4418dfac0c..0000000000 --- a/e2e-nodejs/template.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import path from 'path'; -import { success, fail, testThis } from '../../tools/scripts/utils.mjs'; -import LITCONFIG from '../../lit.config.json' assert { type: 'json' }; -import { client } from '../00-setup.mjs'; - -export async function main() { - // ==================== Setup ==================== - // const xxx = 'yyy'; - // ==================== Test Logic ==================== - // const res = await client.executeJs({ - // authSig: LITCONFIG.CONTROLLER_AUTHSIG, - // code: `(async () => { - // console.log('hello world') - // })();`, - // jsParams: { - // publicKey: LITCONFIG.PKP_PUBKEY, - // }, - // }); - // ==================== Post-Validation ==================== - // if (!res.logs.includes('hello world')) { - // return fail('lit action client should be ready'); - // } - // if (!res.success) { - // return fail('response should be success'); - // } - // ==================== Success ==================== - // return success('Lit Action should log "hello world"'); -} - -await testThis({ name: path.basename(import.meta.url), fn: main }); diff --git a/package.json b/package.json index d04464133b..53283d07ce 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,6 @@ "test:ci": "nx affected --target=test --all --code-coverage", "test:e2e": "yarn tools --test --e2e run-html-and-test", "test:e2e:web": "yarn test:e2e", - "test:e2e:node": "node --no-warnings ./e2e-nodejs/index.mjs", - "test:e2e:nodejs": "yarn test:e2e:node", "test:local": "node ./local-tests/build.mjs && node ./local-tests/build/test.mjs", "test:unit": "yarn test:packages", "test:custom": "yarn tools --test --custom", diff --git a/tools/scripts/tools.mjs b/tools/scripts/tools.mjs index 00e02643a7..09875435f6 100644 --- a/tools/scripts/tools.mjs +++ b/tools/scripts/tools.mjs @@ -2,8 +2,6 @@ import { exit } from 'process'; import { asyncForEach, childRunCommand, - customSort, - findArg, findImportsFromDir, findStrFromDir, getArgs, @@ -21,7 +19,6 @@ import { spawnListener, writeFile, writeJsonFile, - yellowLog, checkEmptyDirectories, } from './utils.mjs'; import fs from 'fs'; @@ -258,16 +255,11 @@ async function testFunc() { } if (TEST_TYPE === '--unit') { - // Run the nx run-many command with the --projects flag set to the project names - const nx = spawn( - 'nx', - ['run-many', '--target=test'], - { - stdio: 'inherit', // This maintains the log output color - shell: true, - } - ); + const nx = spawn('nx', ['run-many', '--target=test'], { + stdio: 'inherit', // This maintains the log output color + shell: true, + }); // Handle errors nx.on('error', (error) => { @@ -1086,7 +1078,7 @@ async function setupLocalDevFunc() { const distPackageJson = await readJsonFile(distPackageJsonPath); packageJson.main = prefixPathWithDir(distPackageJson.main, 'dist'); - packageJson.typings = "./dist/src/index.d.ts"; + packageJson.typings = './dist/src/index.d.ts'; greenLog(`Updating ${packageJsonPath}...`); greenLog(`packageJson.main: ${packageJson.main}`); @@ -1329,7 +1321,6 @@ async function validateDependencyVersions() { ` ❗️ Before publishing, make sure you have tested the build! - yarn test:unit | run unit tests - - yarn test:e2e:node | run e2e tests on nodejs (v0) - yarn test:local | run e2e tests on nodejs `, true @@ -1338,8 +1329,7 @@ async function validateDependencyVersions() { console.log(` Note: for e2e nodejs test, you can use the following options: ------------------------------------------------------------- - --filter flag to filter tests (eg. yarn test:e2e:node --filter=1-sig) - --group flag to test a specific group (yarn test:e2e:node --group=lit-actions) + --filter flag to filter tests (eg. yarn test:local --filter=Encryption) `); } process.exit(0); diff --git a/tools/scripts/utils.mjs b/tools/scripts/utils.mjs index 3bf53d1e0b..1f7c976bd7 100644 --- a/tools/scripts/utils.mjs +++ b/tools/scripts/utils.mjs @@ -471,7 +471,6 @@ export const replaceFileContent = async (path, oldContent, newContent) => { * 2. prefixPathWithDir('src/index.js', 'components') => './components/src/index.js' */ export const prefixPathWithDir = (path, dirName) => { - if (path?.slice(0, 2) === './') { return `./${dirName}/${path.slice(2)}`; } else { @@ -611,74 +610,6 @@ export const log = Object.assign( }, } ); -/** - * testThis - Runs a test and logs the result - * - * This test relies on the `success` and `fail` functions to either return - * 200 or 500 status code. If neither is returned, the test it not correctly implemented. - * - * It DOES not process.exit() on failure, this event is handled by the caller, in this case - * in the test runner script at ./e2e-nodejs/index.mjs - * - * if (errorCounter > 0) { - console.log(`❌ ${errorCounter} test(s) failed`); - process.exit(1); - } - process.exit(0); - * - * This ensures that all tests are run and the user is notified of all failures, and could be integrated - * with a CI/CD pipeline. - * @param {*} test - * @returns - */ -export const testThis = async (test) => { - // calculate the time it takes to run the test - const start = Date.now(); - - const { status, message } = await test.fn(); - - let errorIsThrown = false; - - try { - const end = Date.now(); - - const time = end - start; - - if (status === 200) { - log.green(`\t${message} (${time}ms)`); - return true; - } else { - const _errorMsg = `\t(FAILED 200) ${message} (${time}ms) | ${test.name}`; - errorIsThrown = true; - log.red(_errorMsg); - throw new Error(_errorMsg); - } - } catch (e) { - if (!errorIsThrown) { - const end = Date.now(); - const time = end - start; - const _errorMsg = `\t(FAILED 500) ${message} (${time}ms) | ${test.name}`; - log.red(_errorMsg); - throw new Error(_errorMsg); - } - } -}; - -/** - * testThese - Runs a list of tests using testThis - * Check testThis for more details - * - * @param {*} tests - * - * @returns - */ -export const testThese = async (tests) => { - console.log(`Running ${tests.length} tests...\n`); - - for (const t of tests) { - await testThis(t); - } -}; export function findArg(args, flag) { const flagIndex = args.findIndex((arg) => arg.startsWith(flag)); diff --git a/yarn.lock b/yarn.lock index 0bd1a2f24f..8f293adb08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4867,6 +4867,15 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@spruceid/siwe-parser@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@spruceid/siwe-parser/-/siwe-parser-2.0.0.tgz#fb316b9115e9116bac528c5cbfed18787119bede" + integrity sha512-zXlPBRKaT9ecxhhLQqn/StAWlXvQBlFDFnIAlM7ceMVx/1NVZZ65GdW9A28tYGbhpesYxNYpsqegGsBcrWuASg== + dependencies: + apg-js "^4.1.1" + uri-js "^4.4.1" + valid-url "^1.0.9" + "@spruceid/siwe-parser@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@spruceid/siwe-parser/-/siwe-parser-2.1.2.tgz#3e13e7d3ac0bfdaf109a07342590eb21daee2fc3" @@ -4877,15 +4886,6 @@ uri-js "^4.4.1" valid-url "^1.0.9" -"@spruceid/siwe-parser@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@spruceid/siwe-parser/-/siwe-parser-2.0.0.tgz#fb316b9115e9116bac528c5cbfed18787119bede" - integrity sha512-zXlPBRKaT9ecxhhLQqn/StAWlXvQBlFDFnIAlM7ceMVx/1NVZZ65GdW9A28tYGbhpesYxNYpsqegGsBcrWuASg== - dependencies: - apg-js "^4.1.1" - uri-js "^4.4.1" - valid-url "^1.0.9" - "@stablelib/aead@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3" @@ -7027,6 +7027,11 @@ apache-md5@^1.0.6: resolved "https://registry.yarnpkg.com/apache-md5/-/apache-md5-1.1.8.tgz#ea79c6feb03abfed42b2830dde06f75df5e3bbd9" integrity sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA== +apg-js@^4.1.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/apg-js/-/apg-js-4.4.0.tgz#09dcecab0731fbde233b9f2352fdd2d07e56b2cf" + integrity sha512-fefmXFknJmtgtNEXfPwZKYkMFX4Fyeyz+fNF6JWp87biGOPslJbCBVU158zvKRZfHBKnJDy8CMM40oLFGkXT8Q== + apg-js@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/apg-js/-/apg-js-4.3.0.tgz#2c55d3f1aa6b90be5d3c6539f346cf2c726702c3" From cd6f5f4e16e9c470cf7e142c080c9e0ebac2e856 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 16:46:34 +0100 Subject: [PATCH 161/263] feat: update CI --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09ba122ff2..6c589c024d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: - master - staging/** - feat/** + - feature/** jobs: master: runs-on: ubuntu-latest From 499ced7d030560bab696fc4cda489539a0079144 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 16:48:33 +0100 Subject: [PATCH 162/263] fix(CI): update command --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c589c024d..d9c3cc49c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,4 @@ jobs: run: yarn build - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: NETWORK=cayenne yarn test:local --filtertestUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning, - testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs, - testEthAuthSigToEncryptDecryptString \ No newline at end of file + run: NETWORK=cayenne && yarn test:local --filtertestUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString From fb5bf8f65beda4b8043768af2285bba704a9b757 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 16:51:53 +0100 Subject: [PATCH 163/263] fix(CI): update env --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9c3cc49c4..85349c9b44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,6 @@ jobs: timeout-minutes: 30 env: NETWORK: cayenne - MINT_NEW: true DEBUG: true steps: - name: Checkout repo @@ -47,7 +46,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: '19' + node-version: '20' - name: Install project dependencies run: yarn install - name: Build packages @@ -55,4 +54,4 @@ jobs: run: yarn build - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: NETWORK=cayenne && yarn test:local --filtertestUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString + run: yarn test:local --filtertestUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString From 2c42ca622b1c58244cdffd7f7cea0eef4b130774 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 16:56:45 +0100 Subject: [PATCH 164/263] fix(CI): add `networkContext.json` back for CI --- .gitignore | 2 +- local-tests/setup/networkContext.json | 11370 ++++++++++++++++++++++++ 2 files changed, 11371 insertions(+), 1 deletion(-) create mode 100644 local-tests/setup/networkContext.json diff --git a/.gitignore b/.gitignore index 2eb071aa86..d8e5b157ab 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,4 @@ storage.test.db .yalc local-tests/build -local-tests/setup/networkContext.json \ No newline at end of file +# local-tests/setup/networkContext.json \ No newline at end of file diff --git a/local-tests/setup/networkContext.json b/local-tests/setup/networkContext.json new file mode 100644 index 0000000000..aabf963710 --- /dev/null +++ b/local-tests/setup/networkContext.json @@ -0,0 +1,11370 @@ +{ + "Allowlist": { + "address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "ItemAllowed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "ItemNotAllowed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "addAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "allowAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "allowedItems", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "isAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "removeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_allowAll", + "type": "bool" + } + ], + "name": "setAllowAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "setAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + } + ], + "name": "setNotAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "Allowlist" + }, + "LITToken": { + "address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidShortString", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "str", + "type": "string" + } + ], + "name": "StringTooLong", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "delegator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "fromDelegate", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "toDelegate", + "type": "address" + } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousBalance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBalance", + "type": "uint256" + } + ], + "name": "DelegateVotesChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CLOCK_MODE", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint32", + "name": "pos", + "type": "uint32" + } + ], + "name": "checkpoints", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "fromBlock", + "type": "uint32" + }, + { + "internalType": "uint224", + "name": "votes", + "type": "uint224" + } + ], + "internalType": "struct ERC20Votes.Checkpoint", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "clock", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + } + ], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "delegateBySig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "delegates", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "timepoint", + "type": "uint256" + } + ], + "name": "getPastTotalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timepoint", + "type": "uint256" + } + ], + "name": "getPastVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "numCheckpoints", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "LITToken" + }, + "Multisender": { + "address": "0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_recipients", + "type": "address[]" + } + ], + "name": "sendEth", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_recipients", + "type": "address[]" + }, + { + "internalType": "address", + "name": "tokenContract", + "type": "address" + } + ], + "name": "sendTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenContract", + "type": "address" + } + ], + "name": "withdrawTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "Multisender" + }, + "PKPHelper": { + "address": "0x21dF544947ba3E8b3c32561399E88B52Dc8b2823", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_resolver", + "type": "address" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "_env", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "internalType": "struct LibPKPNFTStorage.ClaimMaterial", + "name": "claimMaterial", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "permittedIpfsCIDs", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedIpfsCIDScopes", + "type": "uint256[][]" + }, + { + "internalType": "address[]", + "name": "permittedAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAddressScopes", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "internalType": "struct PKPHelper.AuthMethodData", + "name": "authMethodData", + "type": "tuple" + } + ], + "name": "claimAndMintNextAndAddAuthMethods", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "internalType": "struct LibPKPNFTStorage.ClaimMaterial", + "name": "claimMaterial", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "permittedIpfsCIDs", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedIpfsCIDScopes", + "type": "uint256[][]" + }, + { + "internalType": "address[]", + "name": "permittedAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAddressScopes", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "internalType": "struct PKPHelper.AuthMethodData", + "name": "authMethodData", + "type": "tuple" + } + ], + "name": "claimAndMintNextAndAddAuthMethodsWithTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "contract ContractResolver", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "env", + "outputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDomainWalletRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPKPNftMetdataAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpPermissionsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "name": "mintNextAndAddAuthMethods", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "permittedIpfsCIDs", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedIpfsCIDScopes", + "type": "uint256[][]" + }, + { + "internalType": "address[]", + "name": "permittedAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAddressScopes", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "name": "mintNextAndAddAuthMethodsWithTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypes", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIds", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeys", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopes", + "type": "uint256[][]" + }, + { + "internalType": "string[]", + "name": "nftMetadata", + "type": "string[]" + }, + { + "internalType": "bool", + "name": "addPkpEthAddressAsPermittedAddress", + "type": "bool" + }, + { + "internalType": "bool", + "name": "sendPkpToItself", + "type": "bool" + } + ], + "name": "mintNextAndAddDomainWalletMetadata", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "removePkpMetadata", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string[]", + "name": "nftMetadata", + "type": "string[]" + } + ], + "name": "setPkpMetadata", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "PKPHelper" + }, + "PKPNFT": { + "address": "0xf5059a5D33d5853360D16C683c16e67980206f36", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "FreeMintSignerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMintCost", + "type": "uint256" + } + ], + "name": "MintCostSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + } + ], + "name": "PKPMinted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrew", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "name": "claimAndMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "freeMintSigner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getEthAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNextDerivedKeyId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftMetadataAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpPermissionsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRouterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mintCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + } + ], + "name": "mintGrantAndBurnNext", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "name": "mintNext", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "prefixed", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "redeemedFreeMintIds", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "setFreeMintSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMintCost", + "type": "uint256" + } + ], + "name": "setMintCost", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "PKPNFT" + }, + "PKPNFTMetadata": { + "address": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_resolver", + "type": "address" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "_env", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "buffer", + "type": "bytes" + } + ], + "name": "bytesToHex", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "contract ContractResolver", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "env", + "outputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "removeProfileForPkp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "removeUrlForPKP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "imgUrl", + "type": "string" + } + ], + "name": "setProfileForPKP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + } + ], + "name": "setUrlForPKP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pubKey", + "type": "bytes" + }, + { + "internalType": "address", + "name": "ethAddress", + "type": "address" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "PKPNFTMetadata" + }, + "PKPPermissions": { + "address": "0x4C4a2f8c81640e47606d3fd77B353E87Ba015584", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "userPubkey", + "type": "bytes" + } + ], + "name": "PermittedAuthMethodAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "PermittedAuthMethodRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "PermittedAuthMethodScopeAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "PermittedAuthMethodScopeRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "root", + "type": "bytes32" + } + ], + "name": "RootHashUpdated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "scopes", + "type": "uint256[]" + } + ], + "name": "addPermittedAction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "scopes", + "type": "uint256[]" + } + ], + "name": "addPermittedAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "userPubkey", + "type": "bytes" + } + ], + "internalType": "struct LibPKPPermissionsStorage.AuthMethod", + "name": "authMethod", + "type": "tuple" + }, + { + "internalType": "uint256[]", + "name": "scopes", + "type": "uint256[]" + } + ], + "name": "addPermittedAuthMethod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "addPermittedAuthMethodScope", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypesToAdd", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIdsToAdd", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodPubkeysToAdd", + "type": "bytes[]" + }, + { + "internalType": "uint256[][]", + "name": "permittedAuthMethodScopesToAdd", + "type": "uint256[][]" + }, + { + "internalType": "uint256[]", + "name": "permittedAuthMethodTypesToRemove", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "permittedAuthMethodIdsToRemove", + "type": "bytes[]" + } + ], + "name": "batchAddRemoveAuthMethods", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "getAuthMethodId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getEthAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPermittedActions", + "outputs": [ + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPermittedAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "maxScopeId", + "type": "uint256" + } + ], + "name": "getPermittedAuthMethodScopes", + "outputs": [ + { + "internalType": "bool[]", + "name": "", + "type": "bool[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPermittedAuthMethods", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "userPubkey", + "type": "bytes" + } + ], + "internalType": "struct LibPKPPermissionsStorage.AuthMethod[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRouterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "getTokenIdsForAuthMethod", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "getUserPubkeyForAuthMethod", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + } + ], + "name": "isPermittedAction", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "isPermittedAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "isPermittedAuthMethod", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "isPermittedAuthMethodScopePresent", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ipfsCID", + "type": "bytes" + } + ], + "name": "removePermittedAction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "removePermittedAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + } + ], + "name": "removePermittedAuthMethod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "authMethodType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "id", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "scopeId", + "type": "uint256" + } + ], + "name": "removePermittedAuthMethodScope", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "root", + "type": "bytes32" + } + ], + "name": "setRootHash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "leaf", + "type": "bytes32" + } + ], + "name": "verifyState", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + }, + { + "internalType": "bool[]", + "name": "proofFlags", + "type": "bool[]" + }, + { + "internalType": "bytes32[]", + "name": "leaves", + "type": "bytes32[]" + } + ], + "name": "verifyStates", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "PKPPermissions" + }, + "PubkeyRouter": { + "address": "0x1291Be112d480055DaFd8a610b7d1e203891C274", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ContractResolverAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "PubkeyRoutingDataSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct IPubkeyRouter.RootKey", + "name": "rootKey", + "type": "tuple" + } + ], + "name": "RootKeySet", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + } + ], + "name": "adminResetRootKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + } + ], + "internalType": "struct IPubkeyRouter.Signature[]", + "name": "signatures", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "signedMessage", + "type": "bytes" + }, + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + } + ], + "name": "checkNodeSignatures", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + } + ], + "name": "deriveEthAddressFromPubkey", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "ethAddress", + "type": "address" + } + ], + "name": "ethAddressToPkpId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "getDerivedPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getEthAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPkpNftAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + } + ], + "name": "getRootKeys", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "internalType": "struct IPubkeyRouter.RootKey[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getRoutingData", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "internalType": "struct LibPubkeyRouterStorage.PubkeyRoutingData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "isRouted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "pubkeys", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "internalType": "struct LibPubkeyRouterStorage.PubkeyRoutingData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "setRoutingData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "address", + "name": "stakingContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "derivedKeyId", + "type": "bytes32" + } + ], + "name": "setRoutingDataAsAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "keyType", + "type": "uint256" + } + ], + "internalType": "struct IPubkeyRouter.RootKey[]", + "name": "newRootKeys", + "type": "tuple[]" + } + ], + "name": "voteForRootKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "PubkeyRouter" + }, + "RateLimitNFT": { + "address": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newAdditionalRequestsPerKilosecondCost", + "type": "uint256" + } + ], + "name": "AdditionalRequestsPerKilosecondCostSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "FreeMintSignerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newFreeRequestsPerRateLimitWindow", + "type": "uint256" + } + ], + "name": "FreeRequestsPerRateLimitWindowSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newRLIHolderRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "RLIHolderRateLimitWindowSecondsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "RateLimitWindowSecondsSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrew", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sVal", + "type": "bytes32" + } + ], + "name": "freeMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newAdditionalRequestsPerKilosecondCost", + "type": "uint256" + } + ], + "name": "setAdditionalRequestsPerKilosecondCost", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newFreeMintSigner", + "type": "address" + } + ], + "name": "setFreeMintSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newFreeRequestsPerRateLimitWindow", + "type": "uint256" + } + ], + "name": "setFreeRequestsPerRateLimitWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaxExpirationSeconds", + "type": "uint256" + } + ], + "name": "setMaxExpirationSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaxRequestsPerKilosecond", + "type": "uint256" + } + ], + "name": "setMaxRequestsPerKilosecond", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newRLIHolderRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "setRLIHolderRateLimitWindowSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newRateLimitWindowSeconds", + "type": "uint256" + } + ], + "name": "setRateLimitWindowSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "RLIHolderRateLimitWindowSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "additionalRequestsPerKilosecondCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "calculateCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "payingAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "calculateRequestsPerKilosecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "capacity", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "internalType": "struct LibRateLimitNFTStorage.RateLimit", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestedRequestsPerKilosecond", + "type": "uint256" + } + ], + "name": "checkBelowMaxRequestsPerKilosecond", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentSoldRequestsPerKilosecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultRateLimitWindowSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestsPerKilosecond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sVal", + "type": "bytes32" + } + ], + "name": "freeMintSigTest", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "freeMintSigner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "freeRequestsPerRateLimitWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "isExpired", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxExpirationSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxRequestsPerKilosecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "prefixed", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "redeemedFreeMints", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokenIdCounter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenSVG", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expiresAt", + "type": "uint256" + } + ], + "name": "totalSoldRequestsPerKilosecondByExpirationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "RateLimitNFT" + }, + "Staking": { + "address": "0xc5a5C42992dECbae36851359345FE25997F5C42d", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "ActiveValidatorsCannotLeave", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "inputs": [], + "name": "CannotKickBelowCurrentValidatorThreshold", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingAddress", + "type": "address" + } + ], + "name": "CannotRejoinUntilNextEpochBecauseKicked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "CannotReuseCommsKeys", + "type": "error" + }, + { + "inputs": [], + "name": "CannotStakeZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "CannotVoteTwice", + "type": "error" + }, + { + "inputs": [], + "name": "CannotWithdrawZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + } + ], + "name": "CouldNotMapNodeAddressToStakerAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInActiveOrUnlockedOrPausedState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInActiveOrUnlockedState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInNextValidatorSetLockedOrReadyForNextEpochOrRestoreState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInNextValidatorSetLockedOrReadyForNextEpochState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInNextValidatorSetLockedState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "state", + "type": "uint8" + } + ], + "name": "MustBeInReadyForNextEpochState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "MustBeValidatorInNextEpochToKick", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epochEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeout", + "type": "uint256" + } + ], + "name": "NotEnoughTimeElapsedForTimeoutSinceLastEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epochEndTime", + "type": "uint256" + } + ], + "name": "NotEnoughTimeElapsedSinceLastEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "validatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCount", + "type": "uint256" + } + ], + "name": "NotEnoughValidatorsInNextEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentReadyValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nextReadyValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCountToBeReady", + "type": "uint256" + } + ], + "name": "NotEnoughValidatorsReadyForNextEpoch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentEpochNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receivedEpochNumber", + "type": "uint256" + } + ], + "name": "SignaledReadyForWrongEpochNumber", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "StakerNotPermitted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "yourBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestedWithdrawlAmount", + "type": "uint256" + } + ], + "name": "TryingToWithdrawMoreThanStaked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "internalType": "address[]", + "name": "validatorsInNextEpoch", + "type": "address[]" + } + ], + "name": "ValidatorIsNotInNextEpoch", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kickPenaltyPercent", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct LibStakingStorage.ComplaintConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "ComplaintConfigSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newTokenRewardPerTokenPerEpoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "newKeyTypes", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinimumValidatorCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxConcurrentRequests", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxTripleCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinTripleCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeerCheckingIntervalSecs", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxTripleConcurrency", + "type": "uint256" + } + ], + "name": "ConfigSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newEpochEndTime", + "type": "uint256" + } + ], + "name": "EpochEndTimeSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newEpochLength", + "type": "uint256" + } + ], + "name": "EpochLengthSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newEpochTimeout", + "type": "uint256" + } + ], + "name": "EpochTimeoutSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newKickPenaltyPercent", + "type": "uint256" + } + ], + "name": "KickPenaltyPercentSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "epochNumber", + "type": "uint256" + } + ], + "name": "ReadyForNextEpoch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Recovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "RequestToJoin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "RequestToLeave", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverContractAddress", + "type": "address" + } + ], + "name": "ResolverContractAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newDuration", + "type": "uint256" + } + ], + "name": "RewardsDurationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newStakingTokenAddress", + "type": "address" + } + ], + "name": "StakingTokenSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum LibStakingStorage.States", + "name": "newState", + "type": "uint8" + } + ], + "name": "StateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountBurned", + "type": "uint256" + } + ], + "name": "ValidatorKickedFromNextEpoch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "ValidatorRejoinedNextEpoch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "VotedToKickValidatorInNextEpoch", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + } + ], + "name": "adminKickValidatorInNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "adminRejoinValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "adminResetEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountToPenalize", + "type": "uint256" + } + ], + "name": "adminSlashValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "advanceEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "exit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "kickValidatorInNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lockValidatorsForNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "requestToJoin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "requestToLeave", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "requestToLeaveAsNode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kickPenaltyPercent", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.ComplaintConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "setComplaintConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenRewardPerTokenPerEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "DEPRECATED_complaintTolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "DEPRECATED_complaintIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "keyTypes", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxConcurrentRequests", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "peerCheckingIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTripleConcurrency", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Config", + "name": "newConfig", + "type": "tuple" + } + ], + "name": "setConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newEpochEndTime", + "type": "uint256" + } + ], + "name": "setEpochEndTime", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newEpochLength", + "type": "uint256" + } + ], + "name": "setEpochLength", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "newState", + "type": "uint8" + } + ], + "name": "setEpochState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newEpochTimeout", + "type": "uint256" + } + ], + "name": "setEpochTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "setIpPortNodeAddressAndCommunicationPubKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newKickPenaltyPercent", + "type": "uint256" + } + ], + "name": "setKickPenaltyPercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epochNumber", + "type": "uint256" + } + ], + "name": "signalReadyForNextEpoch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "name": "stakeAndJoin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "VersionRequirementsUpdated", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "checkVersion", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxVersion", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxVersionString", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMinVersion", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMinVersionString", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "setMaxVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "major", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "patch", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Version", + "name": "version", + "type": "tuple" + } + ], + "name": "setMinVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + } + ], + "name": "complaintConfig", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kickPenaltyPercent", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.ComplaintConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "config", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenRewardPerTokenPerEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "DEPRECATED_complaintTolerance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "DEPRECATED_complaintIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "keyTypes", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minimumValidatorCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxConcurrentRequests", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minTripleCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "peerCheckingIntervalSecs", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxTripleConcurrency", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Config", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "countOfCurrentValidatorsReadyForNextEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "countOfNextValidatorsReadyForNextEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentValidatorCountForConsensus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "epoch", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "epochLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "retries", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeout", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Epoch", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getKeyTypes", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getKickedValidators", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "name": "getNodeStakerAddressMappings", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "internalType": "struct LibStakingStorage.AddressMapping[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStakingBalancesAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsInCurrentEpoch", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsInCurrentEpochLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsInNextEpoch", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "name": "getValidatorsStructs", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsStructsInCurrentEpoch", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorsStructsInNextEpoch", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "epochNumber", + "type": "uint256" + }, + { + "internalType": "address", + "name": "validatorStakerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "voterStakerAddress", + "type": "address" + } + ], + "name": "getVotingStatusToKickValidator", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isActiveValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isActiveValidatorByNodeAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isReadyForNextEpoch", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reason", + "type": "uint256" + } + ], + "name": "kickPenaltyPercentByReason", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextValidatorCountForConsensus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + } + ], + "name": "nodeAddressToStakerAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "readyForNextEpoch", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "shouldKickValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "state", + "outputs": [ + { + "internalType": "enum LibStakingStorage.States", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "validators", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "ip", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ipv6", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "port", + "type": "uint32" + }, + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderPubKey", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receiverPubKey", + "type": "uint256" + } + ], + "internalType": "struct LibStakingStorage.Validator", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "Staking" + }, + "StakingBalances": { + "address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotAddFunctionToDiamondThatAlreadyExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotAddSelectorsToZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveFunctionThatDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotRemoveImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionThatDoesNotExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "_selectors", + "type": "bytes4[]" + } + ], + "name": "CannotReplaceFunctionsFromFacetWithZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "CannotReplaceImmutableFunction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_action", + "type": "uint8" + } + ], + "name": "IncorrectFacetCutAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initializationContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "InitializationFunctionReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "NoBytecodeAtAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "NoSelectorsProvidedForFacetForCut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + } + ], + "name": "NotContractOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facetAddress", + "type": "address" + } + ], + "name": "RemoveFacetAddressMustBeZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamond.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamond.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facetAddress_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facetAddresses_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_facetFunctionSelectors", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "ActiveValidatorsCannotLeave", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "AliasNotOwnedBySender", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "CannotRemoveAliasOfActiveValidator", + "type": "error" + }, + { + "inputs": [], + "name": "CannotStakeZero", + "type": "error" + }, + { + "inputs": [], + "name": "CannotWithdrawZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "aliasCount", + "type": "uint256" + } + ], + "name": "MaxAliasCountReached", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "OnlyStakingContract", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountStaked", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + } + ], + "name": "StakeMustBeGreaterThanMinimumStake", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountStaked", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maximumStake", + "type": "uint256" + } + ], + "name": "StakeMustBeLessThanMaximumStake", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddress", + "type": "address" + } + ], + "name": "StakerNotPermitted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "yourBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestedWithdrawlAmount", + "type": "uint256" + } + ], + "name": "TryingToWithdrawMoreThanStaked", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "AliasAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "AliasRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxAliasCount", + "type": "uint256" + } + ], + "name": "MaxAliasCountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMaximumStake", + "type": "uint256" + } + ], + "name": "MaximumStakeSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMinimumStake", + "type": "uint256" + } + ], + "name": "MinimumStakeSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "PermittedStakerAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "PermittedStakerRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "permittedStakersOn", + "type": "bool" + } + ], + "name": "PermittedStakersOnChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "ResolverContractAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newTokenRewardPerTokenPerEpoch", + "type": "uint256" + } + ], + "name": "TokenRewardPerTokenPerEpochSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "ValidatorNotRewardedBecauseAlias", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRewarded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorTokensPenalized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "addAlias", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "addPermittedStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "stakers", + "type": "address[]" + } + ], + "name": "addPermittedStakers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "checkStakingAmounts", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractResolver", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "isPermittedStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maximumStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minimumStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "penalizeTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "permittedStakersOn", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "aliasAccount", + "type": "address" + } + ], + "name": "removeAlias", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "removePermittedStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "restakePenaltyTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "rewardOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "rewardValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newResolverAddress", + "type": "address" + } + ], + "name": "setContractResolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaxAliasCount", + "type": "uint256" + } + ], + "name": "setMaxAliasCount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaximumStake", + "type": "uint256" + } + ], + "name": "setMaximumStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMinimumStake", + "type": "uint256" + } + ], + "name": "setMinimumStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "permitted", + "type": "bool" + } + ], + "name": "setPermittedStakersOn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalStaked", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "transferPenaltyTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "withdrawPenaltyTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "name": "StakingBalances" + }, + "ContractResolver": { + "address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "abi": [ + { + "inputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AdminRoleRequired", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "AllowedEnvAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "AllowedEnvRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "typ", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "SetContract", + "type": "event" + }, + { + "inputs": [], + "name": "ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ALLOWLIST_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BACKUP_RECOVERY_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_WALLET_REGISTRY", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "HD_KEY_DERIVER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "LIT_TOKEN_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MULTI_SENDER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAYMENT_DELEGATION_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_HELPER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_NFT_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_NFT_METADATA_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PKP_PERMISSIONS_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PUB_KEY_ROUTER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RATE_LIMIT_NFT_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELEASE_REGISTER_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKING_BALANCES_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKING_CONTRACT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "addAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "addAllowedEnv", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "typ", + "type": "bytes32" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "getContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adminBeingRemoved", + "type": "address" + } + ], + "name": "removeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + } + ], + "name": "removeAllowedEnv", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "typ", + "type": "bytes32" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "env", + "type": "uint8" + }, + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "setContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "enum ContractResolver.Env", + "name": "", + "type": "uint8" + } + ], + "name": "typeAddresses", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "name": "ContractResolver" + } +} From 66cd792b8060dc98a56b97c34eb2814aa6222bcd Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 17:06:01 +0100 Subject: [PATCH 165/263] fix(CI): update `--filter` flag in command --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85349c9b44..8035219bed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,4 +54,4 @@ jobs: run: yarn build - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: yarn test:local --filtertestUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString + run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString From e5cbbbcdb94cf421cd4358b675d8e9fa429a9e56 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 17:46:50 +0100 Subject: [PATCH 166/263] feat: add `--exclude` flag for Tinny operation --- local-tests/setup/tinny-operations.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/local-tests/setup/tinny-operations.ts b/local-tests/setup/tinny-operations.ts index 41439a18fa..a3f9151d35 100644 --- a/local-tests/setup/tinny-operations.ts +++ b/local-tests/setup/tinny-operations.ts @@ -14,6 +14,15 @@ export const getFiltersFlag = (): string[] => { return filterArg ? filterArg.replace('--filter=', '').split(',') : []; }; +/** + * Retrieves the exclude flags from the command line arguments. + * @returns An array of strings representing the exclude flags. + */ +export const getExcludeFlags = (): string[] => { + const filterArg = process.argv.find((arg) => arg.startsWith('--exclude=')); + return filterArg ? filterArg.replace('--exclude=', '').split(',') : []; +}; + /** * Runs the tests in the provided `tests` object in a synchronous manner. * Each test is executed in a loop with a maximum number of attempts specified by `devEnv.processEnvs.MAX_ATTEMPTS`. @@ -120,10 +129,15 @@ export const runTestsParallel = async ({ devEnv: TinnyEnvironment; }): Promise => { const filters = getFiltersFlag(); + const excludeFilters = getExcludeFlags(); + + // Filter the tests based on include and exclude filters const testsToRun = Object.entries(tests).filter( ([testName]) => - filters.length === 0 || - filters.some((filter) => testName.includes(filter)) + (filters.length === 0 || + filters.some((filter) => testName.includes(filter))) && + (excludeFilters.length === 0 || + !excludeFilters.some((exclude) => testName.includes(exclude))) ); if (!testsToRun || testsToRun.length <= 0) { From 3872906be151b978f5005a967635c419e58d8e45 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 17:47:22 +0100 Subject: [PATCH 167/263] fix(CI): update command to exclude `Parallel` keyword --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8035219bed..1894c00900 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,4 +54,4 @@ jobs: run: yarn build - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString + run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString --exclude=Parallel From 046319cb7d7719fb4d142b7578c8a63e4f2370ff Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 15 May 2024 17:59:04 +0100 Subject: [PATCH 168/263] fix(CI): increase `MAX_ATTEMPTS` and improve build speed --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1894c00900..c68454d667 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: with: main-branch-name: 'master' - name: Build - run: yarn build + run: yarn build:dev - name: Run Unit tests run: yarn tools --test --unit e2e-connection: @@ -38,6 +38,7 @@ jobs: env: NETWORK: cayenne DEBUG: true + MAX_ATTEMPTS: 3 steps: - name: Checkout repo uses: actions/checkout@v2 @@ -51,7 +52,7 @@ jobs: run: yarn install - name: Build packages id: build - run: yarn build + run: yarn build:dev - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString --exclude=Parallel From 74b2b0a63ae445db98332a86702b2abbb8f43d37 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 20 May 2024 18:25:12 -0400 Subject: [PATCH 169/263] feat: remove implicit loading of wasm to connect invokation --- packages/core/src/lib/lit-core.ts | 19 +++- packages/crypto/src/lib/crypto.spec.ts | 2 + packages/crypto/src/lib/crypto.ts | 117 +++++++++++++++---------- 3 files changed, 90 insertions(+), 48 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index fe67acd536..1f5bde0dc2 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -26,7 +26,12 @@ import { CAYENNE_URL, } from '@lit-protocol/constants'; import { LitContracts } from '@lit-protocol/contracts-sdk'; -import { checkSevSnpAttestation, computeHDPubKey } from '@lit-protocol/crypto'; +import { + checkSevSnpAttestation, + computeHDPubKey, + loadModules, + unloadModules, +} from '@lit-protocol/crypto'; import { bootstrapLogManager, executeWithRetry, @@ -457,11 +462,16 @@ export class LitCore { } /** - * Stops internal listeners/polling that refresh network state and watch for epoch changes + * Stops internal listeners/polling that refresh network state and watch for epoch changes. + * Removes global objects created internally */ async disconnect() { + unloadModules(); + this._stopListeningForNewEpoch(); this._stopNetworkPolling(); + if (globalThis.litConfig) + delete globalThis.litConfig; } _stopNetworkPolling() { @@ -529,6 +539,11 @@ export class LitCore { * */ async connect(): Promise { + // If we have never connected on this client instance first load WASM modules. + if (!this.ready) { + await loadModules(); + } + // Ensure that multiple closely timed calls to `connect()` don't result in concurrent connect() operations being run if (this._connectingPromise) { return this._connectingPromise; diff --git a/packages/crypto/src/lib/crypto.spec.ts b/packages/crypto/src/lib/crypto.spec.ts index d7b13edb36..3b93f9d122 100644 --- a/packages/crypto/src/lib/crypto.spec.ts +++ b/packages/crypto/src/lib/crypto.spec.ts @@ -6,6 +6,7 @@ import { combineSignatureShares, verifySignature, combineEcdsaShares, + loadModules, } from './crypto'; import * as ethers from 'ethers'; import { joinSignature } from 'ethers/lib/utils'; @@ -25,6 +26,7 @@ const identityParam = new Uint8Array([ describe('crypto', () => { beforeAll(async () => { + await loadModules(); await blsSdk.initWasmBlsSdk(); }); diff --git a/packages/crypto/src/lib/crypto.ts b/packages/crypto/src/lib/crypto.ts index a42438a0ce..35fb79d8dd 100644 --- a/packages/crypto/src/lib/crypto.ts +++ b/packages/crypto/src/lib/crypto.ts @@ -22,62 +22,87 @@ import { CombinedECDSASignature } from '@lit-protocol/types'; const LIT_CORS_PROXY = `https://cors.litgateway.com`; -// if 'wasmExports' is not available, we need to initialize the BLS SDK -if (!globalThis.wasmExports) { - blsSdk.initWasmBlsSdk().then((exports) => { - globalThis.wasmExports = exports; - - if (!globalThis.jestTesting) { - log( - `✅ [BLS SDK] wasmExports loaded. ${ - Object.keys(exports).length - } functions available. Run 'wasmExports' in the console to see them.` - ); - } - }); +export interface BlsSignatureShare { + ProofOfPossession: string; } -if (!globalThis.wasmECDSA) { - let init = ecdsaSdk.initWasmEcdsaSdk; - let env; - - if (isBrowser()) { - env = 'Browser'; - } else { - env = 'NodeJS'; +/** + Loads all wasm modules into the glboal scope + + - ECDSA utilities - wasmECDSA + - BLS utilities - wasmExports + - SEV-SNP utilities - wasmSevSnpUtilities + + @returns {Promise} +*/ +export const loadModules = (): Promise => { + // if 'wasmExports' is not available, we need to initialize the BLS SDK + if (!globalThis.wasmExports) { + blsSdk.initWasmBlsSdk().then((exports) => { + globalThis.wasmExports = exports; + + if (!globalThis.jestTesting) { + log( + `✅ [BLS SDK] wasmExports loaded. ${ + Object.keys(exports).length + } functions available. Run 'wasmExports' in the console to see them.` + ); + } + }); } - init().then((sdk: any) => { - globalThis.wasmECDSA = sdk; + if (!globalThis.wasmECDSA) { + let init = ecdsaSdk.initWasmEcdsaSdk; + let env; - if (!globalThis.jestTesting) { - log( - `✅ [ECDSA SDK ${env}] wasmECDSA loaded. ${ - Object.keys(wasmECDSA).length - } functions available. Run 'wasmECDSA' in the console to see them.` - ); + if (isBrowser()) { + env = 'Browser'; + } else { + env = 'NodeJS'; } - }); -} -if (!globalThis.wasmSevSnpUtils) { - sevSnpUtilsSdk.initWasmSevSnpUtilsSdk().then((exports) => { - globalThis.wasmSevSnpUtils = exports; + init().then((sdk: any) => { + globalThis.wasmECDSA = sdk; - if (!globalThis.jestTesting) { - log( - `✅ [SEV SNP Utils SDK] wasmSevSnpUtils loaded. ${ - Object.keys(exports).length - } functions available. Run 'wasmSevSnpUtils' in the console to see them.` - ); - } - }); -} + if (!globalThis.jestTesting) { + log( + `✅ [ECDSA SDK ${env}] wasmECDSA loaded. ${ + Object.keys(wasmECDSA).length + } functions available. Run 'wasmECDSA' in the console to see them.` + ); + } + }); + } -/** ---------- Exports ---------- */ + if (!globalThis.wasmSevSnpUtils) { + sevSnpUtilsSdk.initWasmSevSnpUtilsSdk().then((exports) => { + globalThis.wasmSevSnpUtils = exports; -export interface BlsSignatureShare { - ProofOfPossession: string; + if (!globalThis.jestTesting) { + log( + `✅ [SEV SNP Utils SDK] wasmSevSnpUtils loaded. ${ + Object.keys(exports).length + } functions available. Run 'wasmSevSnpUtils' in the console to see them.` + ); + } + }); + } +}; + +/* + Removes wasm modules from global scope + if found to be defined. Can be called multiple times safely. +*/ +export const unloadModules = () => { + log('running cleanup for global modules'); + if (globalThis.wasmExports) + delete globalThis.wasmExports; + + if (globalThis.wasmECDSA) + delete globalThis.wasmECDSA; + + if(globalThis.wasmSevSnpUtilsSdk) + delete globalThis.initWasmSevSnpUtilsSdk; } /** From d350e0a1ec206147253ffcf583d21830c9f91071 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 20 May 2024 18:25:52 -0400 Subject: [PATCH 170/263] feat: add global checks in env loader for defined wasm globals --- local-tests/setup/tinny-environment.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 81cdac3a33..5f7c2b1696 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -215,6 +215,24 @@ export class TinnyEnvironment { }); } + if (globalThis.wasmExports) { + console.warn( + 'WASM modules already loaded. wil overide. when connect is called' + ); + } + + if (globalThis.wasmECDSA) { + console.warn( + 'WASM modules already loaded. wil overide. when connect is called' + ); + } + + if (globalThis.wasmSevSnpUtils) { + console.warn( + 'WASM modules already loaded. wil overide. when connect is called' + ); + } + await this.litNodeClient.connect(); if (!this.litNodeClient.ready) { From 353e4b4d97a68b193b716386fe69bc4fbd215ffe Mon Sep 17 00:00:00 2001 From: Josh Long Date: Mon, 20 May 2024 18:36:21 -0400 Subject: [PATCH 171/263] chore: fmt --- packages/core/src/lib/lit-core.ts | 3 +-- packages/crypto/src/lib/crypto.ts | 15 ++++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 1f5bde0dc2..39dec183b8 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -470,8 +470,7 @@ export class LitCore { this._stopListeningForNewEpoch(); this._stopNetworkPolling(); - if (globalThis.litConfig) - delete globalThis.litConfig; + if (globalThis.litConfig) delete globalThis.litConfig; } _stopNetworkPolling() { diff --git a/packages/crypto/src/lib/crypto.ts b/packages/crypto/src/lib/crypto.ts index 35fb79d8dd..b99e6afe36 100644 --- a/packages/crypto/src/lib/crypto.ts +++ b/packages/crypto/src/lib/crypto.ts @@ -95,15 +95,12 @@ export const loadModules = (): Promise => { */ export const unloadModules = () => { log('running cleanup for global modules'); - if (globalThis.wasmExports) - delete globalThis.wasmExports; - - if (globalThis.wasmECDSA) - delete globalThis.wasmECDSA; - - if(globalThis.wasmSevSnpUtilsSdk) - delete globalThis.initWasmSevSnpUtilsSdk; -} + if (globalThis.wasmExports) delete globalThis.wasmExports; + + if (globalThis.wasmECDSA) delete globalThis.wasmECDSA; + + if (globalThis.wasmSevSnpUtilsSdk) delete globalThis.initWasmSevSnpUtilsSdk; +}; /** * Encrypt data with a BLS public key. From e6cbc0c4943e05f411711812ad449014c85e574a Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 20 May 2024 23:41:27 +0100 Subject: [PATCH 172/263] feat(contracts-sdk): add helper functions: 1. mintWithCustomAuth 2. addPermittedAuthMethod 3. addPermittedAction --- .../contracts-sdk/src/lib/contracts-sdk.ts | 151 ++++++++++++++++-- 1 file changed, 139 insertions(+), 12 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 0cfb898cdd..a1a219ecc3 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -4,12 +4,12 @@ import { hexToDec, decToHex, intToIP } from './hex2dec'; import bs58 from 'bs58'; import { isBrowser, isNode } from '@lit-protocol/misc'; import { - AuthMethod, - LIT_NETWORKS_KEYS, LitContractContext, LitContractResolverContext, MintCapacityCreditsContext, MintCapacityCreditsRes, + MintWithAuthParams, + mintWithCustomAuthParams, } from '@lit-protocol/types'; // ----- autogen:import-data:start ----- @@ -45,7 +45,7 @@ import * as stakingBalancesContract from '../abis/StakingBalances.sol/StakingBal import { TokenInfo, derivedAddresses } from './addresses'; import { IPubkeyRouter } from '../abis/PKPNFT.sol/PKPNFT'; import { computeAddress } from 'ethers/lib/utils'; -import { getAuthIdByAuthMethod } from './auth-utils'; +import { getAuthIdByAuthMethod, stringToArrayify } from './auth-utils'; import { Logger, LogManager } from '@lit-protocol/logger'; import { calculateUTCMidnightExpiration, @@ -57,6 +57,7 @@ import { IPFSHash, getBytes32FromMultihash, } from './helpers/getBytes32FromMultihash'; +import { AuthMethodScope, AuthMethodType } from '@lit-protocol/constants'; const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; const BLOCK_EXPLORER = 'https://chain.litprotocol.com/'; @@ -980,15 +981,22 @@ export class LitContracts { return data; } + /** + * Mints a new token with authentication. + * + * @param authMethod - The authentication method. + * @param scopes - The permission scopes. + * @param pubkey - The public key. + * @param authId - (optional) The authentication ID. + * @returns An object containing the PKP information and the transaction receipt. + * @throws Error if the contracts are not connected, the contract is not available, authMethodType or accessToken is missing, or permission scopes are required. + */ mintWithAuth = async ({ authMethod, scopes, pubkey, - }: { - authMethod: AuthMethod; - scopes: string[] | number[] | BigNumberish[]; - pubkey?: string; // only applies to webauthn auth method - }) => { + authId, + }: MintWithAuthParams) => { // -- validate if (!this.connected) { throw new Error( @@ -1032,7 +1040,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope return scope; }); - const authId = await getAuthIdByAuthMethod(authMethod); + const _authId = authId ?? (await getAuthIdByAuthMethod(authMethod)); // -- go const mintCost = await this.pkpNftContract.read.mintCost(); @@ -1041,7 +1049,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope const tx = await this.pkpHelperContract.write.mintNextAndAddAuthMethods( 2, // key type [authMethod.authMethodType], - [authId], + [_authId], [_pubkey], [[...scopes]], true, @@ -1090,8 +1098,127 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope }; }; - // Mints a Capacity Credits NFT (RLI) token with the specified daily request rate and expiration period. - // The expiration date is calculated to be at midnight UTC, a specific number of days from now. + /** + * Mints a new token with customer authentication. + * + * @param authMethod - The authentication method. + * @param scopes - The permission scopes. + * @param customAuthId - The authentication ID. + * @returns An object containing the PKP information and the transaction receipt. + * @throws Error if the contracts are not connected, the contract is not available, authMethodType or accessToken is missing, or permission scopes are required. + * @example + * + const customAuthMethodOwnedPkp = + await alice.contractsClient.mintWithCustomAuth({ + customAuthId: 'custom-app-user-id', + authMethod: customAuthMethod, + scopes: [AuthMethodScope.SignAnything], + }); + */ + mintWithCustomAuth = async (params: mintWithCustomAuthParams) => { + params.authId = + typeof params.customAuthId === 'string' + ? stringToArrayify(params.customAuthId) + : params.customAuthId; + + return this.mintWithAuth({ + ...params, + }); + }; + + /** + * Adds a permitted authentication method for a given PKP token. + * + * @param {Object} params - The parameters for adding the permitted authentication method. + * @param {string} params.pkpTokenId - The ID of the PKP token. + * @param {AuthMethodType | number} params.authMethodType - The type of the authentication method. + * @param {string | Uint8Array} params.authId - The ID of the authentication method. + * @param {AuthMethodScope[]} params.authMethodScopes - The scopes of the authentication method. + * @param {string} [params.webAuthnPubkey] - The public key for WebAuthn. + * @returns {Promise} - A promise that resolves with the result of adding the permitted authentication method. + * @throws {Error} - If an error occurs while adding the permitted authentication method. + */ + addPermittedAuthMethod = async ({ + pkpTokenId, + authMethodType, + authId, + authMethodScopes, + webAuthnPubkey, + }: { + pkpTokenId: string; + authMethodType: AuthMethodType | number; + authId: string | Uint8Array; + authMethodScopes: AuthMethodScope[]; + webAuthnPubkey?: string; + }) => { + const _authId = + typeof authId === 'string' ? stringToArrayify(authId) : authId; + + const _webAuthnPubkey = webAuthnPubkey ?? '0x'; + + try { + const res = + await this.pkpPermissionsContract.write.addPermittedAuthMethod( + pkpTokenId, + { + authMethodType: authMethodType, + id: _authId, + userPubkey: _webAuthnPubkey, + }, + authMethodScopes + ); + + const receipt = await res.wait(); + + return receipt; + } catch (e: any) { + throw new Error(e); + } + }; + + /** + * Adds a permitted action to the PKP permissions contract. + * + * @param ipfsId - The IPFS ID of the action. + * @param pkpTokenId - The PKP token ID. + * @param authMethodScopes - Optional array of authentication method scopes. + * @returns A promise that resolves to the result of the write operation. + * @throws If an error occurs during the write operation. + */ + addPermittedAction = async ({ + ipfsId, + pkpTokenId, + authMethodScopes, + }: { + ipfsId: string; + pkpTokenId: string; + authMethodScopes: AuthMethodScope[]; + }) => { + const ipfsIdBytes = this.utils.getBytesFromMultihash(ipfsId); + const scopes = authMethodScopes ?? []; + + try { + const res = await this.pkpPermissionsContract.write.addPermittedAction( + pkpTokenId, + ipfsIdBytes, + scopes + ); + + const receipt = await res.wait(); + + return receipt; + } catch (e: any) { + throw new Error(e); + } + }; + + /** + * Mint a Capacity Credits NFT (RLI) token with the specified daily request rate and expiration period. The expiration date is calculated to be at midnight UTC, a specific number of days from now. + * + * @param {MintCapacityCreditsContext} context - The minting context. + * @returns {Promise} - A promise that resolves to the minted capacity credits NFT response. + * @throws {Error} - If the input parameters are invalid or an error occurs during the minting process. + */ mintCapacityCreditsNFT = async ({ requestsPerDay, requestsPerSecond, From c7327f776c7d744a08eb7068a04400673dad0cd0 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 20 May 2024 23:42:54 +0100 Subject: [PATCH 173/263] fix(types): custom auth jsParams should accept any params as key --- packages/types/src/lib/interfaces.ts | 43 +++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 24d0044a96..92ec6a796d 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1871,8 +1871,18 @@ export interface GetPkpSessionSigs extends CommonGetSessionSigsProps, LitCustomAuth { pkpPublicKey: string; - authMethods: AuthMethod[]; + + /** + * Lit Protocol supported auth methods: https://developer.litprotocol.com/v3/sdk/wallets/auth-methods + * This CANNOT be used for custom auth methods. For custom auth methods, please pass the customAuth + * object to jsParams, and handle the custom auth method in your Lit Action. + * + * Notes for internal dev: for the SDK, this value can be omitted, but it needs to be an empty array [] set in the SDK before + * sending it to the node + */ + authMethods?: AuthMethod[]; jsParams?: { + [key: string]: any; publicKey?: string; sigName?: string; }; @@ -1891,3 +1901,34 @@ export interface SignatureData { export type ClaimsList = { [key: string]: SignatureData; }[]; + +export interface MintWithAuthParams { + /** + * auth method to use for minting + */ + authMethod: AuthMethod; + + /** + * Permission scopes: + * https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scopes + */ + scopes: string[] | number[]; + + /** + * only applies to webauthn auth method + */ + pubkey?: string; + + /** + * The Auth ID of the given auth method. If it's custom auth, then it could be + * anything. + */ + authId?: Uint8Array; +} + +export interface mintWithCustomAuthParams extends MintWithAuthParams { + /** + * For a custom authentication method, the custom auth ID should uniquely identify the user for that project. For example, for Google, we use appId:userId, so you should follow a similar format for Telegram, Twitter, or any other custom auth method. + */ + customAuthId: string | Uint8Array; +} From 1983ff03982150b5044f71ab7a1dfffd127362af Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 20 May 2024 23:43:28 +0100 Subject: [PATCH 174/263] fix(sign-session-key): params are not passed to authNeededCallback when resign is needed --- .../src/lib/lit-node-client-nodejs.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d430aa38f8..ce733bed80 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2406,6 +2406,13 @@ const resourceAbilityRequests = [ uri: sessionKeyUri, nonce, resourceAbilityRequests: params.resourceAbilityRequests, + + // -- optional fields + ...(params.litActionCode && { litActionCode: params.litActionCode }), + ...(params.litActionIpfsId && { + litActionIpfsId: params.litActionIpfsId, + }), + ...(params.jsParams && { jsParams: params.jsParams }), }, }); } @@ -2518,10 +2525,16 @@ const resourceAbilityRequests = [ ); } + /** + * We must provide an empty array for authMethods even if we are not using any auth methods. + * So that the nodes can serialize the request correctly. + */ + const authMethods = params.authMethods || []; + const response = await this.signSessionKey({ sessionKey: props.sessionKey, statement: props.statement || 'Some custom statement.', - authMethods: [...params.authMethods], + authMethods: [...authMethods], pkpPublicKey: params.pkpPublicKey, expiration: props.expiration, resources: props.resources, From ca792786f335ce9c7aefd1be276d2b1586235e13 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 20 May 2024 23:43:40 +0100 Subject: [PATCH 175/263] feat(test): add custom auth tests --- local-tests/test.ts | 4 + .../testUseCustomAuthSessionSigsToPkpSign.ts | 121 ++++++++++++++++++ packages/contracts-sdk/src/lib/auth-utils.ts | 13 ++ 3 files changed, 138 insertions(+) create mode 100644 local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts diff --git a/local-tests/test.ts b/local-tests/test.ts index cc45dbeca1..1474bccc05 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -78,6 +78,7 @@ import { testPkpEthersWithPkpSessionSigsToEthSignTypedData } from './tests/testP import { testPkpEthersWithLitActionSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData'; import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil'; import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil'; +import { testUseCustomAuthSessionSigsToPkpSign } from './tests/testUseCustomAuthSessionSigsToPkpSign'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -125,6 +126,9 @@ import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './t // -- invalid cases testUseInvalidLitActionIpfsCodeToGenerateSessionSigs, + + // -- custom auth methods + testUseCustomAuthSessionSigsToPkpSign, }; const litActionIpfsIdSessionSigsTests = { diff --git a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts new file mode 100644 index 0000000000..cedd368577 --- /dev/null +++ b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts @@ -0,0 +1,121 @@ +import { + LitAbility, + LitActionResource, + LitPKPResource, +} from '@lit-protocol/auth-helpers'; +import { AuthMethodScope } from '@lit-protocol/constants'; +import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; + +/** + * Test Commands: + * ❌ NETWORK=cayenne yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign + * ❌ NOT AVAILABLE IN HABANERO + * ❌ NETWORK=localchain yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign + */ +export const testUseCustomAuthSessionSigsToPkpSign = async ( + devEnv: TinnyEnvironment +) => { + const alice = await devEnv.createRandomPerson(); + + /** + * This is a custom auth method. It can be anything you want. + */ + const customAuthMethod = { + authMethodType: 89989, + accessToken: 'xxx', + }; + + console.log('✅ customAuthMethod:', customAuthMethod); + + const customAuthMethodOwnedPkp = + await alice.contractsClient.mintWithCustomAuth({ + customAuthId: 'custom-app-user-id', // ipfs hash for the auth method + authMethod: customAuthMethod, + scopes: [AuthMethodScope.SignAnything], + }); + console.log('✅ customAuthMethodOwnedPkp:', customAuthMethodOwnedPkp); + + const addPermittedAuthMethodReceipt = + await alice.contractsClient.addPermittedAuthMethod({ + pkpTokenId: alice.pkp.tokenId, + authId: 'app-id-xxx:user-id-yyy', + authMethodType: customAuthMethod.authMethodType, + authMethodScopes: [AuthMethodScope.SignAnything], + }); + + console.log( + '✅ addPermittedAuthMethodReceipt:', + addPermittedAuthMethodReceipt + ); + + /** + * Please note that the code below is first converted to a CID and stored in the smart contract. + * Therefore, the Lit action code executed in the `getPkpSessionSigs` function must match the CID stored in the smart contract. + * + * You can use https://explorer.litprotocol.com/create-action to create a Lit action and get the CID. + */ + const litActionCodeString = `(async () => { + const a = 1; + const b = 2; + + if (a + b === 3 && customAuthMethod.authMethodType === 89989) { + LitActions.setResponse({response:"true"}); + } else { + LitActions.setResponse({response:"false"}); + } + + console.log("16 Lit.Auth:", Lit.Auth); + })()`; + + const IPFSID = 'QmeG3spjJmqzFo4dpWte5Prv1xdUbPT3sYqo3n3ABQXgMF'; + + console.log('✅ IPFSID:', IPFSID.toString()); + + // Grant an action permission to use a PKP + const addPermittedActionReceipt = + await alice.contractsClient.addPermittedAction({ + ipfsId: IPFSID, + pkpTokenId: alice.pkp.tokenId, + authMethodScopes: [AuthMethodScope.SignAnything], + }); + + console.log('✅ addPermittedActionReceipt:', addPermittedActionReceipt); + + const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ + pkpPublicKey: alice.pkp.publicKey, + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ], + // litActionIpfsId: IPFSID, + litActionCode: Buffer.from(litActionCodeString).toString('base64'), + jsParams: { + publicKey: `0x${alice.pkp.publicKey}`, + customAuthMethod: customAuthMethod, + sigName: 'custom-auth-sig', + }, + }); + + console.log('litActionSessionSigs:', litActionSessionSigs); + + // -- pkp sign test + try { + const res = await devEnv.litNodeClient.pkpSign({ + toSign: alice.loveLetter, + pubKey: alice.pkp.publicKey, + sessionSigs: litActionSessionSigs, + }); + + console.log('✅ res:', res); + } catch (e) { + throw new Error(e); + } + + process.exit(); +}; diff --git a/packages/contracts-sdk/src/lib/auth-utils.ts b/packages/contracts-sdk/src/lib/auth-utils.ts index 6e7d379359..134a5910ae 100644 --- a/packages/contracts-sdk/src/lib/auth-utils.ts +++ b/packages/contracts-sdk/src/lib/auth-utils.ts @@ -338,3 +338,16 @@ function _resolveAuthFactor(factor: any): { throw new Error(`Error could not find auth with factor ${factor}`); } + +/** + * Converts a string into a byte array (arrayified value). + * @param str - The input string to be converted. + * @returns A Uint8Array representing the arrayified value of the string. + */ +export const stringToArrayify = (str: string) => { + try { + return ethers.utils.toUtf8Bytes(str); + } catch (e) { + throw new Error(`Error converting string to arrayify: ${e}`); + } +}; From 9e76c3759da008f9c96d595050124270c7bd3dba Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 20 May 2024 23:45:01 +0100 Subject: [PATCH 176/263] chore: update jsDocs --- local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts index cedd368577..3f806f4e77 100644 --- a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts @@ -8,9 +8,9 @@ import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; /** * Test Commands: - * ❌ NETWORK=cayenne yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign - * ❌ NOT AVAILABLE IN HABANERO - * ❌ NETWORK=localchain yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign + * NETWORK=cayenne yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign + * NOT AVAILABLE IN HABANERO + * NETWORK=localchain yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign */ export const testUseCustomAuthSessionSigsToPkpSign = async ( devEnv: TinnyEnvironment From 34c5c890e0799ddfbd93645d782e5e8d6b088fd3 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 20 May 2024 23:53:43 +0100 Subject: [PATCH 177/263] chore: pretty lint --- packages/types/src/lib/interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 92ec6a796d..c1969f5ba3 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1876,7 +1876,7 @@ export interface GetPkpSessionSigs * Lit Protocol supported auth methods: https://developer.litprotocol.com/v3/sdk/wallets/auth-methods * This CANNOT be used for custom auth methods. For custom auth methods, please pass the customAuth * object to jsParams, and handle the custom auth method in your Lit Action. - * + * * Notes for internal dev: for the SDK, this value can be omitted, but it needs to be an empty array [] set in the SDK before * sending it to the node */ From 36b06143562c0976916090232ba365becf845057 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 00:14:33 +0100 Subject: [PATCH 178/263] fix: https://github.com/LIT-Protocol/js-sdk/pull/472#discussion_r1607381850 --- packages/contracts-sdk/src/lib/auth-utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/contracts-sdk/src/lib/auth-utils.ts b/packages/contracts-sdk/src/lib/auth-utils.ts index 134a5910ae..7e3c44a0f3 100644 --- a/packages/contracts-sdk/src/lib/auth-utils.ts +++ b/packages/contracts-sdk/src/lib/auth-utils.ts @@ -340,6 +340,7 @@ function _resolveAuthFactor(factor: any): { } /** + * TODO: Replace ethers to something else, so we don't rely on ethers * Converts a string into a byte array (arrayified value). * @param str - The input string to be converted. * @returns A Uint8Array representing the arrayified value of the string. From 09e21e9e39d1eedf6e9c49eb51f2a6708ddd08ba Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 19:04:28 +0100 Subject: [PATCH 179/263] fix: change `authId` to `authMethodId` and improve interface --- .../testUseCustomAuthSessionSigsToPkpSign.ts | 39 +++++- packages/contracts-sdk/src/lib/auth-utils.ts | 19 +-- .../contracts-sdk/src/lib/contracts-sdk.ts | 67 +++++---- packages/types/src/lib/interfaces.ts | 128 ++++++++++-------- 4 files changed, 160 insertions(+), 93 deletions(-) diff --git a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts index 3f806f4e77..e3000359ec 100644 --- a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts @@ -6,6 +6,28 @@ import { import { AuthMethodScope } from '@lit-protocol/constants'; import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; +import { importer } from 'ipfs-unixfs-importer'; +import { Buffer } from 'buffer'; + +// Function to convert string to an IPFS hash +async function stringToIpfsHash(input: string): Promise { + // Convert the input string to a Buffer + const content = Buffer.from(input); + + // Import the content to create an IPFS file + const files = importer([{ content }], {} as any, { onlyHash: true }); + + // Get the first (and only) file result + const result = (await files.next()).value; + + const ipfsHash = (result as any).cid.toString(); + if (!ipfsHash.startsWith('Qm')) { + throw new Error('Generated hash does not start with Qm'); + } + + return ipfsHash; +} + /** * Test Commands: * NETWORK=cayenne yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign @@ -18,28 +40,31 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( const alice = await devEnv.createRandomPerson(); /** - * This is a custom auth method. It can be anything you want. + * This is a custom auth method. It can be anything you want. Even the shape of the object can be anything, + * because you are handling the logic in the Lit action code yourself. */ const customAuthMethod = { authMethodType: 89989, + authMethodId: 'app-id-xxx:user-id-yyy', accessToken: 'xxx', }; console.log('✅ customAuthMethod:', customAuthMethod); - const customAuthMethodOwnedPkp = + const customAuthMethodOwnedReceipt = await alice.contractsClient.mintWithCustomAuth({ - customAuthId: 'custom-app-user-id', // ipfs hash for the auth method - authMethod: customAuthMethod, + authMethodId: customAuthMethod.authMethodId, + authMethodType: customAuthMethod.authMethodType, scopes: [AuthMethodScope.SignAnything], }); - console.log('✅ customAuthMethodOwnedPkp:', customAuthMethodOwnedPkp); + + console.log('✅ customAuthMethodOwnedReceipt:', customAuthMethodOwnedReceipt); const addPermittedAuthMethodReceipt = await alice.contractsClient.addPermittedAuthMethod({ pkpTokenId: alice.pkp.tokenId, - authId: 'app-id-xxx:user-id-yyy', authMethodType: customAuthMethod.authMethodType, + authMethodId: customAuthMethod.authMethodId, authMethodScopes: [AuthMethodScope.SignAnything], }); @@ -67,7 +92,7 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( console.log("16 Lit.Auth:", Lit.Auth); })()`; - const IPFSID = 'QmeG3spjJmqzFo4dpWte5Prv1xdUbPT3sYqo3n3ABQXgMF'; + const IPFSID = await stringToIpfsHash(litActionCodeString); console.log('✅ IPFSID:', IPFSID.toString()); diff --git a/packages/contracts-sdk/src/lib/auth-utils.ts b/packages/contracts-sdk/src/lib/auth-utils.ts index 7e3c44a0f3..be4fe31499 100644 --- a/packages/contracts-sdk/src/lib/auth-utils.ts +++ b/packages/contracts-sdk/src/lib/auth-utils.ts @@ -5,28 +5,29 @@ import * as jose from 'jose'; * Code here is ported from `packages/lit-auth-client` due to circular dep errors */ export async function getAuthIdByAuthMethod(authMethod: any): Promise { - let authId; + let authMethodId; + switch (authMethod.authMethodType) { case 1: - authId = getEthAuthMethodId(authMethod); + authMethodId = getEthAuthMethodId(authMethod); break; case 4: - authId = await getDiscordAuthId(authMethod); + authMethodId = await getDiscordAuthId(authMethod); break; case 3: - authId = await getWebauthnAuthId(authMethod); + authMethodId = await getWebauthnAuthId(authMethod); break; case 6: - authId = await getGoogleJwtAuthId(authMethod); + authMethodId = await getGoogleJwtAuthId(authMethod); break; case 9: - authId = await getStytchAuthId(authMethod); + authMethodId = await getStytchAuthId(authMethod); break; case 10: case 11: case 12: case 13: - authId = await getStytchFactorAuthMethodId(authMethod); + authMethodId = await getStytchFactorAuthMethodId(authMethod); break; default: throw new Error( @@ -34,7 +35,7 @@ export async function getAuthIdByAuthMethod(authMethod: any): Promise { ); } - return authId; + return authMethodId; } /** @@ -345,7 +346,7 @@ function _resolveAuthFactor(factor: any): { * @param str - The input string to be converted. * @returns A Uint8Array representing the arrayified value of the string. */ -export const stringToArrayify = (str: string) => { +export const stringToArrayify = (str: string): Uint8Array => { try { return ethers.utils.toUtf8Bytes(str); } catch (e) { diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index a1a219ecc3..4befd99ddf 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1,15 +1,22 @@ /* eslint-disable import/order */ -import { BigNumber, BigNumberish, BytesLike, ethers } from 'ethers'; +import { + BigNumber, + BigNumberish, + BytesLike, + ContractReceipt, + ethers, +} from 'ethers'; import { hexToDec, decToHex, intToIP } from './hex2dec'; import bs58 from 'bs58'; import { isBrowser, isNode } from '@lit-protocol/misc'; import { + CreateCustomAuthMethodRequest, LitContractContext, LitContractResolverContext, MintCapacityCreditsContext, MintCapacityCreditsRes, MintWithAuthParams, - mintWithCustomAuthParams, + MintWithAuthResponse, } from '@lit-protocol/types'; // ----- autogen:import-data:start ----- @@ -987,7 +994,7 @@ export class LitContracts { * @param authMethod - The authentication method. * @param scopes - The permission scopes. * @param pubkey - The public key. - * @param authId - (optional) The authentication ID. + * @param authMethodId - (optional) The authentication ID. * @returns An object containing the PKP information and the transaction receipt. * @throws Error if the contracts are not connected, the contract is not available, authMethodType or accessToken is missing, or permission scopes are required. */ @@ -995,8 +1002,8 @@ export class LitContracts { authMethod, scopes, pubkey, - authId, - }: MintWithAuthParams) => { + authMethodId, + }: MintWithAuthParams): Promise> => { // -- validate if (!this.connected) { throw new Error( @@ -1012,7 +1019,11 @@ export class LitContracts { throw new Error('authMethodType is required'); } - if (authMethod && !authMethod?.accessToken) { + if ( + authMethod && + !authMethod?.accessToken && + authMethod?.accessToken !== 'custom-auth' + ) { throw new Error('accessToken is required'); } @@ -1040,7 +1051,8 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope return scope; }); - const _authId = authId ?? (await getAuthIdByAuthMethod(authMethod)); + const _authMethodId = + authMethodId ?? (await getAuthIdByAuthMethod(authMethod)); // -- go const mintCost = await this.pkpNftContract.read.mintCost(); @@ -1049,7 +1061,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope const tx = await this.pkpHelperContract.write.mintNextAndAddAuthMethods( 2, // key type [authMethod.authMethodType], - [_authId], + [_authMethodId], [_pubkey], [[...scopes]], true, @@ -1103,26 +1115,33 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope * * @param authMethod - The authentication method. * @param scopes - The permission scopes. - * @param customAuthId - The authentication ID. + * @param authMethodId - The authentication ID. * @returns An object containing the PKP information and the transaction receipt. * @throws Error if the contracts are not connected, the contract is not available, authMethodType or accessToken is missing, or permission scopes are required. * @example * const customAuthMethodOwnedPkp = await alice.contractsClient.mintWithCustomAuth({ - customAuthId: 'custom-app-user-id', + authMethodId: 'custom-app-user-id', authMethod: customAuthMethod, scopes: [AuthMethodScope.SignAnything], - }); + }); */ - mintWithCustomAuth = async (params: mintWithCustomAuthParams) => { - params.authId = - typeof params.customAuthId === 'string' - ? stringToArrayify(params.customAuthId) - : params.customAuthId; + mintWithCustomAuth = async ( + params: CreateCustomAuthMethodRequest + ): Promise> => { + const authMethodId = + typeof params.authMethodId === 'string' + ? stringToArrayify(params.authMethodId) + : params.authMethodId; return this.mintWithAuth({ ...params, + authMethodId, + authMethod: { + authMethodType: params.authMethodType, + accessToken: 'custom-auth', + }, }); }; @@ -1132,7 +1151,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope * @param {Object} params - The parameters for adding the permitted authentication method. * @param {string} params.pkpTokenId - The ID of the PKP token. * @param {AuthMethodType | number} params.authMethodType - The type of the authentication method. - * @param {string | Uint8Array} params.authId - The ID of the authentication method. + * @param {string | Uint8Array} params.authMethodId - The ID of the authentication method. * @param {AuthMethodScope[]} params.authMethodScopes - The scopes of the authentication method. * @param {string} [params.webAuthnPubkey] - The public key for WebAuthn. * @returns {Promise} - A promise that resolves with the result of adding the permitted authentication method. @@ -1141,18 +1160,20 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope addPermittedAuthMethod = async ({ pkpTokenId, authMethodType, - authId, + authMethodId, authMethodScopes, webAuthnPubkey, }: { pkpTokenId: string; authMethodType: AuthMethodType | number; - authId: string | Uint8Array; + authMethodId: string | Uint8Array; authMethodScopes: AuthMethodScope[]; webAuthnPubkey?: string; - }) => { - const _authId = - typeof authId === 'string' ? stringToArrayify(authId) : authId; + }): Promise => { + const _authMethodId = + typeof authMethodId === 'string' + ? stringToArrayify(authMethodId) + : authMethodId; const _webAuthnPubkey = webAuthnPubkey ?? '0x'; @@ -1162,7 +1183,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope pkpTokenId, { authMethodType: authMethodType, - id: _authId, + id: _authMethodId, userPubkey: _webAuthnPubkey, }, authMethodScopes diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index c1969f5ba3..2b272bd2aa 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -50,7 +50,7 @@ export interface CosmosAuthSig extends AuthSig { export type CosmosWalletType = 'keplr' | 'leap'; -export interface AuthCallbackParams { +export interface AuthCallbackParams extends LitActionSdkParams { /** * The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. */ @@ -99,21 +99,6 @@ export interface AuthCallbackParams { walletConnectProjectId?: string; resourceAbilityRequests?: LitResourceAbilityRequest[]; - - /** - * The js code to run on the nodes - */ - litActionCode?: string; - - /** - * The IPFS id of the lit action to run - */ - litActionIpfsId?: string; - - /** - * The js params to run on the nodes - */ - jsParams?: any; } /** ---------- Web3 ---------- */ @@ -1027,6 +1012,21 @@ export interface AuthMethod { accessToken: string; } +export interface CreateCustomAuthMethodRequest { + /** + * For a custom authentication method, the custom auth ID should uniquely identify the user for that project. For example, for Google, we use appId:userId, so you should follow a similar format for Telegram, Twitter, or any other custom auth method. + */ + authMethodId: string | Uint8Array; + + authMethodType: number; + + /** + * Permission scopes: + * https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scopes + */ + scopes: string[] | number[]; +} + // pub struct JsonSignSessionKeyRequest { // pub session_key: String, // pub auth_methods: Vec, @@ -1034,7 +1034,7 @@ export interface AuthMethod { // pub auth_sig: Option, // pub siwe_message: String, // } -export interface SignSessionKeyProp { +export interface SignSessionKeyProp extends LitActionSdkParams { /** * The serialized session key pair to sign. If not provided, a session key pair will be fetched from localStorge or generated. */ @@ -1077,24 +1077,6 @@ export interface SignSessionKeyProp { * A LIT resource ability is a combination of a LIT resource and a LIT ability. */ resourceAbilityRequests?: LitResourceAbilityRequest[]; - - /** - * The js code on ipfs - */ - litActionIpfsId?: string; - /** - * The js code to run on the nodes - */ - litActionCode?: string; - - /** - * The params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. - */ - jsParams?: { - [key: string]: any; - publicKey: string; - sigName: string; - }; } export interface SignSessionKeyResponse { @@ -1158,7 +1140,7 @@ export interface CommonGetSessionSigsProps { export interface GetSessionSigsProps extends CommonGetSessionSigsProps, - LitCustomAuth { + LitActionSdkParams { /** * This is a callback that will be called if the user needs to authenticate using a PKP. For example, if the user has no wallet, but owns a Lit PKP though something like Google Oauth, then you can use this callback to prompt the user to authenticate with their PKP. This callback should use the LitNodeClient.signSessionKey function to get a session signature for the user from their PKP. If you don't pass this callback, then the user will be prompted to authenticate with their wallet, like metamask. */ @@ -1182,7 +1164,7 @@ export interface SessionRequestBody { siweMessage: string; } -export interface GetWalletSigProps extends LitCustomAuth { +export interface GetWalletSigProps extends LitActionSdkParams { authNeededCallback?: AuthCallback; chain: string; sessionCapabilityObject: ISessionCapabilityObject; @@ -1841,13 +1823,54 @@ export interface CapacityCreditsRes { capacityDelegationAuthSig: AuthSig; } -export interface LitCustomAuth { +export interface LitActionSdkParams { + /** + * The litActionCode is the JavaScript code that will run on the nodes. + * You will need to convert the string content to base64. + * + * @example + * Buffer.from(litActionCodeString).toString('base64'); + */ litActionCode?: string; + + /** + * You can obtain the Lit Action IPFS CID by converting your JavaScript code using this tool: + * https://explorer.litprotocol.com/create-action + * + * Note: You do not need to pin your code to IPFS necessarily. + * You can convert a code string to an IPFS hash using the "ipfs-hash-only" or 'ipfs-unixfs-importer' library. + * + * @example + * async function stringToIpfsHash(input: string): Promise { + * // Convert the input string to a Buffer + * const content = Buffer.from(input); + * + * // Import the content to create an IPFS file + * const files = importer([{ content }], {} as any, { onlyHash: true }); + * + * // Get the first (and only) file result + * const result = (await files.next()).value; + * + * const ipfsHash = (result as any).cid.toString(); + * if (!ipfsHash.startsWith('Qm')) { + * throw new Error('Generated hash does not start with Qm'); + * } + * + * return ipfsHash; + * } + */ litActionIpfsId?: string; - jsParams?: { - publicKey?: string; - sigName?: string; - }; + + /** + * An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. + */ + jsParams?: + | { + [key: string]: any; + publicKey?: string; + sigName?: string; + } + | any; } export interface LitEndpoint { @@ -1869,7 +1892,7 @@ export interface SignerLike { export interface GetPkpSessionSigs extends CommonGetSessionSigsProps, - LitCustomAuth { + LitActionSdkParams { pkpPublicKey: string; /** @@ -1881,11 +1904,6 @@ export interface GetPkpSessionSigs * sending it to the node */ authMethods?: AuthMethod[]; - jsParams?: { - [key: string]: any; - publicKey?: string; - sigName?: string; - }; } export type SessionKeyCache = { @@ -1923,12 +1941,14 @@ export interface MintWithAuthParams { * The Auth ID of the given auth method. If it's custom auth, then it could be * anything. */ - authId?: Uint8Array; + authMethodId?: Uint8Array; } -export interface mintWithCustomAuthParams extends MintWithAuthParams { - /** - * For a custom authentication method, the custom auth ID should uniquely identify the user for that project. For example, for Google, we use appId:userId, so you should follow a similar format for Telegram, Twitter, or any other custom auth method. - */ - customAuthId: string | Uint8Array; +export interface MintWithAuthResponse { + pkp: { + tokenId: string; + publicKey: string; + ethAddress: string; + }; + tx: T; } From c708a294afbe909d3894bbd0251f0062177e18d5 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 20:41:24 +0100 Subject: [PATCH 180/263] feat(tinny-helper): make `stringToIpfsHash` a tinny helper --- local-tests/setup/tinny-utils.ts | 26 +++++++++++++++++++ .../testUseCustomAuthSessionSigsToPkpSign.ts | 23 +--------------- 2 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 local-tests/setup/tinny-utils.ts diff --git a/local-tests/setup/tinny-utils.ts b/local-tests/setup/tinny-utils.ts new file mode 100644 index 0000000000..4e52b609d2 --- /dev/null +++ b/local-tests/setup/tinny-utils.ts @@ -0,0 +1,26 @@ +import { importer } from 'ipfs-unixfs-importer'; +import { Buffer } from 'buffer'; + +/** + * Converts a string to an IPFS hash. + * @param input - The input string to convert. + * @returns A Promise that resolves to the IPFS hash. + * @throws An error if the generated hash does not start with 'Qm'. + */ +export async function stringToIpfsHash(input: string): Promise { + // Convert the input string to a Buffer + const content = Buffer.from(input); + + // Import the content to create an IPFS file + const files = importer([{ content }], {} as any, { onlyHash: true }); + + // Get the first (and only) file result + const result = (await files.next()).value; + + const ipfsHash = (result as any).cid.toString(); + if (!ipfsHash.startsWith('Qm')) { + throw new Error('Generated hash does not start with Qm'); + } + + return ipfsHash; +} diff --git a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts index e3000359ec..059efc2558 100644 --- a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts @@ -5,28 +5,7 @@ import { } from '@lit-protocol/auth-helpers'; import { AuthMethodScope } from '@lit-protocol/constants'; import { TinnyEnvironment } from 'local-tests/setup/tinny-environment'; - -import { importer } from 'ipfs-unixfs-importer'; -import { Buffer } from 'buffer'; - -// Function to convert string to an IPFS hash -async function stringToIpfsHash(input: string): Promise { - // Convert the input string to a Buffer - const content = Buffer.from(input); - - // Import the content to create an IPFS file - const files = importer([{ content }], {} as any, { onlyHash: true }); - - // Get the first (and only) file result - const result = (await files.next()).value; - - const ipfsHash = (result as any).cid.toString(); - if (!ipfsHash.startsWith('Qm')) { - throw new Error('Generated hash does not start with Qm'); - } - - return ipfsHash; -} +import { stringToIpfsHash } from 'local-tests/setup/tinny-utils'; /** * Test Commands: From 1269f8c52ed0d42733e74ede9edf9677d3f04459 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 21:35:52 +0100 Subject: [PATCH 181/263] feat(test): add `ipfs-unixfs-importer` to Tinny --- local-tests/setup/tinny-utils.ts | 9 ++++++++- package.json | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-utils.ts b/local-tests/setup/tinny-utils.ts index 4e52b609d2..013468a4db 100644 --- a/local-tests/setup/tinny-utils.ts +++ b/local-tests/setup/tinny-utils.ts @@ -8,16 +8,23 @@ import { Buffer } from 'buffer'; * @throws An error if the generated hash does not start with 'Qm'. */ export async function stringToIpfsHash(input: string): Promise { + const blockput = { + put: async (block: any) => { + return block.cid; + }, + }; + // Convert the input string to a Buffer const content = Buffer.from(input); // Import the content to create an IPFS file - const files = importer([{ content }], {} as any, { onlyHash: true }); + const files = importer([{ content }], blockput as any); // Get the first (and only) file result const result = (await files.next()).value; const ipfsHash = (result as any).cid.toString(); + if (!ipfsHash.startsWith('Qm')) { throw new Error('Generated hash does not start with Qm'); } diff --git a/package.json b/package.json index 53283d07ce..4e1f820cc8 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "find-config": "^1.0.0", "g": "^2.0.1", "https-browserify": "^1.0.0", + "ipfs-unixfs-importer": "12.0.1", "jose": "^4.14.4", "jszip": "^3.10.1", "micromodal": "^0.4.10", From df055151572d9b602322f31e92a19fb703099000 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 21:39:12 +0100 Subject: [PATCH 182/263] chore: update `yarn.lock` --- yarn.lock | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8f293adb08..1d65f04fad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,6 +27,11 @@ rxjs "7.8.1" source-map "0.7.4" +"@assemblyscript/loader@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.9.4.tgz#a483c54c1253656bb33babd464e3154a173e1577" + integrity sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA== + "@async-generators/from-emitter@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@async-generators/from-emitter/-/from-emitter-0.3.0.tgz#3496bf2a25f40ddbf2bcf5873ae3ceb3f4aa2dc4" @@ -2066,6 +2071,13 @@ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== +"@ipld/dag-pb@^4.0.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ipld/dag-pb/-/dag-pb-4.1.0.tgz#4ebec92eeb9e8f317b8ef971221c6dac7b12b302" + integrity sha512-LJU451Drqs5zjFm7jI4Hs3kHlilOqkjcSfPiQgVsZnWaYb2C7YdfhnclrVn/X+ucKejlU9BL3+gXFCZUXkMuCg== + dependencies: + multiformats "^13.1.0" + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -3348,6 +3360,14 @@ "@motionone/dom" "^10.16.4" tslib "^2.3.1" +"@multiformats/murmur3@^2.0.0": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@multiformats/murmur3/-/murmur3-2.1.8.tgz#81c1c15b6391109f3febfca4b3205196615a04e9" + integrity sha512-6vId1C46ra3R1sbJUOFCZnsUIveR9oF20yhPmAFxPm0JfrX3/ZRCgP3YDrBzlGoEppOXnA9czHeYc0T9mB6hbA== + dependencies: + multiformats "^13.0.0" + murmurhash3js-revisited "^3.0.0" + "@mysten/bcs@0.7.3": version "0.7.3" resolved "https://registry.yarnpkg.com/@mysten/bcs/-/bcs-0.7.3.tgz#b2e4558a8feb9fd3a0dc2ff4e94c37e1f8a7c7e5" @@ -8460,6 +8480,15 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + blakejs@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" @@ -14424,6 +14453,14 @@ h3@^1.10.2, h3@^1.11.1: uncrypto "^0.1.3" unenv "^1.9.0" +hamt-sharding@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/hamt-sharding/-/hamt-sharding-3.0.6.tgz#3643107a3021af66ac95684aec87b196add5ba57" + integrity sha512-nZeamxfymIWLpVcAN0CRrb7uVq3hCOGj9IcL6NMA6VVCVWqj+h9Jo/SmaWuS92AEDf1thmHsM5D5c70hM3j2Tg== + dependencies: + sparse-array "^1.3.1" + uint8arrays "^5.0.1" + handle-thing@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" @@ -15334,6 +15371,35 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== +ipfs-unixfs-importer@12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/ipfs-unixfs-importer/-/ipfs-unixfs-importer-12.0.1.tgz#316a52d8a793e9e006b1ee43edc50b83e00ef306" + integrity sha512-//VPZOqbONtc1HNtb+sBrw+nIGijHEloSm1O3LVR5orSlhHQ8X7+OCkeqceFBhu40tPMe/TwgAPrkvh+fXL+bA== + dependencies: + "@ipld/dag-pb" "^4.0.0" + "@multiformats/murmur3" "^2.0.0" + err-code "^3.0.1" + hamt-sharding "^3.0.0" + interface-blockstore "^4.0.0" + ipfs-unixfs "^9.0.0" + it-all "^2.0.0" + it-batch "^2.0.0" + it-first "^2.0.0" + it-parallel-batch "^2.0.0" + merge-options "^3.0.4" + multiformats "^11.0.0" + rabin-wasm "^0.1.4" + uint8arraylist "^2.3.3" + uint8arrays "^4.0.2" + +ipfs-unixfs@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/ipfs-unixfs/-/ipfs-unixfs-9.0.1.tgz#d06e688e07ef4ce08d610337ba2fe8c143c386e7" + integrity sha512-jh2CbXyxID+v3jLml9CqMwjdSS9ZRnsGfQGGPOfem0/hT/L48xUeTPvh7qLFWkZcIMhZtG+fnS1teei8x5uGBg== + dependencies: + err-code "^3.0.1" + protobufjs "^7.0.0" + iron-webcrypto@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.1.1.tgz#245c9d467075ee810343ddfa53dd4909616aaf33" @@ -15694,7 +15760,7 @@ is-path-inside@^3.0.1, is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@2.1.0, is-plain-obj@^2.0.0: +is-plain-obj@2.1.0, is-plain-obj@^2.0.0, is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== @@ -16075,6 +16141,11 @@ it-all@^2.0.0: resolved "https://registry.yarnpkg.com/it-all/-/it-all-2.0.1.tgz#45d530ecf6e13fb81d7ba583cdfd55ffdb376b05" integrity sha512-9UuJcCRZsboz+HBQTNOau80Dw+ryGaHYFP/cPYzFBJBFcfDathMYnhHk4t52en9+fcyDGPTdLB+lFc1wzQIroA== +it-batch@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/it-batch/-/it-batch-2.0.1.tgz#a0822be9b18743c41d8525835f788a7f297ba41f" + integrity sha512-2gWFuPzamh9Dh3pW+OKjc7UwJ41W4Eu2AinVAfXDMfrC5gXfm3b1TF+1UzsygBUgKBugnxnGP+/fFRyn+9y1mQ== + it-drain@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/it-drain/-/it-drain-2.0.1.tgz#f50f6ce5cb8592a9d6337c9b5e780348877b152d" @@ -16085,6 +16156,18 @@ it-filter@^2.0.0: resolved "https://registry.yarnpkg.com/it-filter/-/it-filter-2.0.2.tgz#c849b3de4a12a2de3cc45be734ee55f69a0ed284" integrity sha512-gocw1F3siqupegsOzZ78rAc9C+sYlQbI2af/TmzgdrR613MyEJHbvfwBf12XRekGG907kqXSOGKPlxzJa6XV1Q== +it-first@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/it-first/-/it-first-2.0.1.tgz#75d66b254c385ae3a1906def060a69006a437cef" + integrity sha512-noC1oEQcWZZMUwq7VWxHNLML43dM+5bviZpfmkxkXlvBe60z7AFRqpZSga9uQBo792jKv9otnn1IjA4zwgNARw== + +it-parallel-batch@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/it-parallel-batch/-/it-parallel-batch-2.0.1.tgz#23eb07bbeb73521253d7c8a1566b53137103077c" + integrity sha512-tXh567/JfDGJ90Zi//H9HkL7kY27ARp0jf2vu2jUI6PUVBWfsoT+gC4eT41/b4+wkJXSGgT8ZHnivAOlMfcNjA== + dependencies: + it-batch "^2.0.0" + it-take@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/it-take/-/it-take-2.0.1.tgz#f9e5ddf0b73a18ba00e62fb532d9d3cde3fe4ce6" @@ -17936,6 +18019,11 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -18242,6 +18330,13 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-options@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7" + integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ== + dependencies: + is-plain-obj "^2.1.0" + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -18744,6 +18839,11 @@ multiformats@^12.0.1: resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-12.1.3.tgz#cbf7a9861e11e74f8228b21376088cb43ba8754e" integrity sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw== +multiformats@^13.0.0, multiformats@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-13.1.0.tgz#5aa9d2175108a448fc3bdb54ba8a3d0b6cab3ac3" + integrity sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ== + multiformats@^9.4.2, multiformats@^9.7.1: version "9.9.0" resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" @@ -18769,6 +18869,11 @@ multimatch@^5.0.0: arrify "^2.0.1" minimatch "^3.0.4" +murmurhash3js-revisited@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" + integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -20909,6 +21014,24 @@ protobufjs@^6.8.8, protobufjs@~6.11.2, protobufjs@~6.11.3: "@types/node" ">=13.7.0" long "^4.0.0" +protobufjs@^7.0.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.0.tgz#a32ec0422c039798c41a0700306a6e305b9cb32c" + integrity sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + protocols@^2.0.0, protocols@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" @@ -21163,6 +21286,18 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +rabin-wasm@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/rabin-wasm/-/rabin-wasm-0.1.5.tgz#5b625ca007d6a2cbc1456c78ae71d550addbc9c9" + integrity sha512-uWgQTo7pim1Rnj5TuWcCewRDTf0PEFTSlaUjWP4eY9EbLV9em08v89oCz/WO+wRxpYuO36XEHp4wgYQnAgOHzA== + dependencies: + "@assemblyscript/loader" "^0.9.4" + bl "^5.0.0" + debug "^4.3.1" + minimist "^1.2.5" + node-fetch "^2.6.1" + readable-stream "^3.6.0" + radix3@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" @@ -22741,6 +22876,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sparse-array@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/sparse-array/-/sparse-array-1.3.2.tgz#0e1a8b71706d356bc916fe754ff496d450ec20b0" + integrity sha512-ZT711fePGn3+kQyLuv1fpd3rNSkNF8vd5Kv2D+qnOANeyKs3fx6bUMGWRPvgTTcYV64QMqZKZwcuaQSP3AZ0tg== + spawn-command@^0.0.2-1: version "0.0.2-1" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" @@ -24282,6 +24422,13 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== +uint8arraylist@^2.3.3: + version "2.4.8" + resolved "https://registry.yarnpkg.com/uint8arraylist/-/uint8arraylist-2.4.8.tgz#5a4d17f4defd77799cb38e93fd5db0f0dceddc12" + integrity sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ== + dependencies: + uint8arrays "^5.0.1" + uint8arrays@^3.0.0, uint8arrays@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" @@ -24289,13 +24436,20 @@ uint8arrays@^3.0.0, uint8arrays@^3.1.0: dependencies: multiformats "^9.4.2" -uint8arrays@^4.0.3: +uint8arrays@^4.0.2, uint8arrays@^4.0.3: version "4.0.10" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.10.tgz#3ec5cde3348903c140e87532fc53f46b8f2e921f" integrity sha512-AnJNUGGDJAgFw/eWu/Xb9zrVKEGlwJJCaeInlf3BkecE/zcTobk5YXYIPNQJO1q5Hh1QZrQQHf0JvcHqz2hqoA== dependencies: multiformats "^12.0.1" +uint8arrays@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.1.0.tgz#14047c9bdf825d025b7391299436e5e50e7270f1" + integrity sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww== + dependencies: + multiformats "^13.0.0" + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" From 1809d3f20f562040a2e9f140bbbb8fb7d54dfd71 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 22:14:58 +0100 Subject: [PATCH 183/263] feat(test): update ci to include `customAuth` --- .github/workflows/ci.yml | 2 +- .../testUseCustomAuthSessionSigsToPkpSign.ts | 41 ++++++++++++------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c68454d667..d2cbabdaf8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,4 +55,4 @@ jobs: run: yarn build:dev - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString --exclude=Parallel + run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString,testUseCustomAuthSessionSigsToPkpSign --exclude=Parallel diff --git a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts index 059efc2558..d747bdbde2 100644 --- a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts @@ -20,7 +20,7 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( /** * This is a custom auth method. It can be anything you want. Even the shape of the object can be anything, - * because you are handling the logic in the Lit action code yourself. + * because you will be handling the logic in the Lit action code yourself. */ const customAuthMethod = { authMethodType: 89989, @@ -28,17 +28,9 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( accessToken: 'xxx', }; - console.log('✅ customAuthMethod:', customAuthMethod); - - const customAuthMethodOwnedReceipt = - await alice.contractsClient.mintWithCustomAuth({ - authMethodId: customAuthMethod.authMethodId, - authMethodType: customAuthMethod.authMethodType, - scopes: [AuthMethodScope.SignAnything], - }); - - console.log('✅ customAuthMethodOwnedReceipt:', customAuthMethodOwnedReceipt); - + /** + * Alice assigns the custom auth method to her PKP. + */ const addPermittedAuthMethodReceipt = await alice.contractsClient.addPermittedAuthMethod({ pkpTokenId: alice.pkp.tokenId, @@ -68,7 +60,7 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( LitActions.setResponse({response:"false"}); } - console.log("16 Lit.Auth:", Lit.Auth); + console.log("Lit.Auth:", Lit.Auth); })()`; const IPFSID = await stringToIpfsHash(litActionCodeString); @@ -116,7 +108,28 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( sessionSigs: litActionSessionSigs, }); - console.log('✅ res:', res); + console.log('✅ pkpSign res:', res); + } catch (e) { + throw new Error(e); + } + + // -- execute js + try { + const res = await devEnv.litNodeClient.executeJs({ + sessionSigs: litActionSessionSigs, + code: `(async () => { + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + })();`, + jsParams: { + dataToSign: alice.loveLetter, + publicKey: alice.pkp.publicKey, + }, + }); + console.log('✅ executeJs res:', res); } catch (e) { throw new Error(e); } From 93897a4e2543025612b9af9b1cc77ae1e830b68b Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 22:51:30 +0100 Subject: [PATCH 184/263] feat: add `getLitActionSessionSigs` function, better interfaces, and add custom test to CI --- .github/workflows/ci.yml | 2 +- local-tests/test.ts | 4 +- ...ustomAuthSessionSigsToPkpSignExecuteJs.ts} | 45 ++++++++++--------- .../src/lib/lit-node-client-nodejs.ts | 24 ++++++++++ packages/types/src/lib/interfaces.ts | 36 ++++++++++----- 5 files changed, 74 insertions(+), 37 deletions(-) rename local-tests/tests/{testUseCustomAuthSessionSigsToPkpSign.ts => testUseCustomAuthSessionSigsToPkpSignExecuteJs.ts} (81%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2cbabdaf8..88e035d740 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,4 +55,4 @@ jobs: run: yarn build:dev - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString,testUseCustomAuthSessionSigsToPkpSign --exclude=Parallel + run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString,testUseCustomAuthSessionSigsToPkpSignExecuteJs --exclude=Parallel diff --git a/local-tests/test.ts b/local-tests/test.ts index 1474bccc05..97530749e8 100644 --- a/local-tests/test.ts +++ b/local-tests/test.ts @@ -78,7 +78,7 @@ import { testPkpEthersWithPkpSessionSigsToEthSignTypedData } from './tests/testP import { testPkpEthersWithLitActionSessionSigsToEthSignTypedData } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedData'; import { testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithPkpSessionSigsToEthSignTypedDataUtil'; import { testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil } from './tests/testPkpEthersWithLitActionSessionSigsToEthSignTypedDataUtil'; -import { testUseCustomAuthSessionSigsToPkpSign } from './tests/testUseCustomAuthSessionSigsToPkpSign'; +import { testUseCustomAuthSessionSigsToPkpSignExecuteJs } from './tests/testUseCustomAuthSessionSigsToPkpSignExecuteJs'; (async () => { console.log('[𐬺🧪 Tinny𐬺] Running tests...'); @@ -128,7 +128,7 @@ import { testUseCustomAuthSessionSigsToPkpSign } from './tests/testUseCustomAuth testUseInvalidLitActionIpfsCodeToGenerateSessionSigs, // -- custom auth methods - testUseCustomAuthSessionSigsToPkpSign, + testUseCustomAuthSessionSigsToPkpSignExecuteJs, }; const litActionIpfsIdSessionSigsTests = { diff --git a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSignExecuteJs.ts similarity index 81% rename from local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts rename to local-tests/tests/testUseCustomAuthSessionSigsToPkpSignExecuteJs.ts index d747bdbde2..5241c77075 100644 --- a/local-tests/tests/testUseCustomAuthSessionSigsToPkpSign.ts +++ b/local-tests/tests/testUseCustomAuthSessionSigsToPkpSignExecuteJs.ts @@ -9,11 +9,11 @@ import { stringToIpfsHash } from 'local-tests/setup/tinny-utils'; /** * Test Commands: - * NETWORK=cayenne yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign + * NETWORK=cayenne yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSignExecuteJs * NOT AVAILABLE IN HABANERO - * NETWORK=localchain yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSign + * NETWORK=localchain yarn test:local --filter=testUseCustomAuthSessionSigsToPkpSignExecuteJs */ -export const testUseCustomAuthSessionSigsToPkpSign = async ( +export const testUseCustomAuthSessionSigsToPkpSignExecuteJs = async ( devEnv: TinnyEnvironment ) => { const alice = await devEnv.createRandomPerson(); @@ -77,26 +77,27 @@ export const testUseCustomAuthSessionSigsToPkpSign = async ( console.log('✅ addPermittedActionReceipt:', addPermittedActionReceipt); - const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ - pkpPublicKey: alice.pkp.publicKey, - resourceAbilityRequests: [ - { - resource: new LitPKPResource('*'), - ability: LitAbility.PKPSigning, - }, - { - resource: new LitActionResource('*'), - ability: LitAbility.LitActionExecution, + const litActionSessionSigs = + await devEnv.litNodeClient.getLitActionSessionSigs({ + pkpPublicKey: alice.pkp.publicKey, + resourceAbilityRequests: [ + { + resource: new LitPKPResource('*'), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource('*'), + ability: LitAbility.LitActionExecution, + }, + ], + // litActionIpfsId: IPFSID, + litActionCode: Buffer.from(litActionCodeString).toString('base64'), + jsParams: { + publicKey: `0x${alice.pkp.publicKey}`, + customAuthMethod: customAuthMethod, + sigName: 'custom-auth-sig', }, - ], - // litActionIpfsId: IPFSID, - litActionCode: Buffer.from(litActionCodeString).toString('base64'), - jsParams: { - publicKey: `0x${alice.pkp.publicKey}`, - customAuthMethod: customAuthMethod, - sigName: 'custom-auth-sig', - }, - }); + }); console.log('litActionSessionSigs:', litActionSessionSigs); diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index ce733bed80..a791294ac9 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -118,6 +118,7 @@ import type { JsonPkpSignSdkParams, SigResponse, EncryptSdkParams, + GetLitActionSessionSigs, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; @@ -2558,6 +2559,29 @@ const resourceAbilityRequests = [ return pkpSessionSigs; }; + /** + * Retrieves session signatures specifically for Lit Actions. + * Unlike `getPkpSessionSigs`, this function requires either `litActionCode` or `litActionIpfsId`, and `jsParams` must be provided. + * + * @param params - The parameters required for retrieving the session signatures. + * @returns A promise that resolves with the session signatures. + */ + getLitActionSessionSigs = async (params: GetLitActionSessionSigs) => { + // Check if either litActionCode or litActionIpfsId is provided + if (!params.litActionCode && !params.litActionIpfsId) { + throw new Error( + "Either 'litActionCode' or 'litActionIpfsId' must be provided." + ); + } + + // Check if jsParams is provided + if (!params.jsParams) { + throw new Error("'jsParams' is required."); + } + + return this.getPkpSessionSigs(params); + }; + /** * * Get Session Key URI eg. lit:session:0x1234 diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 2b272bd2aa..f86377b4df 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -288,19 +288,18 @@ export interface JsonSignChainDataRequest { exp: number; } -export interface JsonSignSessionKeyRequestV1 { +export interface JsonSignSessionKeyRequestV1 + extends Pick, + Pick { sessionKey: string; authMethods: AuthMethod[]; pkpPublicKey?: string; - // authSig?: AuthSig; siweMessage: string; curveType: 'BLS'; epoch?: number; // custom auth params code?: string; - litActionIpfsId?: string; - jsParams?: any; } // [ @@ -484,12 +483,8 @@ export interface JsonExecutionSdkParamsTargetNode targetNodeRange: number; } -export interface JsonExecutionSdkParams { - /** - * An object that contains params to expose to the Lit Action. These will be injected to the JS runtime before your code runs, so you can use any of these as normal variables in your Lit Action. - */ - jsParams?: any; - +export interface JsonExecutionSdkParams + extends Pick { /** * JS code to run on the nodes */ @@ -521,7 +516,8 @@ export interface JsonExecutionRequestTargetNode extends JsonExecutionRequest { targetNodeRange: number; } -export interface JsonExecutionRequest { +export interface JsonExecutionRequest + extends Pick { authSig: AuthSig; /** @@ -531,7 +527,6 @@ export interface JsonExecutionRequest { // epoch: number; ipfsId?: string; code?: string; - jsParams?: any; authMethods?: AuthMethod[]; } @@ -1906,6 +1901,23 @@ export interface GetPkpSessionSigs authMethods?: AuthMethod[]; } +/** + * Includes common session signature properties, parameters for a Lit Action, + * and either a required litActionCode or a required litActionIpfsId, but not both. + */ +export type GetLitActionSessionSigs = CommonGetSessionSigsProps & + Pick & + Pick & + Pick, 'jsParams'> & + ( + | (Pick, 'litActionCode'> & { + litActionIpfsId?: never; + }) + | (Pick, 'litActionIpfsId'> & { + litActionCode?: never; + }) + ); + export type SessionKeyCache = { value: SessionKeyPair; timestamp: number; From 923f72d392ef953ffd6a7f29a63bad6779dc6b1e Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 22:59:40 +0100 Subject: [PATCH 185/263] fix: Replace ethers to something else, so we don't rely on ethers --- .../contracts-sdk/src/lib/auth-utils.spec.ts | 30 +++++++++++++++---- packages/contracts-sdk/src/lib/auth-utils.ts | 7 +++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/contracts-sdk/src/lib/auth-utils.spec.ts b/packages/contracts-sdk/src/lib/auth-utils.spec.ts index 6d8b9297d1..ae0679df12 100644 --- a/packages/contracts-sdk/src/lib/auth-utils.spec.ts +++ b/packages/contracts-sdk/src/lib/auth-utils.spec.ts @@ -1,7 +1,27 @@ -import { getEthAuthMethodId } from './auth-utils'; -//TODO: update with tests of hashing implementation for auth method ids. -describe('auth-utils', () => { - it('place holder', () => { - expect(1).toEqual(1); +import { getAuthIdByAuthMethod } from './auth-utils'; + +describe('getAuthIdByAuthMethod', () => { + it('should return the auth method id for the given auth method', async () => { + const authMethod = { + authMethodType: 1, + accessToken: '{"address": "0x123abc"}', + }; + + const authMethodId = await getAuthIdByAuthMethod(authMethod); + + expect(authMethodId).toEqual( + '0xfd2f905d807d37105365c450643b6e04c83cf73223d166fb6d63d9b9c974f1a8' + ); + }); + + it('should throw an error for unsupported auth method type', async () => { + const authMethod = { + authMethodType: 5, + accessToken: '...', + }; + + await expect(getAuthIdByAuthMethod(authMethod)).rejects.toThrow( + 'Unsupported auth method type: 5' + ); }); }); diff --git a/packages/contracts-sdk/src/lib/auth-utils.ts b/packages/contracts-sdk/src/lib/auth-utils.ts index be4fe31499..c6d9193932 100644 --- a/packages/contracts-sdk/src/lib/auth-utils.ts +++ b/packages/contracts-sdk/src/lib/auth-utils.ts @@ -341,14 +341,15 @@ function _resolveAuthFactor(factor: any): { } /** - * TODO: Replace ethers to something else, so we don't rely on ethers - * Converts a string into a byte array (arrayified value). + * Converts a string into a byte array (arrayified value) * @param str - The input string to be converted. * @returns A Uint8Array representing the arrayified value of the string. */ export const stringToArrayify = (str: string): Uint8Array => { try { - return ethers.utils.toUtf8Bytes(str); + // Convert the string to a UTF-8 encoded byte array + const encoder = new TextEncoder(); + return encoder.encode(str); } catch (e) { throw new Error(`Error converting string to arrayify: ${e}`); } From 78fc929ac82fb54913901de1f75f5553e49a8504 Mon Sep 17 00:00:00 2001 From: Anson Date: Tue, 21 May 2024 23:00:50 +0100 Subject: [PATCH 186/263] fix: remove `customAuth` on CI as hasn't implemented yet --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88e035d740..c68454d667 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,4 +55,4 @@ jobs: run: yarn build:dev - name: Run End to End Tests if: steps.build.outputs.exit_code == 0 - run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString,testUseCustomAuthSessionSigsToPkpSignExecuteJs --exclude=Parallel + run: yarn test:local --filter=testUseEoaSessionSigsToExecuteJsSigning,testUseEoaSessionSigsToPkpSign,testUsePkpSessionSigsToExecuteJsSigning,testUsePkpSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToPkpSign,testUseValidLitActionCodeGeneratedSessionSigsToExecuteJsSigning,testDelegatingCapacityCreditsNFTToAnotherWalletToExecuteJs,testEthAuthSigToEncryptDecryptString --exclude=Parallel From d37f121198a042bd820da511d643f9e569a076a8 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 21 May 2024 19:08:15 -0400 Subject: [PATCH 187/263] fix exp not respected --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d430aa38f8..7de8e88308 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2430,7 +2430,7 @@ const resourceAbilityRequests = [ // - 5 minutes is the default expiration for a session signature // - Because we can generate a new session sig every time the user wants to access a resource without prompting them to sign with their wallet const sessionExpiration = - params.expiration ?? new Date(Date.now() + 1000 * 60 * 5).toISOString(); + expiration ?? new Date(Date.now() + 1000 * 60 * 5).toISOString(); const capabilities = params.capacityDelegationAuthSig ? [ From ce7ece3274f71a1a7eb57045eedb50b357296e1c Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 22 May 2024 15:38:02 +0100 Subject: [PATCH 188/263] fix: move `"ipfs-unixfs-importer": "12.0.1",` to dev depen --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4e1f820cc8..ef7edfcfc8 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,6 @@ "find-config": "^1.0.0", "g": "^2.0.1", "https-browserify": "^1.0.0", - "ipfs-unixfs-importer": "12.0.1", "jose": "^4.14.4", "jszip": "^3.10.1", "micromodal": "^0.4.10", @@ -203,7 +202,8 @@ "ts-jest": "29.1.2", "ts-node": "10.9.1", "typedoc": "^0.23.10", - "typescript": "~4.7.2" + "typescript": "~4.7.2", + "ipfs-unixfs-importer": "12.0.1" }, "workspaces": [ "packages/*" From dede172fdc20ad503b790c4d7108bcc651fc24d1 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 22 May 2024 16:36:16 +0100 Subject: [PATCH 189/263] feat(tinny): use `getLitActionSessionSigs` instead --- .../get-lit-action-session-sigs.ts | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts index baf05b96ce..192a60e761 100644 --- a/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts +++ b/local-tests/setup/session-sigs/get-lit-action-session-sigs.ts @@ -54,23 +54,24 @@ export const getLitActionSessionSigs = async ( }, ]; - const litActionSessionSigs = await devEnv.litNodeClient.getPkpSessionSigs({ - pkpPublicKey: alice.authMethodOwnedPkp.publicKey, - authMethods: [alice.authMethod], - resourceAbilityRequests: _resourceAbilityRequests, - litActionCode: Buffer.from(VALID_SESSION_SIG_LIT_ACTION_CODE).toString( - 'base64' - ), - jsParams: { - publicKey: alice.authMethodOwnedPkp.publicKey, - sigName: 'unified-auth-sig', - }, + const litActionSessionSigs = + await devEnv.litNodeClient.getLitActionSessionSigs({ + pkpPublicKey: alice.authMethodOwnedPkp.publicKey, + authMethods: [alice.authMethod], + resourceAbilityRequests: _resourceAbilityRequests, + litActionCode: Buffer.from(VALID_SESSION_SIG_LIT_ACTION_CODE).toString( + 'base64' + ), + jsParams: { + publicKey: alice.authMethodOwnedPkp.publicKey, + sigName: 'unified-auth-sig', + }, - // -- only add this for manzano network - ...(devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano - ? { capacityDelegationAuthSig: devEnv.superCapacityDelegationAuthSig } - : {}), - }); + // -- only add this for manzano network + ...(devEnv.litNodeClient.config.litNetwork === LitNetwork.Manzano + ? { capacityDelegationAuthSig: devEnv.superCapacityDelegationAuthSig } + : {}), + }); return litActionSessionSigs; }; From 5e6c576b02c4f3d8df6788c8c7195340be71cf22 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 22 May 2024 11:47:32 -0400 Subject: [PATCH 190/263] Publish 6.0.0-beta.3 --- lerna.json | 2 +- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/constants/src/lib/version.ts | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lerna.json b/lerna.json index c9c78976e2..54be8ed37a 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "useNx": true, "useWorkspaces": true, - "version": "6.0.0-beta.2" + "version": "6.0.0-beta.3" } diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 49d1652d30..4fce19b65c 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 75e6372dcf..f794eb69a2 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -30,7 +30,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index d5695e23ce..deb26a2b0f 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index c0ffab694b..ddc27357ad 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/constants/package.json b/packages/constants/package.json index b20ccfab90..0784fc0f54 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index 96cbe99b8f..adda30ba16 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = '6.0.0-beta.2'; +export const version = '6.0.0-beta.3'; diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index c4ca0de3d5..de40bb1fbd 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -32,7 +32,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/core/package.json b/packages/core/package.json index 24c776acbe..8d8852390d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/core", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/crypto/package.json b/packages/crypto/package.json index b5d169bf6e..b17bb3b183 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index e7b40c8f45..67af205aac 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 0542df409e..a9240fb16e 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index db56194122..a7634fb6ca 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/lit-auth-client", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 454bf1cb1c..7963cdfc57 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -24,7 +24,7 @@ "tags": [ "nodejs" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index bb18a0d62d..2d97db8555 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/logger/package.json b/packages/logger/package.json index 7baa7d6072..54c0938f6d 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/logger", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "tags": [ "universal" diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 23e3b2806c..80f5f510c9 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -21,7 +21,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/misc/package.json b/packages/misc/package.json index 5c69732cd0..ddb23d255d 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/nacl/package.json b/packages/nacl/package.json index a5010da387..267827e308 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -21,7 +21,7 @@ "access": "public", "directory": "../../dist/packages/nacl" }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 862e7e45ea..6d2b3cc936 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-base", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 1541da1fd4..cbd91dcaad 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-client", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 8e4c005481..20b26cb17e 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-cosmos", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 2b7b882243..9d19666bb6 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 2db9f2674d..77bae01bdf 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-sui", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 72dfb5a04f..6e7da327f2 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-walletconnect", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index eb0b681e3b..09fd9ff702 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/types/package.json b/packages/types/package.json index 91533ec2aa..bb4c9bc89d 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -23,7 +23,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index c95c6e6a1e..f69393b79c 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" } From cc3a122a5116988f5b3510b2a818b1c24549bd23 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 22 May 2024 20:53:41 -0400 Subject: [PATCH 191/263] feat: gen a new wallet and transfer small fund amount for tests. --- local-tests/setup/tinny-environment.ts | 24 +++++++++++++----------- local-tests/setup/tinny-person.ts | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 81cdac3a33..3e8d49f5fa 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -251,15 +251,6 @@ export class TinnyEnvironment { const privateKey = key.privateKey; const envConfig = this.getEnvConfig(); - console.log( - '[𐬺🧪 Tinny Environment𐬺] Creating new person with private key:', - JSON.stringify(key) - ); - console.log( - '[𐬺🧪 Tinny Environment𐬺] Creating new person with envConfig:', - envConfig - ); - const person = new TinnyPerson({ privateKey, envConfig, @@ -338,6 +329,16 @@ export class TinnyEnvironment { const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc); const wallet = new ethers.Wallet(privateKey.privateKey, provider); + // TODO: This wallet should be cached somehwere and reused to create delegation signatures. + let capacityCreditWallet = ethers.Wallet.createRandom(); + capacityCreditWallet = new ethers.Wallet(capacityCreditWallet.privateKey, provider); + + let transferTx = await wallet.sendTransaction({ + to: capacityCreditWallet.address, + value: ethers.utils.parseEther("0.001") + }); + await transferTx.wait(); + /** * ==================================== * Setup contracts-sdk client @@ -345,14 +346,14 @@ export class TinnyEnvironment { */ if (this.network === LIT_TESTNET.LOCALCHAIN) { this.contractsClient = new LitContracts({ - signer: wallet, + signer: capacityCreditWallet, debug: this.processEnvs.DEBUG, rpc: this.processEnvs.LIT_RPC_URL, // anvil rpc customContext: networkContext as unknown as LitContractContext, }); } else { this.contractsClient = new LitContracts({ - signer: wallet, + signer: capacityCreditWallet, debug: this.processEnvs.DEBUG, network: this.network, }); @@ -379,6 +380,7 @@ export class TinnyEnvironment { await this.litNodeClient.createCapacityDelegationAuthSig({ dAppOwnerWallet: wallet, capacityTokenId: capacityTokenId, + uses: "200" }) ).capacityDelegationAuthSig; }; diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index bd5057ac42..c92fe89a53 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -51,6 +51,19 @@ export class TinnyPerson { } async spawn() { + let fundingWallet = ethers.Wallet.createRandom(); + fundingWallet = new ethers.Wallet(fundingWallet.privateKey, this.provider); + + const transferTx = await this.wallet.sendTransaction({ + to: fundingWallet.address, + value: ethers.utils.parseEther("0.001") + }); + + const transferReciept = await transferTx.wait(); + console.log('[𐬺🧪 Tinny Person𐬺] Transfered Assets for person tx: ', transferReciept.transactionHash); + this.wallet = fundingWallet; + + console.log('[𐬺🧪 Tinny Person𐬺] Spawning person:', this.wallet.address); /** * ==================================== @@ -163,6 +176,7 @@ export class TinnyPerson { console.log( '[𐬺🧪 Tinny Person𐬺] Mint a Capacity Credits NFT and get a capacity delegation authSig with it' ); + const capacityTokenId = ( await this.contractsClient.mintCapacityCreditsNFT({ requestsPerKilosecond: @@ -171,6 +185,8 @@ export class TinnyPerson { }) ).capacityTokenIdStr; + this.contractsClient.signer = this.wallet; + await this.contractsClient.connect(); return ( await this.envConfig.litNodeClient.createCapacityDelegationAuthSig({ dAppOwnerWallet: this.wallet, From 9670831ef4ed361f7e6401d2bd72407b5b12a9c1 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 22 May 2024 21:04:05 -0400 Subject: [PATCH 192/263] ref: change ethers amount for in memory wallet tinny person --- local-tests/setup/tinny-person.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index c92fe89a53..dafae3ce0f 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -56,7 +56,7 @@ export class TinnyPerson { const transferTx = await this.wallet.sendTransaction({ to: fundingWallet.address, - value: ethers.utils.parseEther("0.001") + value: ethers.utils.parseEther("0.00001") }); const transferReciept = await transferTx.wait(); From fe1e2169b9fde698e53d4328b9fcd44abf19e666 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 22 May 2024 21:05:22 -0400 Subject: [PATCH 193/263] chore: fmt --- local-tests/setup/tinny-environment.ts | 9 ++++++--- local-tests/setup/tinny-person.ts | 12 +++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 3e8d49f5fa..ef6ea5ab81 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -331,11 +331,14 @@ export class TinnyEnvironment { // TODO: This wallet should be cached somehwere and reused to create delegation signatures. let capacityCreditWallet = ethers.Wallet.createRandom(); - capacityCreditWallet = new ethers.Wallet(capacityCreditWallet.privateKey, provider); + capacityCreditWallet = new ethers.Wallet( + capacityCreditWallet.privateKey, + provider + ); let transferTx = await wallet.sendTransaction({ to: capacityCreditWallet.address, - value: ethers.utils.parseEther("0.001") + value: ethers.utils.parseEther('0.001'), }); await transferTx.wait(); @@ -380,7 +383,7 @@ export class TinnyEnvironment { await this.litNodeClient.createCapacityDelegationAuthSig({ dAppOwnerWallet: wallet, capacityTokenId: capacityTokenId, - uses: "200" + uses: '200', }) ).capacityDelegationAuthSig; }; diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index dafae3ce0f..0e89449155 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -53,17 +53,19 @@ export class TinnyPerson { async spawn() { let fundingWallet = ethers.Wallet.createRandom(); fundingWallet = new ethers.Wallet(fundingWallet.privateKey, this.provider); - + const transferTx = await this.wallet.sendTransaction({ to: fundingWallet.address, - value: ethers.utils.parseEther("0.00001") + value: ethers.utils.parseEther('0.00001'), }); const transferReciept = await transferTx.wait(); - console.log('[𐬺🧪 Tinny Person𐬺] Transfered Assets for person tx: ', transferReciept.transactionHash); + console.log( + '[𐬺🧪 Tinny Person𐬺] Transfered Assets for person tx: ', + transferReciept.transactionHash + ); this.wallet = fundingWallet; - console.log('[𐬺🧪 Tinny Person𐬺] Spawning person:', this.wallet.address); /** * ==================================== @@ -176,7 +178,7 @@ export class TinnyPerson { console.log( '[𐬺🧪 Tinny Person𐬺] Mint a Capacity Credits NFT and get a capacity delegation authSig with it' ); - + const capacityTokenId = ( await this.contractsClient.mintCapacityCreditsNFT({ requestsPerKilosecond: From 0381071f1afa2e9b12ac185e434ff1c058ae6633 Mon Sep 17 00:00:00 2001 From: Bean Date: Thu, 23 May 2024 09:43:59 -0400 Subject: [PATCH 194/263] Update local-tests/setup/tinny-environment.ts Co-authored-by: Anson Signed-off-by: Bean --- local-tests/setup/tinny-environment.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index ef6ea5ab81..29078bded2 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -330,11 +330,9 @@ export class TinnyEnvironment { const wallet = new ethers.Wallet(privateKey.privateKey, provider); // TODO: This wallet should be cached somehwere and reused to create delegation signatures. - let capacityCreditWallet = ethers.Wallet.createRandom(); - capacityCreditWallet = new ethers.Wallet( - capacityCreditWallet.privateKey, - provider - ); +```suggestion + // There is a correlation between the number of Capacity Credit NFTs in a wallet and the speed at which nodes can verify a given rate limit authorization. Creating a single wallet to hold all Capacity Credit NFTs improves network performance during tests. + const capacityCreditWallet = ethers.Wallet.createRandom().connect(provider); let transferTx = await wallet.sendTransaction({ to: capacityCreditWallet.address, From a73ccee8798302a408f49a3a6da42569b99da268 Mon Sep 17 00:00:00 2001 From: Bean Date: Thu, 23 May 2024 09:45:38 -0400 Subject: [PATCH 195/263] Apply suggestions from code review Co-authored-by: Anson Signed-off-by: Bean --- local-tests/setup/tinny-environment.ts | 3 ++- local-tests/setup/tinny-person.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 29078bded2..046a9b5a55 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -334,7 +334,7 @@ export class TinnyEnvironment { // There is a correlation between the number of Capacity Credit NFTs in a wallet and the speed at which nodes can verify a given rate limit authorization. Creating a single wallet to hold all Capacity Credit NFTs improves network performance during tests. const capacityCreditWallet = ethers.Wallet.createRandom().connect(provider); - let transferTx = await wallet.sendTransaction({ + const transferTx = await wallet.sendTransaction({ to: capacityCreditWallet.address, value: ethers.utils.parseEther('0.001'), }); @@ -381,6 +381,7 @@ export class TinnyEnvironment { await this.litNodeClient.createCapacityDelegationAuthSig({ dAppOwnerWallet: wallet, capacityTokenId: capacityTokenId, + // Sets a maximum limit of 200 times that the delegation can be used and prevents usage beyond it uses: '200', }) ).capacityDelegationAuthSig; diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index 0e89449155..ae17c51e4d 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -51,8 +51,8 @@ export class TinnyPerson { } async spawn() { - let fundingWallet = ethers.Wallet.createRandom(); - fundingWallet = new ethers.Wallet(fundingWallet.privateKey, this.provider); + // Create a new funding wallet, funds it with small amount of ethers, and updates the current wallet to the new one. + const fundingWallet = ethers.Wallet.createRandom().connect(this.provider); const transferTx = await this.wallet.sendTransaction({ to: fundingWallet.address, From 61898ec3cc9becaf45df29254c3d8c00cc72bcca Mon Sep 17 00:00:00 2001 From: Anson Date: Thu, 23 May 2024 14:52:48 +0100 Subject: [PATCH 196/263] Update local-tests/setup/tinny-environment.ts Signed-off-by: Anson --- local-tests/setup/tinny-environment.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 046a9b5a55..dbfb2cd82e 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -330,7 +330,6 @@ export class TinnyEnvironment { const wallet = new ethers.Wallet(privateKey.privateKey, provider); // TODO: This wallet should be cached somehwere and reused to create delegation signatures. -```suggestion // There is a correlation between the number of Capacity Credit NFTs in a wallet and the speed at which nodes can verify a given rate limit authorization. Creating a single wallet to hold all Capacity Credit NFTs improves network performance during tests. const capacityCreditWallet = ethers.Wallet.createRandom().connect(provider); From 34bb874c3a6767d7d6747b8f49fd71448e5d2a9a Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 23 May 2024 13:10:05 -0400 Subject: [PATCH 197/263] chore: fix typo. --- local-tests/setup/tinny-environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 5f7c2b1696..e02e6cf9dc 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -217,7 +217,7 @@ export class TinnyEnvironment { if (globalThis.wasmExports) { console.warn( - 'WASM modules already loaded. wil overide. when connect is called' + 'WASM modules already loaded. Will overide when connect is called' ); } From 5e426d01732857345dd7d00cc36c6febeaf9ba95 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:25:23 +0100 Subject: [PATCH 198/263] chore: remove unsued function `generateAuthMethodForWebAuthn` --- .../src/lib/lit-node-client-nodejs.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 7de8e88308..a0030435af 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2281,13 +2281,6 @@ export class LitNodeClientNodeJs }); }; - generateAuthMethodForWebAuthn = ( - params: WebAuthnAuthenticationVerificationParams - ): AuthMethod => ({ - authMethodType: AUTH_METHOD_TYPE_IDS.WEBAUTHN, - accessToken: JSON.stringify(params), - }); - generateAuthMethodForDiscord = (access_token: string): AuthMethod => ({ authMethodType: AUTH_METHOD_TYPE_IDS.DISCORD, accessToken: access_token, From 0b6e373c72a86fe9e9ad5a718f6db5a06567bdeb Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:25:43 +0100 Subject: [PATCH 199/263] chore: remove unused function `generateAuthMethodForDiscord` --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index a0030435af..56bc6bddad 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2281,11 +2281,6 @@ export class LitNodeClientNodeJs }); }; - generateAuthMethodForDiscord = (access_token: string): AuthMethod => ({ - authMethodType: AUTH_METHOD_TYPE_IDS.DISCORD, - accessToken: access_token, - }); - generateAuthMethodForGoogle = (access_token: string): AuthMethod => ({ authMethodType: AUTH_METHOD_TYPE_IDS.GOOGLE, accessToken: access_token, From 76e0d8c13368b809590544438527a1c85063f859 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:26:00 +0100 Subject: [PATCH 200/263] chore: remove unused function `generateAuthMethodForGoogle` --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 56bc6bddad..5d5dfafac1 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2281,11 +2281,6 @@ export class LitNodeClientNodeJs }); }; - generateAuthMethodForGoogle = (access_token: string): AuthMethod => ({ - authMethodType: AUTH_METHOD_TYPE_IDS.GOOGLE, - accessToken: access_token, - }); - generateAuthMethodForGoogleJWT = (access_token: string): AuthMethod => ({ authMethodType: AUTH_METHOD_TYPE_IDS.GOOGLE_JWT, accessToken: access_token, From cf7e2ac6cfc332009c858d5426c05b74800eec36 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:26:18 +0100 Subject: [PATCH 201/263] chore: remove unused function `generateAuthMethodForGoogleJWT` --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 5d5dfafac1..e3fc9c035a 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2281,11 +2281,6 @@ export class LitNodeClientNodeJs }); }; - generateAuthMethodForGoogleJWT = (access_token: string): AuthMethod => ({ - authMethodType: AUTH_METHOD_TYPE_IDS.GOOGLE_JWT, - accessToken: access_token, - }); - /** * Get session signatures for a set of resources * From f14acebabd408cfb4f82c7f35669ccdb6e416216 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:44:17 +0100 Subject: [PATCH 202/263] refactor(claimKeyId): remove `getClaimKeyExecutionShares` and add type for request --- .../src/lib/lit-node-client-nodejs.ts | 37 +++++++------------ packages/types/src/index.ts | 1 + .../lib/node-interfaces/node-interfaces.ts | 14 +++++++ 3 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 packages/types/src/lib/node-interfaces/node-interfaces.ts diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 7de8e88308..4b55edf42e 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -118,6 +118,7 @@ import type { JsonPkpSignSdkParams, SigResponse, EncryptSdkParams, + JsonPKPClaimKeyRequest, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; @@ -568,26 +569,6 @@ export class LitNodeClientNodeJs }; // ==================== API Calls to Nodes ==================== - getClaimKeyExecutionShares = async ( - url: string, - params: any, - requestId: string - ) => { - logWithRequestId(requestId, 'getPkpSigningShares'); - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.PKP_CLAIM, - }); - if (!params.authMethod) { - throw new Error('authMethod is required'); - } - - return await this.sendCommandToNode({ - url: urlWithPath, - data: params, - requestId, - }); - }; /** * Get Signing Shares for Token containing Access Control Condition @@ -2588,11 +2569,21 @@ const resourceAbilityRequests = [ const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = await this.getNodePromises((url: string) => { - const nodeRequestParams = { + const nodePromises = this.getNodePromises((url: string) => { + if (!params.authMethod) { + throw new Error('authMethod is required'); + } + + const reqBody: JsonPKPClaimKeyRequest = { authMethod: params.authMethod, }; - return this.getClaimKeyExecutionShares(url, nodeRequestParams, id); + + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.PKP_CLAIM, + }); + + return this.generatePromise(urlWithPath, reqBody, id); }); const responseData = await this.handleNodePromises( diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index f80142dc7e..a5fa52c539 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -2,3 +2,4 @@ export * from './lib/types'; export * from './lib/interfaces'; export * from './lib/ILitNodeClient'; export * from './lib/models'; +export * from './lib/node-interfaces/node-interfaces'; diff --git a/packages/types/src/lib/node-interfaces/node-interfaces.ts b/packages/types/src/lib/node-interfaces/node-interfaces.ts new file mode 100644 index 0000000000..e890a4bbc5 --- /dev/null +++ b/packages/types/src/lib/node-interfaces/node-interfaces.ts @@ -0,0 +1,14 @@ +/** + * This file serves as a central location for all Lit node endpoints and their request/response interfaces & types. + */ + +import { AuthMethod } from '../interfaces'; + +// pub struct JsonPKPClaimKeyRequest { +// pub auth_method: AuthMethod, +// pub credential_public_key: Option, +// } +export interface JsonPKPClaimKeyRequest { + authMethod: AuthMethod; + credentialPublicKey?: string | null; +} From 3adeacc5d5d5cb2b0dc652f012d23277231ee2e6 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:51:01 +0100 Subject: [PATCH 203/263] refactor(getSignedToken): remove `getSigningShareForToken` and add `SigningAccessControlConditionRequest` type --- .../src/lib/lit-node-client-nodejs.ts | 59 ++++++------------- packages/types/src/lib/ILitNodeClient.ts | 15 ----- .../lib/node-interfaces/node-interfaces.ts | 32 +++++++++- 3 files changed, 48 insertions(+), 58 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 4b55edf42e..bd729d712c 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -570,34 +570,6 @@ export class LitNodeClientNodeJs // ==================== API Calls to Nodes ==================== - /** - * Get Signing Shares for Token containing Access Control Condition - * - * @param { string } url - * @param { SigningAccessControlConditionRequest } params - * - * @returns { Promise } - * - */ - getSigningShareForToken = async ( - url: string, - params: SigningAccessControlConditionRequest, - requestId: string - ): Promise => { - logWithRequestId(requestId, 'getSigningShareForToken'); - - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.SIGN_ACCS, - }); - - return this.sendCommandToNode({ - url: urlWithPath, - data: params, - requestId, - }); - }; - /** * * Get signature shares for decryption. @@ -1475,21 +1447,24 @@ export class LitNodeClientNodeJs // -- if session key is available, use it const authSigToSend = sessionSigs ? sessionSigs[url] : authSig; - return this.getSigningShareForToken( + const reqBody: SigningAccessControlConditionRequest = { + accessControlConditions: formattedAccessControlConditions, + evmContractConditions: formattedEVMContractConditions, + solRpcConditions: formattedSolRpcConditions, + unifiedAccessControlConditions: + formattedUnifiedAccessControlConditions, + chain, + authSig: authSigToSend, + iat, + exp, + }; + + const urlWithPath = composeLitUrl({ url, - { - accessControlConditions: formattedAccessControlConditions, - evmContractConditions: formattedEVMContractConditions, - solRpcConditions: formattedSolRpcConditions, - unifiedAccessControlConditions: - formattedUnifiedAccessControlConditions, - chain, - authSig: authSigToSend, - iat, - exp, - }, - id - ); + endpoint: LIT_ENDPOINT.SIGN_ACCS, + }); + + return this.generatePromise(urlWithPath, reqBody, id); }); // -- resolve promises diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index acdfa00890..3137b5206c 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -159,21 +159,6 @@ export interface ILitNodeClient { * @returns { Promise } */ - /** - * Get Signing Shares for Token containing Access Control Condition - * - * @param { string } url - * @param { SigningAccessControlConditionRequest } params - * - * @returns { Promise } - * - */ - getSigningShareForToken( - url: string, - params: SigningAccessControlConditionRequest, - requestId: string - ): Promise; - /** * * Sign Condition ECDSA diff --git a/packages/types/src/lib/node-interfaces/node-interfaces.ts b/packages/types/src/lib/node-interfaces/node-interfaces.ts index e890a4bbc5..9bf79d4738 100644 --- a/packages/types/src/lib/node-interfaces/node-interfaces.ts +++ b/packages/types/src/lib/node-interfaces/node-interfaces.ts @@ -2,7 +2,13 @@ * This file serves as a central location for all Lit node endpoints and their request/response interfaces & types. */ -import { AuthMethod } from '../interfaces'; +import { AuthMethod, AuthSig } from '../interfaces'; +import { + AccessControlConditions, + EvmContractConditions, + SolRpcConditions, + UnifiedAccessControlConditions, +} from '../types'; // pub struct JsonPKPClaimKeyRequest { // pub auth_method: AuthMethod, @@ -12,3 +18,27 @@ export interface JsonPKPClaimKeyRequest { authMethod: AuthMethod; credentialPublicKey?: string | null; } + +// pub struct SigningAccessControlConditionRequest { +// pub access_control_conditions: Option>, +// pub evm_contract_conditions: Option>, +// pub sol_rpc_conditions: Option>, +// pub unified_access_control_conditions: Option>, +// pub chain: Option, +// pub auth_sig: AuthSigItem, +// pub iat: u64, +// pub exp: u64, +// #[serde(default = "default_epoch")] +// pub epoch: u64, +// } +export interface SigningAccessControlConditionRequest { + accessControlConditions?: AccessControlConditions[]; + evmContractConditions?: EvmContractConditions[]; + solRpcConditions?: SolRpcConditions[]; + unifiedAccessControlConditions?: UnifiedAccessControlConditions[]; + chain?: string | null; + authSig: AuthSig; + iat: number; + exp: number; + epoch: number; +} From 907a0a28d6610fa2917735beb71ad9673e01fd04 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 15:55:41 +0100 Subject: [PATCH 204/263] refactor(decrypt): remove `getSigningShareForDecryption` and add `EncryptionSignRequest` type of request --- .../src/lib/lit-node-client-nodejs.ts | 67 +++++++------------ .../lib/node-interfaces/node-interfaces.ts | 22 ++++++ 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index bd729d712c..fe703abdce 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -119,6 +119,7 @@ import type { SigResponse, EncryptSdkParams, JsonPKPClaimKeyRequest, + EncryptionSignRequest, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; @@ -570,34 +571,6 @@ export class LitNodeClientNodeJs // ==================== API Calls to Nodes ==================== - /** - * - * Get signature shares for decryption. - * - * @param url - * @param params - * @param requestId - * @returns - */ - getSigningShareForDecryption = async ( - url: string, - params: GetSigningShareForDecryptionRequest, - requestId: string - ): Promise => { - log('getSigningShareForDecryption'); - - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.ENCRYPTION_SIGN, - }); - - return await this.sendCommandToNode({ - url: urlWithPath, - data: params, - requestId, - }); - }; - /** * * Sign Condition ECDSA @@ -1703,20 +1676,32 @@ export class LitNodeClientNodeJs // -- if session key is available, use it const authSigToSend = sessionSigs ? sessionSigs[url] : params.authSig; - return this.getSigningShareForDecryption( + if (!authSigToSend) { + return throwError({ + message: `authSig is required`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); + } + + const reqBody: EncryptionSignRequest = { + accessControlConditions: formattedAccessControlConditions, + evmContractConditions: formattedEVMContractConditions, + solRpcConditions: formattedSolRpcConditions, + unifiedAccessControlConditions: + formattedUnifiedAccessControlConditions, + dataToEncryptHash, + chain, + authSig: authSigToSend, + epoch: this.currentEpochNumber!, + }; + + const urlWithParh = composeLitUrl({ url, - { - accessControlConditions: formattedAccessControlConditions, - evmContractConditions: formattedEVMContractConditions, - solRpcConditions: formattedSolRpcConditions, - unifiedAccessControlConditions: - formattedUnifiedAccessControlConditions, - dataToEncryptHash, - chain, - authSig: authSigToSend, - }, - id - ); + endpoint: LIT_ENDPOINT.ENCRYPTION_SIGN, + }); + + return this.generatePromise(urlWithParh, reqBody, id); }); // -- resolve promises diff --git a/packages/types/src/lib/node-interfaces/node-interfaces.ts b/packages/types/src/lib/node-interfaces/node-interfaces.ts index 9bf79d4738..369e8ce1fe 100644 --- a/packages/types/src/lib/node-interfaces/node-interfaces.ts +++ b/packages/types/src/lib/node-interfaces/node-interfaces.ts @@ -42,3 +42,25 @@ export interface SigningAccessControlConditionRequest { exp: number; epoch: number; } + +// pub struct EncryptionSignRequest { +// pub access_control_conditions: Option>, +// pub evm_contract_conditions: Option>, +// pub sol_rpc_conditions: Option>, +// pub unified_access_control_conditions: Option>, +// pub chain: Option, +// pub data_to_encrypt_hash: String, +// pub auth_sig: AuthSigItem, +// #[serde(default = "default_epoch")] +// pub epoch: u64, +// } +export interface EncryptionSignRequest { + accessControlConditions?: AccessControlConditions[]; + evmContractConditions?: EvmContractConditions[]; + solRpcConditions?: SolRpcConditions[]; + unifiedAccessControlConditions?: UnifiedAccessControlConditions[]; + chain?: string | null; + dataToEncryptHash: string; + authSig: AuthSig; + epoch: number; +} From 23be35b45d133c9eb9f8ceed39c59dec33e4d775 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 16:02:43 +0100 Subject: [PATCH 205/263] chore: endpoint `/web/signing/signConditionEcdsa` doesn't exist. Removed all related functionalities --- .../constants/src/lib/constants/endpoints.ts | 4 - .../src/lib/lit-node-client-nodejs.ts | 170 ------------------ packages/types/src/lib/ILitNodeClient.ts | 43 ----- packages/types/src/lib/interfaces.ts | 15 -- 4 files changed, 232 deletions(-) diff --git a/packages/constants/src/lib/constants/endpoints.ts b/packages/constants/src/lib/constants/endpoints.ts index be29b214d6..3672dce5df 100644 --- a/packages/constants/src/lib/constants/endpoints.ts +++ b/packages/constants/src/lib/constants/endpoints.ts @@ -32,8 +32,4 @@ export const LIT_ENDPOINT = { path: '/web/encryption/sign', version: LIT_ENDPOINT_VERSION.V0, }, - SIGN_ECDSA: { - path: '/web/signing/signConditionEcdsa', - version: LIT_ENDPOINT_VERSION.V0, - }, }; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index fe703abdce..9bdfe6b43b 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -97,13 +97,11 @@ import type { SessionSigningTemplate, SessionSigsMap, SigShare, - SignConditionECDSA, SignSessionKeyProp, SignSessionKeyResponse, Signature, SigningAccessControlConditionRequest, SuccessNodePromises, - ValidateAndSignECDSA, WebAuthnAuthenticationVerificationParams, ILitNodeClient, GetPkpSessionSigs, @@ -571,61 +569,6 @@ export class LitNodeClientNodeJs // ==================== API Calls to Nodes ==================== - /** - * - * Sign Condition ECDSA - * - * @param { string } url - * @param { SignConditionECDSA } params - * - * @returns { Promise } - * - */ - signConditionEcdsa = async ( - url: string, - params: SignConditionECDSA, - requestId: string - ): Promise => { - const wrapper = async ( - id: string - ): Promise | RejectedNodePromises> => { - log('signConditionEcdsa'); - - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.SIGN_ECDSA, - }); - - const data = { - access_control_conditions: params.accessControlConditions, - evmContractConditions: params.evmContractConditions, - solRpcConditions: params.solRpcConditions, - auth_sig: params.auth_sig, - chain: params.chain, - iat: params.iat, - exp: params.exp, - }; - - return await this.sendCommandToNode({ - url: urlWithPath, - data, - requestId: id, - }); - }; - - const res = await executeWithRetry( - wrapper, - (_error: any, _requestid: string, isFinal: boolean) => { - if (!isFinal) { - logError('An error occured. attempting to retry: '); - } - }, - this.config.retryTolerance - ); - - return res as unknown as NodeCommandResponse; - }; - /** * * Combine Shares from network public key set and signature shares @@ -1793,119 +1736,6 @@ export class LitNodeClientNodeJs ).getResourceKey(); }; - /** - * - * Validates a condition, and then signs the condition if the validation returns true. - * Before calling this function, you must know the on chain conditions that you wish to validate. - * - * @param { ValidateAndSignECDSA } params - * - * @returns { Promise } - */ - validateAndSignEcdsa = async ( - params: ValidateAndSignECDSA - ): Promise => { - // ========== Validate Params ========== - // -- validate if it's ready - if (!this.ready) { - const message = - '7 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; - throwError({ - message, - errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, - errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, - }); - } - - // ========== Prepare Params ========== - const { accessControlConditions, chain, auth_sig } = params; - - // ========== Prepare JWT Params ========== - // we need to send jwt params iat (issued at) and exp (expiration) - // because the nodes may have different wall clock times - // the nodes will verify that these params are withing a grace period - const { iat, exp } = this.getJWTParams(); - - // -- validate - if (!accessControlConditions) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } - - // -- formatted access control conditions - let formattedAccessControlConditions: any; - - formattedAccessControlConditions = accessControlConditions.map((c: any) => - canonicalAccessControlConditionFormatter(c) - ); - log( - 'formattedAccessControlConditions', - JSON.stringify(formattedAccessControlConditions) - ); - - // ========== Node Promises ========== - const wrapper = async ( - id: string - ): Promise> => { - const nodePromises = this.getNodePromises((url: string) => { - return this.signConditionEcdsa( - url, - { - accessControlConditions: formattedAccessControlConditions, - evmContractConditions: undefined, - solRpcConditions: undefined, - auth_sig, - chain, - iat, - exp, - }, - id - ); - }); - - // ----- Resolve Promises ----- - const responses = await this.handleNodePromises( - nodePromises, - id, - this.connectedNodes.size - ); - - return responses; - }; - - const res = await executeWithRetry< - RejectedNodePromises | SuccessNodePromises - >( - wrapper, - (_error: any, _requestId: string, isFinal: boolean) => { - if (!isFinal) { - logError('an error has occured, attempting to retry '); - } - }, - this.config.retryTolerance - ); - - const requestId = res.requestId; - // return the first value as this will be the signature data - try { - if (res.success === false) { - return 'Condition Failed'; - } - const shareData = (res as SuccessNodePromises).values; - const signature = this.getSignature(shareData, requestId); - return signature; - } catch (e) { - logErrorWithRequestId(requestId, 'Error - signed_ecdsa_messages - ', e); - const signed_ecdsa_message = res as RejectedNodePromises; - // have to cast to any to keep with above `string` return value - // this will be returned as `RejectedNodePromise` - return signed_ecdsa_message as any; - } - }; - /** ============================== SESSION ============================== */ /** diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 3137b5206c..0f8b3646b0 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -17,10 +17,7 @@ import { NodeCommandServerKeysResponse, RejectedNodePromises, SendNodeCommand, - SignConditionECDSA, - SigningAccessControlConditionRequest, SuccessNodePromises, - ValidateAndSignECDSA, } from './interfaces'; import { ILitResource, ISessionCapabilityObject } from './models'; import { SupportedJsonRequests } from './types'; @@ -159,22 +156,6 @@ export interface ILitNodeClient { * @returns { Promise } */ - /** - * - * Sign Condition ECDSA - * - * @param { string } url - * @param { SignConditionECDSA } params - * - * @returns { Promise } - * - */ - signConditionEcdsa( - url: string, - params: SignConditionECDSA, - requestId: string - ): Promise; - /** * * Handshake with SGX @@ -228,30 +209,6 @@ export interface ILitNodeClient { */ decrypt(params: DecryptRequest): Promise; - /** - * - * Signs a message with Lit threshold ECDSA algorithms. - * - * @param { `SignWithECDSA } params - * - * @returns { Promise } - * - */ - // signWithEcdsa(params: SignWithECDSA): Promise; - - /** - * - * Validates a condition, and then signs the condition if the validation returns true. - * Before calling this function, you must know the on chain conditions that you wish to validate. - * - * @param { ValidateAndSignECDSA } params - * - * @returns { Promise } - */ - validateAndSignEcdsa( - params: ValidateAndSignECDSA - ): Promise; - /** * * Connect to the LIT nodes diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 24d0044a96..e2c3d104eb 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -624,16 +624,6 @@ export interface GetSigningShareForDecryptionRequest extends JsonAccsRequest { dataToEncryptHash: string; } -export interface SignConditionECDSA { - accessControlConditions: any; - evmContractConditions: undefined; - solRpcConditions: undefined; - auth_sig: AuthSig; - chain: Chain; - iat: number; - exp: number; -} - export interface SigResponse { r: string; s: string; @@ -879,11 +869,6 @@ export interface CombinedECDSASignature { s: string; recid: number; } -export interface ValidateAndSignECDSA { - accessControlConditions: AccessControlConditions; - chain: Chain; - auth_sig: AuthSig; -} export interface HandshakeWithNode { url: string; From 2b52ad70dd4cfb8b7f972f54252c79dfedd252ee Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 16:07:14 +0100 Subject: [PATCH 206/263] refactor(signSessionKey): remove `getSignSessionKeyShares` --- .../src/lib/lit-node-client-nodejs.ts | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 9bdfe6b43b..5f3282b82c 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -79,9 +79,7 @@ import type { ExecuteJsResponse, FormattedMultipleAccs, GetSessionSigsProps, - GetSignSessionKeySharesProp, GetSignedTokenRequest, - GetSigningShareForDecryptionRequest, GetWalletSigProps, JsonExecutionRequest, JsonPkpSignRequest, @@ -1847,13 +1845,14 @@ export class LitNodeClientNodeJs ): Promise | RejectedNodePromises> => { logWithRequestId(id, 'signSessionKey body', body); const nodePromises = this.getNodePromises((url: string) => { - return this.getSignSessionKeyShares( + const reqBody: JsonSignSessionKeyRequestV1 = body; + + const urlWithPath = composeLitUrl({ url, - { - body, - }, - id - ); + endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, + }); + + return this.generatePromise(urlWithPath, reqBody, id); }); // -- resolve promises @@ -2035,23 +2034,6 @@ export class LitNodeClientNodeJs return res.success === true; }; - getSignSessionKeyShares = async ( - url: string, - params: GetSignSessionKeySharesProp, - requestId: string - ) => { - log('getSignSessionKeyShares'); - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, - }); - return await this.sendCommandToNode({ - url: urlWithPath, - data: params.body, - requestId, - }); - }; - generateAuthMethodForWebAuthn = ( params: WebAuthnAuthenticationVerificationParams ): AuthMethod => ({ From 90acf3bef04f99a66f82041b64e8ecef78c2d5dd Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 16:10:41 +0100 Subject: [PATCH 207/263] chore: remove unused imports --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 5f3282b82c..8603f58780 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -3,7 +3,6 @@ import { BigNumber, ethers } from 'ethers'; import { joinSignature, sha256 } from 'ethers/lib/utils'; import { SiweMessage } from 'siwe'; -import { canonicalAccessControlConditionFormatter } from '@lit-protocol/access-control-conditions'; import { ILitResource, ISessionCapabilityObject, @@ -50,7 +49,6 @@ import { normalizeAndStringify, removeHexPrefix, throwError, - throwErrorV1, } from '@lit-protocol/misc'; import { getStorageItem, From 24d3202769382e41ff3a17a1eef130d51e9862d8 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 16:18:11 +0100 Subject: [PATCH 208/263] fix: remove duplicated interface --- packages/types/src/lib/interfaces.ts | 13 +--------- .../lib/node-interfaces/node-interfaces.ts | 26 +++++++++++-------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index e2c3d104eb..17418f6825 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -19,6 +19,7 @@ import { UnifiedAccessControlConditions, } from './types'; import { ISessionCapabilityObject, LitResourceAbilityRequest } from './models'; +import { SigningAccessControlConditionRequest } from './node-interfaces/node-interfaces'; /** ---------- Access Control Conditions Interfaces ---------- */ export interface ABIParams { @@ -437,18 +438,6 @@ export interface GetSignedTokenRequest sessionSigs: SessionSigsMap; } -export interface SigningAccessControlConditionRequest - extends MultipleAccessControlConditions { - // The chain name of the chain that you are querying. See ALL_LIT_CHAINS for currently supported chains. - chain?: string; - - // The authentication signature that proves that the user owns the crypto wallet address that meets the access control conditions - authSig?: AuthSig; - - iat?: number; - exp?: number; -} - /** * Struct in rust * ----- diff --git a/packages/types/src/lib/node-interfaces/node-interfaces.ts b/packages/types/src/lib/node-interfaces/node-interfaces.ts index 369e8ce1fe..3c049230f8 100644 --- a/packages/types/src/lib/node-interfaces/node-interfaces.ts +++ b/packages/types/src/lib/node-interfaces/node-interfaces.ts @@ -2,7 +2,11 @@ * This file serves as a central location for all Lit node endpoints and their request/response interfaces & types. */ -import { AuthMethod, AuthSig } from '../interfaces'; +import { + AuthMethod, + AuthSig, + MultipleAccessControlConditions, +} from '../interfaces'; import { AccessControlConditions, EvmContractConditions, @@ -31,16 +35,16 @@ export interface JsonPKPClaimKeyRequest { // #[serde(default = "default_epoch")] // pub epoch: u64, // } -export interface SigningAccessControlConditionRequest { - accessControlConditions?: AccessControlConditions[]; - evmContractConditions?: EvmContractConditions[]; - solRpcConditions?: SolRpcConditions[]; - unifiedAccessControlConditions?: UnifiedAccessControlConditions[]; - chain?: string | null; - authSig: AuthSig; - iat: number; - exp: number; - epoch: number; +export interface SigningAccessControlConditionRequest + extends MultipleAccessControlConditions { + // The chain name of the chain that you are querying. See ALL_LIT_CHAINS for currently supported chains. + chain?: string; + + // The authentication signature that proves that the user owns the crypto wallet address that meets the access control conditions + authSig?: AuthSig; + + iat?: number; + exp?: number; } // pub struct EncryptionSignRequest { From 2e9173b9e3e241b2f7274c97359ea3ff16dd1469 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 16:27:20 +0100 Subject: [PATCH 209/263] fix(tinny): `localchain` should have higher amount of LIT token --- local-tests/setup/tinny-person.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index ae17c51e4d..6dae8edf36 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -54,9 +54,14 @@ export class TinnyPerson { // Create a new funding wallet, funds it with small amount of ethers, and updates the current wallet to the new one. const fundingWallet = ethers.Wallet.createRandom().connect(this.provider); + const amount = + this.envConfig.processEnvs.NETWORK === LIT_TESTNET.LOCALCHAIN + ? '0.1' + : '0.0001'; + const transferTx = await this.wallet.sendTransaction({ to: fundingWallet.address, - value: ethers.utils.parseEther('0.00001'), + value: ethers.utils.parseEther(amount), }); const transferReciept = await transferTx.wait(); From 858a52fc6cbefce823cb0b87ac392220da2ac03c Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 16:55:22 +0100 Subject: [PATCH 210/263] fix(contracts-sdk): ensure provided provider and signer instances are used Resolves an issue where a provided signer or provider instance given to LitContracts was not being used, instead defaulting to a new provider with Chronicle RPC URL. This fix prioritizes the provided instances in the constructor arguments. --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 0cfb898cdd..eb07d39b2d 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -239,8 +239,9 @@ export class LitContracts { // ------------------------------------------------- let wallet; let SETUP_DONE = false; - - if (isBrowser() && !this.signer) { + if (this.provider) { + this.log('Using provided provider'); + } else if (isBrowser() && !this.signer) { this.log("----- We're in the browser! -----"); const web3Provider = window.ethereum; @@ -285,7 +286,7 @@ export class LitContracts { // ---------------------------------------------- // (Node) Setting up Provider // ---------------------------------------------- - if (isNode()) { + else if (isNode()) { this.log("----- We're in node! -----"); this.provider = new ethers.providers.JsonRpcProvider(this.rpc); } From c40784c69ddc80bf9f896e7b1f118819b5ec155f Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 24 May 2024 23:23:10 +0100 Subject: [PATCH 211/263] Update packages/crypto/src/lib/crypto.ts Signed-off-by: Anson --- packages/crypto/src/lib/crypto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/lib/crypto.ts b/packages/crypto/src/lib/crypto.ts index b99e6afe36..95a4984506 100644 --- a/packages/crypto/src/lib/crypto.ts +++ b/packages/crypto/src/lib/crypto.ts @@ -27,7 +27,7 @@ export interface BlsSignatureShare { } /** - Loads all wasm modules into the glboal scope + Loads all wasm modules into the global scope - ECDSA utilities - wasmECDSA - BLS utilities - wasmExports From 17b0f697cedbe2b6c085e315d4ca222bfc17d2cc Mon Sep 17 00:00:00 2001 From: Josh Long Date: Sat, 25 May 2024 08:35:41 -0400 Subject: [PATCH 212/263] Publish 6.0.0-beta.4 --- lerna.json | 2 +- .../access-control-conditions/package.json | 4 +-- packages/auth-browser/package.json | 4 +-- packages/auth-helpers/package.json | 4 +-- packages/bls-sdk/package.json | 4 +-- packages/constants/package.json | 4 +-- .../src/lib/constants/autogen_internal.ts | 26 +++++++++++++++++-- packages/constants/src/lib/version.ts | 2 +- packages/contracts-sdk/package.json | 4 +-- packages/core/package.json | 4 +-- packages/crypto/package.json | 4 +-- packages/ecdsa-sdk/package.json | 4 +-- packages/encryption/package.json | 4 +-- packages/lit-auth-client/package.json | 4 +-- packages/lit-node-client-nodejs/package.json | 4 +-- packages/lit-node-client/package.json | 4 +-- packages/logger/package.json | 4 +-- packages/misc-browser/package.json | 4 +-- packages/misc/package.json | 4 +-- packages/nacl/package.json | 4 +-- packages/pkp-base/package.json | 4 +-- packages/pkp-client/package.json | 4 +-- packages/pkp-cosmos/package.json | 4 +-- packages/pkp-ethers/package.json | 4 +-- packages/pkp-sui/package.json | 4 +-- packages/pkp-walletconnect/package.json | 4 +-- packages/sev-snp-utils-sdk/package.json | 4 +-- packages/types/package.json | 4 +-- packages/uint8arrays/package.json | 4 +-- 29 files changed, 78 insertions(+), 56 deletions(-) diff --git a/lerna.json b/lerna.json index 54be8ed37a..0a888f9cfd 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "useNx": true, "useWorkspaces": true, - "version": "6.0.0-beta.3" + "version": "6.0.0-beta.4" } diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 4fce19b65c..594d70c080 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index f794eb69a2..cdd46fcd95 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -30,7 +30,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index deb26a2b0f..5323abd039 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index ddc27357ad..59e82b4e2d 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/package.json b/packages/constants/package.json index 0784fc0f54..c80a36d025 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/src/lib/constants/autogen_internal.ts b/packages/constants/src/lib/constants/autogen_internal.ts index a7ba16f7be..8e0ea60db6 100644 --- a/packages/constants/src/lib/constants/autogen_internal.ts +++ b/packages/constants/src/lib/constants/autogen_internal.ts @@ -1,5 +1,16 @@ // This file is auto-generated by tools/scripts/gen-internal-dev.mjs -export const INTERNAL_DEV = []; +export const INTERNAL_DEV = [ + 'https://167.114.17.201:443', + 'https://199.115.117.113:443', + 'https://167.114.17.202:443', + 'https://167.114.17.205:443', + 'https://167.114.17.203:443', + 'https://108.62.0.105:443', + 'https://199.115.117.115:443', + 'https://64.131.85.106:443', + 'https://167.114.17.204:443', + 'https://64.131.85.108:443', +]; export const INTERNAL_MIN_NODE_COUNT = 2; @@ -7,7 +18,18 @@ export const INTERNAL_DEFAULT_CONFIG = { alertWhenUnauthorized: false, minNodeCount: 2, debug: true, - bootstrapUrls: [], + bootstrapUrls: [ + 'https://167.114.17.201:443', + 'https://199.115.117.113:443', + 'https://167.114.17.202:443', + 'https://167.114.17.205:443', + 'https://167.114.17.203:443', + 'https://108.62.0.105:443', + 'https://199.115.117.115:443', + 'https://64.131.85.106:443', + 'https://167.114.17.204:443', + 'https://64.131.85.108:443', + ], litNetwork: 'internalDev', connectTimeout: 20000, }; diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index adda30ba16..1b8c7c6e9e 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = '6.0.0-beta.3'; +export const version = '6.0.0-beta.4'; diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index de40bb1fbd..fd1307fbdd 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -32,7 +32,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 8d8852390d..a15a90a5ad 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/core", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/crypto/package.json b/packages/crypto/package.json index b17bb3b183..0f7fb92fdb 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index 67af205aac..9010474635 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/encryption/package.json b/packages/encryption/package.json index a9240fb16e..a130f7e1b8 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index a7634fb6ca..473d1ba5ab 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/lit-auth-client", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 7963cdfc57..eabac6079d 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -24,7 +24,7 @@ "tags": [ "nodejs" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index 2d97db8555..3096768dd7 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/logger/package.json b/packages/logger/package.json index 54c0938f6d..1186846d78 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/logger", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "tags": [ "universal" @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 80f5f510c9..f1a581723c 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -21,7 +21,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc/package.json b/packages/misc/package.json index ddb23d255d..7b77d60ff2 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 267827e308..a045ab6466 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -21,7 +21,7 @@ "access": "public", "directory": "../../dist/packages/nacl" }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 6d2b3cc936..946b5c9eda 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-base", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index cbd91dcaad..8fea907c22 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-client", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 20b26cb17e..56a93f4ce9 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-cosmos", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 9d19666bb6..0ffc19b5c2 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 77bae01bdf..9c3a0c31ce 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-sui", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 6e7da327f2..e4eab22b82 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-walletconnect", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 09fd9ff702..0b8872d5e7 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/types/package.json b/packages/types/package.json index bb4c9bc89d..6ed554a5cb 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -23,7 +23,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index f69393b79c..f313906f38 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file From 03a4afbae1619af368eaab2557cceafd0edc9f03 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Sat, 25 May 2024 08:48:28 -0400 Subject: [PATCH 213/263] fix(tinny): fix localchain minting --- local-tests/setup/tinny-environment.ts | 21 ++++++++++----------- local-tests/setup/tinny-person.ts | 25 +++++++++++++------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 818379ae11..0265bbe44d 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -347,16 +347,6 @@ export class TinnyEnvironment { const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc); const wallet = new ethers.Wallet(privateKey.privateKey, provider); - // TODO: This wallet should be cached somehwere and reused to create delegation signatures. - // There is a correlation between the number of Capacity Credit NFTs in a wallet and the speed at which nodes can verify a given rate limit authorization. Creating a single wallet to hold all Capacity Credit NFTs improves network performance during tests. - const capacityCreditWallet = ethers.Wallet.createRandom().connect(provider); - - const transferTx = await wallet.sendTransaction({ - to: capacityCreditWallet.address, - value: ethers.utils.parseEther('0.001'), - }); - await transferTx.wait(); - /** * ==================================== * Setup contracts-sdk client @@ -364,12 +354,21 @@ export class TinnyEnvironment { */ if (this.network === LIT_TESTNET.LOCALCHAIN) { this.contractsClient = new LitContracts({ - signer: capacityCreditWallet, + signer: wallet, debug: this.processEnvs.DEBUG, rpc: this.processEnvs.LIT_RPC_URL, // anvil rpc customContext: networkContext as unknown as LitContractContext, }); } else { + // TODO: This wallet should be cached somehwere and reused to create delegation signatures. + // There is a correlation between the number of Capacity Credit NFTs in a wallet and the speed at which nodes can verify a given rate limit authorization. Creating a single wallet to hold all Capacity Credit NFTs improves network performance during tests. + const capacityCreditWallet = ethers.Wallet.createRandom().connect(provider); + + const transferTx = await wallet.sendTransaction({ + to: capacityCreditWallet.address, + value: ethers.utils.parseEther('0.001'), + }); + await transferTx.wait(); this.contractsClient = new LitContracts({ signer: capacityCreditWallet, debug: this.processEnvs.DEBUG, diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index ae17c51e4d..c4d0f5032f 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -53,18 +53,19 @@ export class TinnyPerson { async spawn() { // Create a new funding wallet, funds it with small amount of ethers, and updates the current wallet to the new one. const fundingWallet = ethers.Wallet.createRandom().connect(this.provider); - - const transferTx = await this.wallet.sendTransaction({ - to: fundingWallet.address, - value: ethers.utils.parseEther('0.00001'), - }); - - const transferReciept = await transferTx.wait(); - console.log( - '[𐬺🧪 Tinny Person𐬺] Transfered Assets for person tx: ', - transferReciept.transactionHash - ); - this.wallet = fundingWallet; + if (this.envConfig.network != LIT_TESTNET.LOCALCHAIN) { + const transferTx = await this.wallet.sendTransaction({ + to: fundingWallet.address, + value: ethers.utils.parseEther('0.00001'), + }); + + const transferReciept = await transferTx.wait(); + console.log( + '[𐬺🧪 Tinny Person𐬺] Transfered Assets for person tx: ', + transferReciept.transactionHash + ); + this.wallet = fundingWallet; + } console.log('[𐬺🧪 Tinny Person𐬺] Spawning person:', this.wallet.address); /** From 9f001c4ce2e50fc6a2b64cbf2a9ed0a3ac036638 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Sat, 25 May 2024 09:00:06 -0400 Subject: [PATCH 214/263] chore: fmt --- local-tests/setup/tinny-environment.ts | 3 ++- local-tests/setup/tinny-person.ts | 2 +- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/contracts-sdk/package.json | 2 +- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- 28 files changed, 29 insertions(+), 28 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 0265bbe44d..65da822020 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -362,7 +362,8 @@ export class TinnyEnvironment { } else { // TODO: This wallet should be cached somehwere and reused to create delegation signatures. // There is a correlation between the number of Capacity Credit NFTs in a wallet and the speed at which nodes can verify a given rate limit authorization. Creating a single wallet to hold all Capacity Credit NFTs improves network performance during tests. - const capacityCreditWallet = ethers.Wallet.createRandom().connect(provider); + const capacityCreditWallet = + ethers.Wallet.createRandom().connect(provider); const transferTx = await wallet.sendTransaction({ to: capacityCreditWallet.address, diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index c4d0f5032f..e77044620f 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -58,7 +58,7 @@ export class TinnyPerson { to: fundingWallet.address, value: ethers.utils.parseEther('0.00001'), }); - + const transferReciept = await transferTx.wait(); console.log( '[𐬺🧪 Tinny Person𐬺] Transfered Assets for person tx: ', diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 594d70c080..80a3421371 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index cdd46fcd95..d4f77871b6 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 5323abd039..2f4a6e197e 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index 59e82b4e2d..c290e8cecd 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index c80a36d025..d25e77fb5e 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index fd1307fbdd..e6b9e53dfc 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/core/package.json b/packages/core/package.json index a15a90a5ad..aaf2261fbf 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 0f7fb92fdb..553e900121 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index 9010474635..faf66d11a3 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index a130f7e1b8..0281ef2b68 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index 473d1ba5ab..c52c0668c5 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index eabac6079d..6f60d9de64 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index 3096768dd7..65a42336a0 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index 1186846d78..1292dd2d08 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index f1a581723c..1bdaaf3d3f 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 7b77d60ff2..f13a758c4e 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index a045ab6466..237805d876 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 946b5c9eda..a71ab5d5f2 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 8fea907c22..dfbeb5eb4e 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 56a93f4ce9..666c99169f 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 0ffc19b5c2..f42b7b5e10 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 9c3a0c31ce..e12863949d 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index e4eab22b82..89381a89ac 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 0b8872d5e7..8c90087e31 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index 6ed554a5cb..2eae993602 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index f313906f38..2c5ea4435e 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-beta.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} From 84dda2a80cbe8fcb3a42a81a67233500501472c3 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 28 May 2024 17:43:05 -0400 Subject: [PATCH 215/263] ref: move to replica url from sequencer url for read ops --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index dcacf0560e..c7315a8797 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -67,6 +67,7 @@ import { import { AuthMethodScope, AuthMethodType } from '@lit-protocol/constants'; const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; +const DEFAULT_READ_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; const BLOCK_EXPLORER = 'https://chain.litprotocol.com/'; // This function asynchronously executes a provided callback function for each item in the given array. @@ -575,7 +576,7 @@ export class LitContracts { rpcUrl?: string ) { let provider: ethers.providers.JsonRpcProvider; - rpcUrl = rpcUrl ?? DEFAULT_RPC; + rpcUrl = rpcUrl ?? DEFAULT_READ_RPC; if (context && 'provider' in context!) { provider = context.provider; } else { From 2e5f64e56f37e3cfde60b380358855a149a5ff13 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 28 May 2024 17:57:14 -0400 Subject: [PATCH 216/263] ref: update to use replica over sequencer rpc --- packages/contracts-sdk/src/lib/addresses.ts | 2 +- packages/contracts-sdk/src/lib/contracts-sdk.spec.ts | 2 +- packages/lit-auth-client/src/lib/lit-auth-client.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts-sdk/src/lib/addresses.ts b/packages/contracts-sdk/src/lib/addresses.ts index efd106ee7b..35dd73ff98 100644 --- a/packages/contracts-sdk/src/lib/addresses.ts +++ b/packages/contracts-sdk/src/lib/addresses.ts @@ -47,7 +47,7 @@ export const derivedAddresses = async ({ // if default RPC url is not provided, use the default one https://endpoints.omniatech.io/v1/matic/mumbai/public if (!defaultRPCUrl) { - defaultRPCUrl = 'https://chain-rpc.litprotocol.com/http'; + defaultRPCUrl = 'https://lit-protocol.calderachain.xyz/replica-http'; } // if pkpTokenId is provided, get the public key from it diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts b/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts index 4e17643a5b..bfa8040bdd 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts @@ -29,7 +29,7 @@ describe('contractsSdk', () => { }); it('Test that connection from custom context resolves contracts in correct mapping', async () => { - const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; + const DEFAULT_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; const provider = new ethers.providers.JsonRpcProvider(DEFAULT_RPC); litContracts = new LitContracts({ customContext: { diff --git a/packages/lit-auth-client/src/lib/lit-auth-client.ts b/packages/lit-auth-client/src/lib/lit-auth-client.ts index 8089d0fbf9..603b3ad23b 100644 --- a/packages/lit-auth-client/src/lib/lit-auth-client.ts +++ b/packages/lit-auth-client/src/lib/lit-auth-client.ts @@ -138,7 +138,7 @@ export class LitAuthClient { } // Set RPC URL - this.rpcUrl = options?.rpcUrl || 'https://chain-rpc.litprotocol.com/http'; + this.rpcUrl = options?.rpcUrl || 'https://lit-protocol.calderachain.xyz/replica-http'; log('rpc url: ', this.rpcUrl); log('relay config: ', options.litRelayConfig); log('relay instance: ', this.relay); From d57f04cc8f92e0f44a5a051420f222f083d7d596 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 28 May 2024 18:06:56 -0400 Subject: [PATCH 217/263] chore: fmt --- packages/lit-auth-client/src/lib/lit-auth-client.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/lit-auth-client/src/lib/lit-auth-client.ts b/packages/lit-auth-client/src/lib/lit-auth-client.ts index 603b3ad23b..d2d4dc0574 100644 --- a/packages/lit-auth-client/src/lib/lit-auth-client.ts +++ b/packages/lit-auth-client/src/lib/lit-auth-client.ts @@ -138,7 +138,8 @@ export class LitAuthClient { } // Set RPC URL - this.rpcUrl = options?.rpcUrl || 'https://lit-protocol.calderachain.xyz/replica-http'; + this.rpcUrl = + options?.rpcUrl || 'https://lit-protocol.calderachain.xyz/replica-http'; log('rpc url: ', this.rpcUrl); log('relay config: ', options.litRelayConfig); log('relay instance: ', this.relay); From 5eca13582a5cd19d08c29676224a1ded700f845f Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 28 May 2024 18:42:18 -0400 Subject: [PATCH 218/263] dev: replace sequencer with replica in token info --- packages/constants/src/lib/constants/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index 713e491808..f17747a01c 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -472,7 +472,7 @@ export const LIT_CHAINS: LITChain = { name: 'Chronicle - Lit Protocol Testnet', symbol: 'testLPX', decimals: 18, - rpcUrls: ['https://chain-rpc.litprotocol.com/http'], + rpcUrls: ['https://lit-protocol.calderachain.xyz/replica-http'], blockExplorerUrls: ['https://chain.litprotocol.com/'], type: null, vmType: 'EVM', @@ -483,7 +483,7 @@ export const LIT_CHAINS: LITChain = { name: 'Chronicle - Lit Protocol Testnet', symbol: 'testLPX', decimals: 18, - rpcUrls: ['https://chain-rpc.litprotocol.com/http'], + rpcUrls: ['https://lit-protocol.calderachain.xyz/replica-http'], blockExplorerUrls: ['https://chain.litprotocol.com/'], type: null, vmType: 'EVM', From 2308b16a687b3c4c16db631cb41fda028c79b0ee Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:10:48 +0100 Subject: [PATCH 219/263] refactor: make `checkNeedToResignSessionKey` private --- .../src/lib/lit-node-client-nodejs.ts | 4 ++-- packages/types/src/lib/interfaces.ts | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 7de8e88308..7a0f1d5b71 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -508,7 +508,7 @@ export class LitNodeClientNodeJs * 3. The authSig.signedMessage does not contain at least one session capability object * */ - checkNeedToResignSessionKey = async ({ + #checkNeedToResignSessionKey = async ({ authSig, sessionKeyUri, resourceAbilityRequests, @@ -2383,7 +2383,7 @@ const resourceAbilityRequests = [ ...(params.jsParams && { jsParams: params.jsParams }), }); - const needToResignSessionKey = await this.checkNeedToResignSessionKey({ + const needToResignSessionKey = await this.#checkNeedToResignSessionKey({ authSig, sessionKeyUri, resourceAbilityRequests: params.resourceAbilityRequests, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 24d0044a96..e35da37a45 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1227,16 +1227,7 @@ export interface LitClientSessionManager { isSessionKeyPair(obj: any): boolean; getExpiration: () => string; getWalletSig: (getWalletSigProps: GetWalletSigProps) => Promise; - // #authCallbackAndUpdateStorageItem: (params: { - // authCallbackParams: AuthCallbackParams; - // authCallback?: AuthCallback; - // }) => Promise; getPkpSessionSigs: (params: GetPkpSessionSigs) => Promise; - checkNeedToResignSessionKey: (params: { - authSig: AuthSig; - sessionKeyUri: any; - resourceAbilityRequests: LitResourceAbilityRequest[]; - }) => Promise; getSessionSigs: (params: GetSessionSigsProps) => Promise; signSessionKey: ( params: SignSessionKeyProp From 5e021157c6b6d18c9a30f4cdc8fa41bbbc1f3889 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:33:13 +0100 Subject: [PATCH 220/263] chore: remove unused function --- packages/misc/src/lib/misc.spec.ts | 9 --------- packages/misc/src/lib/misc.ts | 22 ---------------------- 2 files changed, 31 deletions(-) diff --git a/packages/misc/src/lib/misc.spec.ts b/packages/misc/src/lib/misc.spec.ts index 2f0e7e22d9..6130923dd4 100644 --- a/packages/misc/src/lib/misc.spec.ts +++ b/packages/misc/src/lib/misc.spec.ts @@ -288,12 +288,3 @@ it('should not remove hex prefix if it is not present', () => { expect(result).toBe(expectedOutput); }); - -it('should get ip address', async () => { - // polyfill fetch - const fetch = require('node-fetch'); - global.fetch = fetch; - - const ipAddres = await utilsModule.getIpAddress('cayenne.litgateway.com'); - expect(ipAddres).toBe('207.244.70.36'); -}); diff --git a/packages/misc/src/lib/misc.ts b/packages/misc/src/lib/misc.ts index 223ae1df6d..83afda633a 100644 --- a/packages/misc/src/lib/misc.ts +++ b/packages/misc/src/lib/misc.ts @@ -916,25 +916,3 @@ export function normalizeAndStringify(input: string): string { } } -/** - * Retrieves the IP address associated with a given domain. - * @param domain - The domain for which to retrieve the IP address. - * @returns A Promise that resolves to the IP address. - * @throws If no IP address is found or if the domain name is invalid. - */ -export async function getIpAddress(domain: string): Promise { - const apiURL = `https://dns.google/resolve?name=${domain}&type=A`; - - try { - const response = await fetch(apiURL); - const data = await response.json(); - - if (data.Answer && data.Answer.length > 0) { - return data.Answer[0].data; - } else { - throw new Error('No IP Address found or bad domain name'); - } - } catch (error: any) { - throw new Error(error); - } -} From 1ccd46a427d3460bd7cccf065d04257c7bb3fe4f Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:33:39 +0100 Subject: [PATCH 221/263] chore: reorganised methods placement --- .../src/lib/lit-node-client-nodejs.ts | 285 +++++++++--------- 1 file changed, 140 insertions(+), 145 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 7a0f1d5b71..6e755e8989 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -156,6 +156,146 @@ export class LitNodeClientNodeJs } } + // ========== Private Methods ========== + #authCallbackAndUpdateStorageItem = async ({ + authCallbackParams, + authCallback, + }: { + authCallbackParams: AuthCallbackParams; + authCallback?: AuthCallback; + }): Promise => { + let authSig: AuthSig; + + if (authCallback) { + authSig = await authCallback(authCallbackParams); + } else { + if (!this.defaultAuthCallback) { + return throwError({ + message: 'No default auth callback provided', + errorKind: LIT_ERROR.PARAMS_MISSING_ERROR.kind, + errorCode: LIT_ERROR.PARAMS_MISSING_ERROR.name, + }); + } + authSig = await this.defaultAuthCallback(authCallbackParams); + } + + // (TRY) to set walletSig to local storage + const storeNewWalletSigOrError = setStorageItem( + LOCAL_STORAGE_KEYS.WALLET_SIGNATURE, + JSON.stringify(authSig) + ); + if (storeNewWalletSigOrError.type === EITHER_TYPE.SUCCESS) { + return authSig; + } + + // Setting local storage failed, try to remove the item key. + console.warn( + `Unable to store walletSig in local storage. Not a problem. Continuing to remove item key...` + ); + const removeWalletSigOrError = removeStorageItem( + LOCAL_STORAGE_KEYS.WALLET_SIGNATURE + ); + if (removeWalletSigOrError.type === EITHER_TYPE.ERROR) { + console.warn( + `Unable to remove walletSig in local storage. Not a problem. Continuing...` + ); + } + + return authSig; + }; + /** + * + * Check if a session key needs to be resigned. These are the scenarios where a session key needs to be resigned: + * 1. The authSig.sig does not verify successfully against the authSig.signedMessage + * 2. The authSig.signedMessage.uri does not match the sessionKeyUri + * 3. The authSig.signedMessage does not contain at least one session capability object + * + */ + #checkNeedToResignSessionKey = async ({ + authSig, + sessionKeyUri, + resourceAbilityRequests, + }: { + authSig: AuthSig; + sessionKeyUri: any; + resourceAbilityRequests: LitResourceAbilityRequest[]; + }): Promise => { + const authSigSiweMessage = new SiweMessage(authSig.signedMessage); + + try { + await authSigSiweMessage.validate(authSig.sig); + } catch (e) { + console.debug('Need retry because verify failed', e); + return true; + } + + // make sure the sig is for the correct session key + if (authSigSiweMessage.uri !== sessionKeyUri) { + console.debug('Need retry because uri does not match'); + return true; + } + + // make sure the authSig contains at least one resource. + if ( + !authSigSiweMessage.resources || + authSigSiweMessage.resources.length === 0 + ) { + console.debug('Need retry because empty resources'); + return true; + } + + // make sure the authSig contains session capabilities that can be parsed. + // TODO: we currently only support the first resource being a session capability object. + const authSigSessionCapabilityObject = decode( + authSigSiweMessage.resources[0] + ); + + // make sure the authSig session capability object describes capabilities that are equal or greater than + // the abilities requested against the resources in the resource ability requests. + for (const resourceAbilityRequest of resourceAbilityRequests) { + if ( + !authSigSessionCapabilityObject.verifyCapabilitiesForResource( + resourceAbilityRequest.resource, + resourceAbilityRequest.ability + ) + ) { + console.debug('Need retry because capabilities do not match', { + authSigSessionCapabilityObject, + resourceAbilityRequest, + }); + return true; + } + } + + return false; + }; + #decryptWithSignatureShares = ( + networkPubKey: string, + identityParam: Uint8Array, + ciphertext: string, + signatureShares: NodeBlsSigningShare[] + ): Uint8Array => { + const sigShares = signatureShares.map((s: any) => s.signatureShare); + + return verifyAndDecryptWithSignatureShares( + networkPubKey, + identityParam, + ciphertext, + sigShares + ); + }; + #isSuccessNodePromises = (res: any): res is SuccessNodePromises => { + return res.success === true; + }; + #getIdentityParamForEncryption = ( + hashOfConditionsStr: string, + hashOfPrivateDataStr: string + ): string => { + return new LitAccessControlConditionResource( + `${hashOfConditionsStr}/${hashOfPrivateDataStr}` + ).getResourceKey(); + }; + // ========== Rate Limit NFT ========== // TODO: Add support for browser feature/lit-2321-js-sdk-add-browser-support-for-createCapacityDelegationAuthSig @@ -453,120 +593,6 @@ export class LitNodeClientNodeJs return walletSig!; }; - #authCallbackAndUpdateStorageItem = async ({ - authCallbackParams, - authCallback, - }: { - authCallbackParams: AuthCallbackParams; - authCallback?: AuthCallback; - }): Promise => { - let authSig: AuthSig; - - if (authCallback) { - authSig = await authCallback(authCallbackParams); - } else { - if (!this.defaultAuthCallback) { - return throwError({ - message: 'No default auth callback provided', - errorKind: LIT_ERROR.PARAMS_MISSING_ERROR.kind, - errorCode: LIT_ERROR.PARAMS_MISSING_ERROR.name, - }); - } - authSig = await this.defaultAuthCallback(authCallbackParams); - } - - // (TRY) to set walletSig to local storage - const storeNewWalletSigOrError = setStorageItem( - LOCAL_STORAGE_KEYS.WALLET_SIGNATURE, - JSON.stringify(authSig) - ); - if (storeNewWalletSigOrError.type === EITHER_TYPE.SUCCESS) { - return authSig; - } - - // Setting local storage failed, try to remove the item key. - console.warn( - `Unable to store walletSig in local storage. Not a problem. Continuing to remove item key...` - ); - const removeWalletSigOrError = removeStorageItem( - LOCAL_STORAGE_KEYS.WALLET_SIGNATURE - ); - if (removeWalletSigOrError.type === EITHER_TYPE.ERROR) { - console.warn( - `Unable to remove walletSig in local storage. Not a problem. Continuing...` - ); - } - - return authSig; - }; - - /** - * - * Check if a session key needs to be resigned. These are the scenarios where a session key needs to be resigned: - * 1. The authSig.sig does not verify successfully against the authSig.signedMessage - * 2. The authSig.signedMessage.uri does not match the sessionKeyUri - * 3. The authSig.signedMessage does not contain at least one session capability object - * - */ - #checkNeedToResignSessionKey = async ({ - authSig, - sessionKeyUri, - resourceAbilityRequests, - }: { - authSig: AuthSig; - sessionKeyUri: any; - resourceAbilityRequests: LitResourceAbilityRequest[]; - }): Promise => { - const authSigSiweMessage = new SiweMessage(authSig.signedMessage); - - try { - await authSigSiweMessage.validate(authSig.sig); - } catch (e) { - console.debug('Need retry because verify failed', e); - return true; - } - - // make sure the sig is for the correct session key - if (authSigSiweMessage.uri !== sessionKeyUri) { - console.debug('Need retry because uri does not match'); - return true; - } - - // make sure the authSig contains at least one resource. - if ( - !authSigSiweMessage.resources || - authSigSiweMessage.resources.length === 0 - ) { - console.debug('Need retry because empty resources'); - return true; - } - - // make sure the authSig contains session capabilities that can be parsed. - // TODO: we currently only support the first resource being a session capability object. - const authSigSessionCapabilityObject = decode( - authSigSiweMessage.resources[0] - ); - - // make sure the authSig session capability object describes capabilities that are equal or greater than - // the abilities requested against the resources in the resource ability requests. - for (const resourceAbilityRequest of resourceAbilityRequests) { - if ( - !authSigSessionCapabilityObject.verifyCapabilitiesForResource( - resourceAbilityRequest.resource, - resourceAbilityRequest.ability - ) - ) { - console.debug('Need retry because capabilities do not match', { - authSigSessionCapabilityObject, - resourceAbilityRequest, - }); - return true; - } - } - - return false; - }; - // ==================== API Calls to Nodes ==================== getClaimKeyExecutionShares = async ( url: string, @@ -750,22 +776,6 @@ export class LitNodeClientNodeJs return finalJwt; }; - #decryptWithSignatureShares = ( - networkPubKey: string, - identityParam: Uint8Array, - ciphertext: string, - signatureShares: NodeBlsSigningShare[] - ): Uint8Array => { - const sigShares = signatureShares.map((s: any) => s.signatureShare); - - return verifyAndDecryptWithSignatureShares( - networkPubKey, - identityParam, - ciphertext, - sigShares - ); - }; - // ========== Promise Handlers ========== getIpfsId = async ({ dataToHash, @@ -1843,15 +1853,6 @@ export class LitNodeClientNodeJs ); }; - #getIdentityParamForEncryption = ( - hashOfConditionsStr: string, - hashOfPrivateDataStr: string - ): string => { - return new LitAccessControlConditionResource( - `${hashOfConditionsStr}/${hashOfPrivateDataStr}` - ).getResourceKey(); - }; - /** * * Validates a condition, and then signs the condition if the validation returns true. @@ -2260,10 +2261,6 @@ export class LitNodeClientNodeJs return signSessionKeyRes; }; - #isSuccessNodePromises = (res: any): res is SuccessNodePromises => { - return res.success === true; - }; - getSignSessionKeyShares = async ( url: string, params: GetSignSessionKeySharesProp, @@ -2389,8 +2386,6 @@ const resourceAbilityRequests = [ resourceAbilityRequests: params.resourceAbilityRequests, }); - // console.log('XXX needToResignSessionKey:', needToResignSessionKey); - // -- (CHECK) if we need to resign the session key if (needToResignSessionKey) { log('need to re-sign session key. Signing...'); From 7190ca1a7a360bca330900fe74f0fd39b4503cb3 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:34:11 +0100 Subject: [PATCH 222/263] chore: privateised methods --- packages/core/src/lib/lit-core.ts | 29 ++++++++++--------- .../src/lib/lit-node-client.ts | 4 +-- packages/types/src/lib/ILitNodeClient.ts | 26 ----------------- 3 files changed, 18 insertions(+), 41 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index fe67acd536..39bf8d15f6 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -30,7 +30,6 @@ import { checkSevSnpAttestation, computeHDPubKey } from '@lit-protocol/crypto'; import { bootstrapLogManager, executeWithRetry, - getIpAddress, isBrowser, isNode, log, @@ -168,7 +167,7 @@ export class LitCore { } // -- set bootstrapUrls to match the network litNetwork unless it's set to custom - this.setCustomBootstrapUrls(); + this.#setCustomBootstrapUrls(); // -- set global variables globalThis.litConfig = this.config; @@ -432,9 +431,9 @@ export class LitCore { * that the client's configuration is always in sync with the current state of the * staking contract. * - * @returns {Promise} A promise that resolves when the listener is successfully set up. + * @returns { void } */ - private _listenForNewEpoch() { + #listenForNewEpoch(): void { // Check if we've already set up the listener to avoid duplicates if (this._stakingContractListener) { // Already listening, do nothing @@ -464,13 +463,14 @@ export class LitCore { this._stopNetworkPolling(); } - _stopNetworkPolling() { + protected _stopNetworkPolling() { if (this._networkSyncInterval) { clearInterval(this._networkSyncInterval); this._networkSyncInterval = null; } } - _stopListeningForNewEpoch() { + + protected _stopListeningForNewEpoch() { if (this._stakingContract && this._stakingContractListener) { this._stakingContract.off('StateChanged', this._stakingContractListener); this._stakingContractListener = null; @@ -484,7 +484,7 @@ export class LitCore { * @returns { void } * */ - setCustomBootstrapUrls = (): void => { + #setCustomBootstrapUrls = (): void => { // -- validate if (this.config.litNetwork === 'custom') return; @@ -561,8 +561,8 @@ export class LitCore { await this._runHandshakeWithBootstrapUrls(); Object.assign(this, { ...coreNodeConfig, connectedNodes, serverKeys }); - this._scheduleNetworkSync(); - this._listenForNewEpoch(); + this.#scheduleNetworkSync(); + this.#listenForNewEpoch(); // FIXME: don't create global singleton; multiple instances of `core` should not all write to global // @ts-expect-error typeof globalThis is not defined. We're going to get rid of the global soon. @@ -805,7 +805,7 @@ export class LitCore { * We can remove this network sync code entirely if we refactor our code to fetch latest blockhash on-demand. * @private */ - private _scheduleNetworkSync() { + #scheduleNetworkSync() { if (this._networkSyncInterval) { clearInterval(this._networkSyncInterval); } @@ -848,7 +848,7 @@ export class LitCore { * @returns { string } * */ - getRequestId() { + getRequestId(): string { return Math.random().toString(16).slice(2); } @@ -859,7 +859,7 @@ export class LitCore { * @returns { string } */ - getRandomHexString(size: number) { + getRandomHexString(size: number): string { return [...Array(size)] .map(() => Math.floor(Math.random() * 16).toString(16)) .join(''); @@ -1205,7 +1205,10 @@ export class LitCore { * @returns { void } * */ - _throwNodeError = (res: RejectedNodePromises, requestId: string): void => { + protected _throwNodeError = ( + res: RejectedNodePromises, + requestId: string + ): void => { if (res.error) { if ( ((res.error.errorCode && diff --git a/packages/lit-node-client/src/lib/lit-node-client.ts b/packages/lit-node-client/src/lib/lit-node-client.ts index 7d84a9c697..935594cbd8 100644 --- a/packages/lit-node-client/src/lib/lit-node-client.ts +++ b/packages/lit-node-client/src/lib/lit-node-client.ts @@ -26,7 +26,7 @@ export class LitNodeClient extends LitNodeClientNodeJs { }); // -- override configs - this.overrideConfigsFromLocalStorage(); + this.#overrideConfigsFromLocalStorage(); } /** @@ -36,7 +36,7 @@ export class LitNodeClient extends LitNodeClientNodeJs { * @returns { void } * */ - overrideConfigsFromLocalStorage = (): void => { + #overrideConfigsFromLocalStorage = (): void => { if (isNode()) return; const storageKey = 'LitNodeClientConfig'; diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index acdfa00890..eec36dee37 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -39,17 +39,6 @@ export interface ILitNodeClient { // ** IMPORTANT !! You have to create your constructor when implementing this class ** // constructor(customConfig: LitNodeClientConfig); - // ========== Scoped Class Helpers ========== - - /** - * - * Set bootstrapUrls to match the network litNetwork unless it's set to custom - * - * @returns { void } - * - */ - setCustomBootstrapUrls(): void; - /** * * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period @@ -123,19 +112,6 @@ export interface ILitNodeClient { minNodeCount: number ): Promise | RejectedNodePromises>; - /** - * - * Throw node error - * - * @param { RejectedNodePromises } res - * - * @returns { void } - * - */ - _throwNodeError(res: RejectedNodePromises, requestId: string): void; - - // ========== Shares Resolvers ========== - /** * * Get Signature @@ -147,7 +123,6 @@ export interface ILitNodeClient { */ getSignature(shareData: any[], requestId: string): Promise; - // ========== API Calls to Nodes ========== sendCommandToNode({ url, data, requestId }: SendNodeCommand): Promise; /** @@ -204,7 +179,6 @@ export interface ILitNodeClient { requestId: string ): Promise; - // ========== Scoped Business Logics ========== /** * * Execute JS on the nodes and combine and return any resulting signatures From 2ceba6ffce4c50d311c6b5d0d4df7228115764fc Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:40:58 +0100 Subject: [PATCH 223/263] refactor: privateise `getJWTParams` --- .../src/lib/lit-node-client-nodejs.ts | 29 +++++++++---------- packages/types/src/lib/ILitNodeClient.ts | 7 ----- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index ba1b5f89ad..5b52d402a1 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -291,6 +291,18 @@ export class LitNodeClientNodeJs `${hashOfConditionsStr}/${hashOfPrivateDataStr}` ).getResourceKey(); }; + /** + * + * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period + * + */ + #getJWTParams = () => { + const now = Date.now(); + const iat = Math.floor(now / 1000); + const exp = iat + 12 * 60 * 60; // 12 hours in seconds + + return { iat, exp }; + }; // ========== Rate Limit NFT ========== @@ -345,21 +357,6 @@ export class LitNodeClientNodeJs return { capacityDelegationAuthSig: authSig }; }; - // ========== Scoped Class Helpers ========== - - /** - * - * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period - * - */ - getJWTParams = () => { - const now = Date.now(); - const iat = Math.floor(now / 1000); - const exp = iat + 12 * 60 * 60; // 12 hours in seconds - - return { iat, exp }; - }; - // ==================== SESSIONS ==================== /** * Try to get the session key in the local storage, @@ -1342,7 +1339,7 @@ export class LitNodeClientNodeJs // we need to send jwt params iat (issued at) and exp (expiration) // because the nodes may have different wall clock times // the nodes will verify that these params are withing a grace period - const { iat, exp } = this.getJWTParams(); + const { iat, exp } = this.#getJWTParams(); // ========== Formatting Access Control Conditions ========= const { diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 5ea3a2db24..74ca3d77a1 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -36,13 +36,6 @@ export interface ILitNodeClient { // ** IMPORTANT !! You have to create your constructor when implementing this class ** // constructor(customConfig: LitNodeClientConfig); - /** - * - * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period - * - */ - getJWTParams(): { iat: number; exp: number }; - /** * * Combine Shares from signature shares From c248c5837d43205d84698b7afd1162b2707bb8d1 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:45:37 +0100 Subject: [PATCH 224/263] chore: add jsDocs to private methods --- .../src/lib/lit-node-client-nodejs.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 5b52d402a1..d66dfc5152 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -153,6 +153,13 @@ export class LitNodeClientNodeJs } // ========== Private Methods ========== + /** + * Handles the authentication callback and updates the storage item with the authentication signature. + * @param authCallbackParams - The parameters required for the authentication callback. + * @param authCallback - The optional authentication callback function. + * @returns A promise that resolves to the authentication signature. + * @throws An error if no default authentication callback is provided. + */ #authCallbackAndUpdateStorageItem = async ({ authCallbackParams, authCallback, @@ -199,6 +206,7 @@ export class LitNodeClientNodeJs return authSig; }; + /** * * Check if a session key needs to be resigned. These are the scenarios where a session key needs to be resigned: @@ -265,6 +273,15 @@ export class LitNodeClientNodeJs return false; }; + /** + * Decrypts the ciphertext using the provided signature shares. + * + * @param networkPubKey - The network public key. + * @param identityParam - The identity parameter. + * @param ciphertext - The ciphertext to decrypt. + * @param signatureShares - An array of signature shares. + * @returns The decrypted data as a Uint8Array. + */ #decryptWithSignatureShares = ( networkPubKey: string, identityParam: Uint8Array, @@ -280,9 +297,22 @@ export class LitNodeClientNodeJs sigShares ); }; + /** + * Checks if the given response is a success node promise. + * @private + * @param res - The response object to check. + * @returns A boolean indicating whether the response is a success node promise. + * @template T - The type of the success node promise. + */ #isSuccessNodePromises = (res: any): res is SuccessNodePromises => { return res.success === true; }; + /** + * Generates an identity parameter for encryption based on the provided conditions and private data. + * @param hashOfConditionsStr - The hash of the conditions string. + * @param hashOfPrivateDataStr - The hash of the private data string. + * @returns The generated identity parameter for encryption. + */ #getIdentityParamForEncryption = ( hashOfConditionsStr: string, hashOfPrivateDataStr: string @@ -291,6 +321,7 @@ export class LitNodeClientNodeJs `${hashOfConditionsStr}/${hashOfPrivateDataStr}` ).getResourceKey(); }; + /** * * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period From c93fbba2ac9ab4d98e6b38425918c5905df5754d Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:48:27 +0100 Subject: [PATCH 225/263] refactor: privatise `combineSharesAndGetJWT` --- .../src/lib/lit-node-client-nodejs.ts | 4 ++-- packages/types/src/lib/ILitNodeClient.ts | 11 ----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d66dfc5152..d5182f7c46 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -628,7 +628,7 @@ export class LitNodeClientNodeJs * @returns { string } final JWT (convert the sig to base64 and append to the jwt) * */ - combineSharesAndGetJWT = ( + #combineSharesAndGetJWT = ( signatureShares: NodeBlsSigningShare[], requestId: string = '' ): string => { @@ -1451,7 +1451,7 @@ export class LitNodeClientNodeJs log('signatureShares', signatureShares); // ========== Result ========== - const finalJwt: string = this.combineSharesAndGetJWT( + const finalJwt: string = this.#combineSharesAndGetJWT( signatureShares, requestId ); diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 74ca3d77a1..d4bd37f4a0 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -36,17 +36,6 @@ export interface ILitNodeClient { // ** IMPORTANT !! You have to create your constructor when implementing this class ** // constructor(customConfig: LitNodeClientConfig); - /** - * - * Combine Shares from signature shares - * - * @param { NodeBlsSigningShare } signatureShares - * - * @returns { string } final JWT (convert the sig to base64 and append to the jwt) - * - */ - combineSharesAndGetJWT(signatureShares: NodeBlsSigningShare[]): string; - /** * * Get different formats of access control conditions, eg. evm, sol, unified etc. From 2614b3762b862af81e8f1df9fde2f03fddf22386 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:49:44 +0100 Subject: [PATCH 226/263] refactor: privatise `getSessionKeyUri` --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d5182f7c46..34c604a671 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -2118,7 +2118,7 @@ const resourceAbilityRequests = [ // Try to get it from local storage, if not generates one~ const sessionKey = params.sessionKey ?? this.getSessionKey(); - const sessionKeyUri = this.getSessionKeyUri(sessionKey.publicKey); + const sessionKeyUri = this.#getSessionKeyUri(sessionKey.publicKey); // First get or generate the session capability object for the specified resources. const sessionCapabilityObject = params.sessionCapabilityObject @@ -2326,7 +2326,7 @@ const resourceAbilityRequests = [ * @param publicKey is the public key of the session key * @returns { string } the session key uri */ - getSessionKeyUri = (publicKey: string): string => { + #getSessionKeyUri = (publicKey: string): string => { return LIT_SESSION_KEY_URI + publicKey; }; From 36f0e6968dd09ab0e39a4a4182a54c0eea0f83b8 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 14:57:46 +0100 Subject: [PATCH 227/263] refactor: protect `sendCommandToNode` --- cypress/e2e/spec.cy.ts | 2 +- packages/core/src/lib/lit-core.ts | 4 ++-- .../src/lib/lit-node-client-nodejs.ts | 20 +++++++++---------- packages/types/src/lib/ILitNodeClient.ts | 2 -- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/cypress/e2e/spec.cy.ts b/cypress/e2e/spec.cy.ts index 2f7c61a44f..093be6d346 100644 --- a/cypress/e2e/spec.cy.ts +++ b/cypress/e2e/spec.cy.ts @@ -549,7 +549,7 @@ describe('Lit Action', () => { url: 'https://cayenne.litgateway.com:7371/web/execute', data, }; - const res = await savedParams.litNodeClient.sendCommandToNode(reqBody); + const res = await savedParams.litNodeClient._sendCommandToNode(reqBody); expect(res).to.have.property('success', true); }); diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index d58ea3f80e..4b6e88527e 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -909,7 +909,7 @@ export class LitCore { challenge: params.challenge, }; - return await this.sendCommandToNode({ + return await this._sendCommandToNode({ url: urlWithPath, data, requestId, @@ -967,7 +967,7 @@ export class LitCore { * @returns { Promise } * */ - sendCommandToNode = async ({ + protected _sendCommandToNode = async ({ url, data, requestId, diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 35e81d6281..238646915a 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -802,7 +802,7 @@ export class LitNodeClientNodeJs // this return { url: string, data: JsonRequest } // const singleNodePromise = this.getJsExecutionShares(url, reqBody, id); - const singleNodePromise = this.sendCommandToNode({ + const singleNodePromise = this._sendCommandToNode({ url: url, data: params, requestId: id, @@ -1060,7 +1060,7 @@ export class LitNodeClientNodeJs endpoint: LIT_ENDPOINT.EXECUTE_JS, }); - return this.generatePromise(urlWithPath, reqBody, requestId); + return this.#generatePromise(urlWithPath, reqBody, requestId); }); // -- resolve promises @@ -1186,12 +1186,12 @@ export class LitNodeClientNodeJs * @param requestId - The ID of the request. * @returns A promise that resolves with the response from the server. */ - generatePromise = async ( + #generatePromise = async ( url: string, params: any, requestId: string ): Promise => { - return await this.sendCommandToNode({ + return await this._sendCommandToNode({ url, data: params, requestId, @@ -1264,7 +1264,7 @@ export class LitNodeClientNodeJs endpoint: LIT_ENDPOINT.PKP_SIGN, }); - return this.generatePromise(urlWithPath, reqBody, id); + return this.#generatePromise(urlWithPath, reqBody, id); }); const res = await this.handleNodePromises( @@ -1416,7 +1416,7 @@ export class LitNodeClientNodeJs endpoint: LIT_ENDPOINT.SIGN_ACCS, }); - return this.generatePromise(urlWithPath, reqBody, id); + return this.#generatePromise(urlWithPath, reqBody, id); }); // -- resolve promises @@ -1680,7 +1680,7 @@ export class LitNodeClientNodeJs endpoint: LIT_ENDPOINT.ENCRYPTION_SIGN, }); - return this.generatePromise(urlWithParh, reqBody, id); + return this.#generatePromise(urlWithParh, reqBody, id); }); // -- resolve promises @@ -1881,7 +1881,7 @@ export class LitNodeClientNodeJs endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, }); - return this.generatePromise(urlWithPath, reqBody, id); + return this.#generatePromise(urlWithPath, reqBody, id); }); // -- resolve promises @@ -2069,7 +2069,7 @@ export class LitNodeClientNodeJs url, endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, }); - return await this.sendCommandToNode({ + return await this._sendCommandToNode({ url: urlWithPath, data: params.body, requestId, @@ -2409,7 +2409,7 @@ const resourceAbilityRequests = [ endpoint: LIT_ENDPOINT.PKP_CLAIM, }); - return this.generatePromise(urlWithPath, reqBody, id); + return this.#generatePromise(urlWithPath, reqBody, id); }); const responseData = await this.handleNodePromises( diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index d4bd37f4a0..402e9c6dd6 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -102,8 +102,6 @@ export interface ILitNodeClient { */ getSignature(shareData: any[], requestId: string): Promise; - sendCommandToNode({ url, data, requestId }: SendNodeCommand): Promise; - /** * * Get JS Execution Shares from Nodes From e0dd999d80f494ea29c495559dff5e9a897611e1 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:01:04 +0100 Subject: [PATCH 228/263] refactor: protect `getNodePromises` --- .../src/lib/lit-node-client-nodejs.ts | 12 ++++++------ packages/types/src/lib/ILitNodeClient.ts | 11 ----------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 238646915a..b6ea73149c 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1043,7 +1043,7 @@ export class LitNodeClientNodeJs const wrapper = async ( requestId: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises(async (url: string) => { + const nodePromises = this._getNodePromises(async (url: string) => { // -- choose the right signature const sessionSig = this.getSessionSigByUrl({ sessionSigs: formattedParams.sessionSigs, @@ -1238,7 +1238,7 @@ export class LitNodeClientNodeJs const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises((url: string) => { + const nodePromises = this._getNodePromises((url: string) => { // -- get the session sig from the url key const sessionSig = this.getSessionSigByUrl({ sessionSigs: params.sessionSigs, @@ -1395,7 +1395,7 @@ export class LitNodeClientNodeJs const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises((url: string) => { + const nodePromises = this._getNodePromises((url: string) => { // -- if session key is available, use it const authSigToSend = sessionSigs ? sessionSigs[url] : authSig; @@ -1651,7 +1651,7 @@ export class LitNodeClientNodeJs const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises((url: string) => { + const nodePromises = this._getNodePromises((url: string) => { // -- if session key is available, use it const authSigToSend = sessionSigs ? sessionSigs[url] : params.authSig; @@ -1873,7 +1873,7 @@ export class LitNodeClientNodeJs id: string ): Promise | RejectedNodePromises> => { logWithRequestId(id, 'signSessionKey body', body); - const nodePromises = this.getNodePromises((url: string) => { + const nodePromises = this._getNodePromises((url: string) => { const reqBody: JsonSignSessionKeyRequestV1 = body; const urlWithPath = composeLitUrl({ @@ -2395,7 +2395,7 @@ const resourceAbilityRequests = [ const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - const nodePromises = this.getNodePromises((url: string) => { + const nodePromises = this._getNodePromises((url: string) => { if (!params.authMethod) { throw new Error('authMethod is required'); } diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 402e9c6dd6..040bac2a19 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -64,17 +64,6 @@ export interface ILitNodeClient { // ========== Promise Handlers ========== - /** - * - * Get and gather node promises - * - * @param { any } callback - * - * @returns { Array> } - * - */ - getNodePromises(callback: Function): Promise[]; - /** * Handle node promises * From 6793fb10f1c647f23affaa2216b1f1212b2d667b Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:02:16 +0100 Subject: [PATCH 229/263] refactor: privatised `getRequestId` --- packages/core/src/lib/lit-core.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 4b6e88527e..6cb2599fe2 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -697,7 +697,7 @@ export class LitCore { coreNodeConfig: CoreNodeConfig; }> { // -- handshake with each node - const requestId: string = this.getRequestId(); + const requestId: string = this.#getRequestId(); // track connectedNodes for the new handshake operation const connectedNodes = new Set(); @@ -862,7 +862,7 @@ export class LitCore { * @returns { string } * */ - getRequestId(): string { + #getRequestId(): string { return Math.random().toString(16).slice(2); } @@ -1005,7 +1005,7 @@ export class LitCore { * @returns { Array> } * */ - getNodePromises = ( + protected _getNodePromises = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (url: string) => Promise // eslint-disable-next-line @typescript-eslint/no-explicit-any From b199cee26b24b90c2b730d331ae2f7a7a3976c1b Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:03:57 +0100 Subject: [PATCH 230/263] refactor: privatised `handshakeWithNode` --- packages/core/src/lib/lit-core.ts | 4 ++-- packages/types/src/lib/ILitNodeClient.ts | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 6cb2599fe2..fd5484a85a 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -607,7 +607,7 @@ export class LitCore { }): Promise { const challenge = this.getRandomHexString(64); - const handshakeResult = await this.handshakeWithNode( + const handshakeResult = await this.#handshakeWithNode( { url, challenge }, requestId ); @@ -887,7 +887,7 @@ export class LitCore { * @returns { Promise } * */ - handshakeWithNode = async ( + #handshakeWithNode = async ( params: HandshakeWithNode, requestId: string ): Promise => { diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 040bac2a19..0b108090a7 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -100,20 +100,6 @@ export interface ILitNodeClient { * @returns { Promise } */ - /** - * - * Handshake with SGX - * - * @param { HandshakeWithNode } params - * - * @returns { Promise } - * - */ - handshakeWithNode( - params: HandshakeWithNode, - requestId: string - ): Promise; - /** * * Execute JS on the nodes and combine and return any resulting signatures From 991e651f49243937f5a15eb74e62dda9a950c70f Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:06:45 +0100 Subject: [PATCH 231/263] refactor: remove `getSessionSignatures` --- .../src/lib/lit-node-client-nodejs.ts | 128 ------------------ 1 file changed, 128 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index b6ea73149c..3589fd0c07 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -832,134 +832,6 @@ export class LitNodeClientNodeJs ); }; - /** - * - * Get signatures from signed data - * - * @param { Array } signedData - * - * @returns { any } - * - */ - getSessionSignatures = (signedData: any[]): any => { - // -- prepare - const signatures: any = {}; - - // TOOD: get keys of signedData - const keys = Object.keys(signedData[0]); - - // removeExtraBackslashesAndQuotes - const sanitise = (str: string) => { - // Check if str is a string and remove extra backslashes - if (typeof str === 'string') { - // Remove backslashes - let newStr = str.replace(/\\+/g, ''); - // Remove leading and trailing double quotes - newStr = newStr.replace(/^"|"$/g, ''); - return newStr; - } - return str; - }; - - // -- execute - keys.forEach((key: any) => { - log('key:', key); - - const shares = signedData.map((r: any) => r[key]); - - log('shares:', shares); - - shares.sort((a: any, b: any) => a.shareIndex - b.shareIndex); - - const sigShares: SigShare[] = shares.map((s: any, index: number) => { - log('Original Share Struct:', s); - - const share = getFlattenShare(s); - - log('share:', share); - - if (!share) { - throw new Error('share is null or undefined'); - } - - if (!share.bigr) { - throw new Error( - `bigR is missing in share ${index}. share ${JSON.stringify(share)}` - ); - } - - const sanitisedBigR = sanitise(share.bigr); - const sanitisedSigShare = sanitise(share.publicKey); - - log('sanitisedBigR:', sanitisedBigR); - log('sanitisedSigShare:', sanitisedSigShare); - - return { - sigType: share.sigType, - signatureShare: sanitise(share.signatureShare), - shareIndex: share.shareIndex, - bigR: sanitise(share.bigr), - publicKey: share.publicKey, - dataSigned: share.dataSigned, - siweMessage: share.siweMessage, - }; - }); - - log('getSessionSignatures - sigShares', sigShares); - - const sigType = mostCommonString(sigShares.map((s: any) => s.sigType)); - - // -- validate if this.networkPubKeySet is null - if (this.networkPubKeySet === null) { - throwError({ - message: 'networkPubKeySet cannot be null', - errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, - errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, - }); - return; - } - - // -- validate if signature type is ECDSA - if ( - sigType !== LIT_CURVE.EcdsaCaitSith && - sigType !== LIT_CURVE.EcdsaK256 && - sigType !== LIT_CURVE.EcdsaCAITSITHP256 - ) { - throwError({ - message: `signature type is ${sigType} which is invalid`, - errorKind: LIT_ERROR.UNKNOWN_SIGNATURE_TYPE.kind, - errorCode: LIT_ERROR.UNKNOWN_SIGNATURE_TYPE.name, - }); - return; - } - - const signature: any = combineEcdsaShares(sigShares); - if (!signature.r) { - throwError({ - message: 'siganture could not be combined', - errorKind: LIT_ERROR.UNKNOWN_SIGNATURE_ERROR.kind, - errorCode: LIT_ERROR.UNKNOWN_SIGNATURE_ERROR.name, - }); - } - - const encodedSig = joinSignature({ - r: '0x' + signature.r, - s: '0x' + signature.s, - v: signature.recid, - }); - - signatures[key] = { - ...signature, - signature: encodedSig, - publicKey: mostCommonString(sigShares.map((s: any) => s.publicKey)), - dataSigned: mostCommonString(sigShares.map((s: any) => s.dataSigned)), - siweMessage: mostCommonString(sigShares.map((s) => s.siweMessage)), - }; - }); - - return signatures; - }; - /** * * Get a single signature From 07259950079b5d3a80ff797dac35f7cabf1797fa Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:10:07 +0100 Subject: [PATCH 232/263] refactor: protected `getSessionSigByUrl` --- packages/core/src/lib/lit-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index fd5484a85a..591e377c41 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -1030,7 +1030,7 @@ export class LitCore { * @returns The session signature for the given URL. * @throws An error if sessionSigs is not provided or if the session signature for the URL is not found. */ - getSessionSigByUrl = ({ + protected _getSessionSigByUrl = ({ sessionSigs, url, }: { From bf83f0cf5c77b883fd513b72f7dcba3f709d8e06 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:10:20 +0100 Subject: [PATCH 233/263] refactor: privatised `getWalletSig` --- .../src/lib/lit-node-client-nodejs.ts | 10 +++++----- packages/types/src/lib/interfaces.ts | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 3589fd0c07..20f08ae056 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -501,7 +501,7 @@ export class LitNodeClientNodeJs * Get the signature from local storage, if not, generates one * */ - getWalletSig = async ({ + #getWalletSig = async ({ authNeededCallback, chain, sessionCapabilityObject, @@ -789,7 +789,7 @@ export class LitNodeClientNodeJs log(`running on node ${nodeIndex} at ${url}`); // -- choose the right signature - const sessionSig = this.getSessionSigByUrl({ + const sessionSig = this._getSessionSigByUrl({ sessionSigs: params.sessionSigs, url, }); @@ -917,7 +917,7 @@ export class LitNodeClientNodeJs ): Promise | RejectedNodePromises> => { const nodePromises = this._getNodePromises(async (url: string) => { // -- choose the right signature - const sessionSig = this.getSessionSigByUrl({ + const sessionSig = this._getSessionSigByUrl({ sessionSigs: formattedParams.sessionSigs, url, }); @@ -1112,7 +1112,7 @@ export class LitNodeClientNodeJs ): Promise | RejectedNodePromises> => { const nodePromises = this._getNodePromises((url: string) => { // -- get the session sig from the url key - const sessionSig = this.getSessionSigByUrl({ + const sessionSig = this._getSessionSigByUrl({ sessionSigs: params.sessionSigs, url, }); @@ -2007,7 +2007,7 @@ const resourceAbilityRequests = [ const nonce = this.latestBlockhash!; // -- (TRY) to get the wallet signature - let authSig = await this.getWalletSig({ + let authSig = await this.#getWalletSig({ authNeededCallback: params.authNeededCallback, chain: params.chain || 'ethereum', sessionCapabilityObject, diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index 5d56839395..c9780b12e7 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1177,7 +1177,6 @@ export interface LitClientSessionManager { getSessionKey: () => SessionKeyPair; isSessionKeyPair(obj: any): boolean; getExpiration: () => string; - getWalletSig: (getWalletSigProps: GetWalletSigProps) => Promise; getPkpSessionSigs: (params: GetPkpSessionSigs) => Promise; getSessionSigs: (params: GetSessionSigsProps) => Promise; signSessionKey: ( From ca59ef062264190a0fdee9764922f80dd6c67d7d Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:12:27 +0100 Subject: [PATCH 234/263] refactor: protected `this.handleNodePromises` --- packages/core/src/lib/lit-core.ts | 2 +- .../src/lib/lit-node-client-nodejs.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 591e377c41..2f8e2e6104 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -1136,7 +1136,7 @@ export class LitCore { * @param { number } minNodeCount number of nodes we need valid results from in order to resolve * @returns { Promise | RejectedNodePromises> } */ - handleNodePromises = async ( + protected _handleNodePromises = async ( nodePromises: Promise[], requestId: string, minNodeCount: number diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 20f08ae056..56fef4eb78 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -811,7 +811,7 @@ export class LitNodeClientNodeJs nodePromises.push(singleNodePromise); } - const handledPromise = (await this.handleNodePromises( + const handledPromise = (await this._handleNodePromises( nodePromises, id, params.targetNodeRange @@ -936,7 +936,7 @@ export class LitNodeClientNodeJs }); // -- resolve promises - const res = await this.handleNodePromises( + const res = await this._handleNodePromises( nodePromises, requestId, this.connectedNodes.size @@ -1139,7 +1139,7 @@ export class LitNodeClientNodeJs return this.#generatePromise(urlWithPath, reqBody, id); }); - const res = await this.handleNodePromises( + const res = await this._handleNodePromises( nodePromises, id, this.connectedNodes.size // ECDSA requires responses from all nodes, but only shares from minNodeCount. @@ -1292,7 +1292,7 @@ export class LitNodeClientNodeJs }); // -- resolve promises - const res = await this.handleNodePromises( + const res = await this._handleNodePromises( nodePromises, id, this.config.minNodeCount @@ -1556,7 +1556,7 @@ export class LitNodeClientNodeJs }); // -- resolve promises - const res = await this.handleNodePromises( + const res = await this._handleNodePromises( nodePromises, id, this.config.minNodeCount @@ -1759,7 +1759,7 @@ export class LitNodeClientNodeJs // -- resolve promises let res; try { - res = await this.handleNodePromises( + res = await this._handleNodePromises( nodePromises, id, this.connectedNodes.size @@ -2284,7 +2284,7 @@ const resourceAbilityRequests = [ return this.#generatePromise(urlWithPath, reqBody, id); }); - const responseData = await this.handleNodePromises( + const responseData = await this._handleNodePromises( nodePromises, id, this.connectedNodes.size From 2a0328d2475960230856e6d9cb65906f74922581 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:24:57 +0100 Subject: [PATCH 235/263] refactor: privateised `generatePromise` & remove unused imports --- .../src/lib/lit-node-client-nodejs.ts | 442 ++++++++---------- packages/types/src/lib/ILitNodeClient.ts | 27 -- packages/types/src/lib/interfaces.ts | 3 - 3 files changed, 190 insertions(+), 282 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 56fef4eb78..d61916214e 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -1,6 +1,6 @@ import { computeAddress } from '@ethersproject/transactions'; import { BigNumber, ethers } from 'ethers'; -import { joinSignature, sha256 } from 'ethers/lib/utils'; +import { sha256 } from 'ethers/lib/utils'; import { SiweMessage } from 'siwe'; import { @@ -16,7 +16,6 @@ import { createSiweMessage, } from '@lit-protocol/auth-helpers'; import { - AUTH_METHOD_TYPE_IDS, AuthMethodType, EITHER_TYPE, LIT_ACTION_IPFS_HASH, @@ -29,7 +28,6 @@ import { } from '@lit-protocol/constants'; import { LitCore, composeLitUrl } from '@lit-protocol/core'; import { - combineEcdsaShares, combineSignatureShares, encrypt, generateSessionKeyPair, @@ -64,7 +62,6 @@ import { import type { AuthCallback, AuthCallbackParams, - AuthMethod, AuthSig, ClaimKeyResponse, ClaimProcessor, @@ -92,13 +89,11 @@ import type { SessionKeyPair, SessionSigningTemplate, SessionSigsMap, - SigShare, SignSessionKeyProp, SignSessionKeyResponse, Signature, SigningAccessControlConditionRequest, SuccessNodePromises, - WebAuthnAuthenticationVerificationParams, ILitNodeClient, GetPkpSessionSigs, CapacityCreditsReq, @@ -114,14 +109,13 @@ import type { EncryptSdkParams, GetLitActionSessionSigs, EncryptionSignRequest, - GetSignSessionKeySharesProp, JsonPKPClaimKeyRequest, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; import { normalizeJsParams } from './helpers/normalize-params'; import { encodeCode } from './helpers/encode-code'; -import { getFlattenShare, getSignatures } from './helpers/get-signatures'; +import { getSignatures } from './helpers/get-signatures'; import { removeDoubleQuotes } from './helpers/remove-double-quotes'; import { parseAsJsonOrString } from './helpers/parse-as-json-or-string'; import { getClaimsList } from './helpers/get-claims-list'; @@ -336,166 +330,6 @@ export class LitNodeClientNodeJs return { iat, exp }; }; - - // ========== Rate Limit NFT ========== - - // TODO: Add support for browser feature/lit-2321-js-sdk-add-browser-support-for-createCapacityDelegationAuthSig - createCapacityDelegationAuthSig = async ( - params: CapacityCreditsReq - ): Promise => { - // -- validate - if (!params.dAppOwnerWallet) { - throw new Error('dAppOwnerWallet must exist'); - } - - // Useful log for debugging - if (!params.delegateeAddresses || params.delegateeAddresses.length === 0) { - log( - `[createCapacityDelegationAuthSig] 'delegateeAddresses' is an empty array. It means that no body can use it. However, if the 'delegateeAddresses' field is omitted, It means that the capability will not restrict access based on delegatee list, but it may still enforce other restrictions such as usage limits (uses) and specific NFT IDs (nft_id).` - ); - } - - // -- This is the owner address who holds the Capacity Credits NFT token and wants to delegate its - // usage to a list of delegatee addresses - const dAppOwnerWalletAddress = ethers.utils.getAddress( - await params.dAppOwnerWallet.getAddress() - ); - - // -- if it's not ready yet, then connect - if (!this.ready) { - await this.connect(); - } - - const nonce = await this.getLatestBlockhash(); - const siweMessage = await createSiweMessageWithCapacityDelegation({ - uri: 'lit:capability:delegation', - litNodeClient: this, - walletAddress: dAppOwnerWalletAddress, - nonce: nonce, - expiration: params.expiration, - domain: params.domain, - statement: params.statement, - - // -- capacity delegation specific configuration - uses: params.uses, - delegateeAddresses: params.delegateeAddresses, - capacityTokenId: params.capacityTokenId, - }); - - const authSig = await generateAuthSig({ - signer: params.dAppOwnerWallet, - toSign: siweMessage, - }); - - return { capacityDelegationAuthSig: authSig }; - }; - - // ==================== SESSIONS ==================== - /** - * Try to get the session key in the local storage, - * if not, generates one. - * @return { SessionKeyPair } session key pair - */ - getSessionKey = (): SessionKeyPair => { - const storageKey = LOCAL_STORAGE_KEYS.SESSION_KEY; - const storedSessionKeyOrError = getStorageItem(storageKey); - - if ( - storedSessionKeyOrError.type === EITHER_TYPE.ERROR || - !storedSessionKeyOrError.result || - storedSessionKeyOrError.result === '' - ) { - console.warn( - `Storage key "${storageKey}" is missing. Not a problem. Contiune...` - ); - - // Generate new one - const newSessionKey = generateSessionKeyPair(); - - // (TRY) to set to local storage - try { - localStorage.setItem(storageKey, JSON.stringify(newSessionKey)); - } catch (e) { - log( - `[getSessionKey] Localstorage not available.Not a problem.Contiune...` - ); - } - - return newSessionKey; - } else { - return JSON.parse(storedSessionKeyOrError.result as string); - } - }; - - /** - * Check if a given object is of type SessionKeyPair. - * - * @param obj - The object to check. - * @returns True if the object is of type SessionKeyPair. - */ - isSessionKeyPair(obj: any): obj is SessionKeyPair { - return ( - typeof obj === 'object' && - 'publicKey' in obj && - 'secretKey' in obj && - typeof obj.publicKey === 'string' && - typeof obj.secretKey === 'string' - ); - } - - /** - * Generates wildcard capability for each of the LIT resources - * specified. - * @param litResources is an array of LIT resources - * @param addAllCapabilities is a boolean that specifies whether to add all capabilities for each resource - */ - static async generateSessionCapabilityObjectWithWildcards( - litResources: ILitResource[], - addAllCapabilities?: boolean, - rateLimitAuthSig?: AuthSig - ): Promise { - const sessionCapabilityObject = new RecapSessionCapabilityObject({}, []); - - // disable for now - const _addAllCapabilities = addAllCapabilities ?? false; - - if (_addAllCapabilities) { - for (const litResource of litResources) { - sessionCapabilityObject.addAllCapabilitiesForResource(litResource); - } - } - - if (rateLimitAuthSig) { - throw new Error('Not implemented yet.'); - // await sessionCapabilityObject.addRateLimitAuthSig(rateLimitAuthSig); - } - - return sessionCapabilityObject; - } - - // backward compatibility - async generateSessionCapabilityObjectWithWildcards( - litResources: ILitResource[] - ): Promise { - return await LitNodeClientNodeJs.generateSessionCapabilityObjectWithWildcards( - litResources - ); - } - - /** - * - * Get expiration for session default time is 1 day / 24 hours - * - */ - static getExpiration = () => { - return new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(); - }; - - // backward compatibility - getExpiration = () => { - return LitNodeClientNodeJs.getExpiration(); - }; - /** * * Get the signature from local storage, if not, generates one @@ -619,8 +453,6 @@ export class LitNodeClientNodeJs return walletSig!; }; - // ==================== API Calls to Nodes ==================== - /** * * Combine Shares from network public key set and signature shares @@ -670,6 +502,194 @@ export class LitNodeClientNodeJs return finalJwt; }; + /** + * + * Get Session Key URI eg. lit:session:0x1234 + * + * @param publicKey is the public key of the session key + * @returns { string } the session key uri + */ + #getSessionKeyUri = (publicKey: string): string => { + return LIT_SESSION_KEY_URI + publicKey; + }; + /** + * Generates a promise by sending a command to the Lit node + * + * @param url - The URL to send the command to. + * @param params - The parameters to include in the command. + * @param requestId - The ID of the request. + * @returns A promise that resolves with the response from the server. + */ + #generatePromise = async ( + url: string, + params: any, + requestId: string + ): Promise => { + return await this._sendCommandToNode({ + url, + data: params, + requestId, + }); + }; + // ========== Rate Limit NFT ========== + + // TODO: Add support for browser feature/lit-2321-js-sdk-add-browser-support-for-createCapacityDelegationAuthSig + /** + * Creates a capacity delegation authSig. + * + * @param params - The parameters for creating the capacity delegation authSig. + * @returns A promise that resolves to the capacity delegation authSig. + * @throws An error if the dAppOwnerWallet is not provided. + */ + createCapacityDelegationAuthSig = async ( + params: CapacityCreditsReq + ): Promise => { + // -- validate + if (!params.dAppOwnerWallet) { + throw new Error('dAppOwnerWallet must exist'); + } + + // Useful log for debugging + if (!params.delegateeAddresses || params.delegateeAddresses.length === 0) { + log( + `[createCapacityDelegationAuthSig] 'delegateeAddresses' is an empty array. It means that no body can use it. However, if the 'delegateeAddresses' field is omitted, It means that the capability will not restrict access based on delegatee list, but it may still enforce other restrictions such as usage limits (uses) and specific NFT IDs (nft_id).` + ); + } + + // -- This is the owner address who holds the Capacity Credits NFT token and wants to delegate its + // usage to a list of delegatee addresses + const dAppOwnerWalletAddress = ethers.utils.getAddress( + await params.dAppOwnerWallet.getAddress() + ); + + // -- if it's not ready yet, then connect + if (!this.ready) { + await this.connect(); + } + + const nonce = await this.getLatestBlockhash(); + const siweMessage = await createSiweMessageWithCapacityDelegation({ + uri: 'lit:capability:delegation', + litNodeClient: this, + walletAddress: dAppOwnerWalletAddress, + nonce: nonce, + expiration: params.expiration, + domain: params.domain, + statement: params.statement, + + // -- capacity delegation specific configuration + uses: params.uses, + delegateeAddresses: params.delegateeAddresses, + capacityTokenId: params.capacityTokenId, + }); + + const authSig = await generateAuthSig({ + signer: params.dAppOwnerWallet, + toSign: siweMessage, + }); + + return { capacityDelegationAuthSig: authSig }; + }; + + // ==================== SESSIONS ==================== + /** + * Try to get the session key in the local storage, + * if not, generates one. + * @return { SessionKeyPair } session key pair + */ + getSessionKey = (): SessionKeyPair => { + const storageKey = LOCAL_STORAGE_KEYS.SESSION_KEY; + const storedSessionKeyOrError = getStorageItem(storageKey); + + if ( + storedSessionKeyOrError.type === EITHER_TYPE.ERROR || + !storedSessionKeyOrError.result || + storedSessionKeyOrError.result === '' + ) { + console.warn( + `Storage key "${storageKey}" is missing. Not a problem. Contiune...` + ); + + // Generate new one + const newSessionKey = generateSessionKeyPair(); + + // (TRY) to set to local storage + try { + localStorage.setItem(storageKey, JSON.stringify(newSessionKey)); + } catch (e) { + log( + `[getSessionKey] Localstorage not available.Not a problem.Contiune...` + ); + } + + return newSessionKey; + } else { + return JSON.parse(storedSessionKeyOrError.result as string); + } + }; + + /** + * Check if a given object is of type SessionKeyPair. + * + * @param obj - The object to check. + * @returns True if the object is of type SessionKeyPair. + */ + isSessionKeyPair(obj: any): obj is SessionKeyPair { + return ( + typeof obj === 'object' && + 'publicKey' in obj && + 'secretKey' in obj && + typeof obj.publicKey === 'string' && + typeof obj.secretKey === 'string' + ); + } + + /** + * Generates wildcard capability for each of the LIT resources + * specified. + * @param litResources is an array of LIT resources + * @param addAllCapabilities is a boolean that specifies whether to add all capabilities for each resource + */ + static async generateSessionCapabilityObjectWithWildcards( + litResources: ILitResource[], + addAllCapabilities?: boolean + ): Promise { + const sessionCapabilityObject = new RecapSessionCapabilityObject({}, []); + + // disable for now + const _addAllCapabilities = addAllCapabilities ?? false; + + if (_addAllCapabilities) { + for (const litResource of litResources) { + sessionCapabilityObject.addAllCapabilitiesForResource(litResource); + } + } + + return sessionCapabilityObject; + } + + // backward compatibility + async generateSessionCapabilityObjectWithWildcards( + litResources: ILitResource[] + ): Promise { + return await LitNodeClientNodeJs.generateSessionCapabilityObjectWithWildcards( + litResources + ); + } + + /** + * + * Get expiration for session default time is 1 day / 24 hours + * + */ + static getExpiration = () => { + return new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(); + }; + + // backward compatibility + getExpiration = () => { + return LitNodeClientNodeJs.getExpiration(); + }; // ========== Promise Handlers ========== getIpfsId = async ({ @@ -832,40 +852,6 @@ export class LitNodeClientNodeJs ); }; - /** - * - * Get a single signature - * - * @param { Array } shareData from all node promises - * - * @returns { string } signature - * - */ - getSignature = async (shareData: any[], requestId: string): Promise => { - // R_x & R_y values can come from any node (they will be different per node), and will generate a valid signature - const R_x = shareData[0].local_x; - const R_y = shareData[0].local_y; - - const valid_shares = shareData.map((s: any) => s.signature_share); - const shares = JSON.stringify(valid_shares); - - await wasmECDSA.initWasmEcdsaSdk(); // init WASM - const signature = wasmECDSA.combine_signature(R_x, R_y, shares); - logWithRequestId(requestId, 'raw ecdsa sig', signature); - - return signature; - }; - - // ========== Scoped Business Logics ========== - - // Normalize the data to a basic array - - // TODO: executeJsWithTargettedNodes - // if (formattedParams.targetNodeRange) { - // // FIXME: we should make this a separate function - // res = await this.runOnTargetedNodes(formattedParams); - // } - /** * * Execute JS on the nodes and combine and return any resulting signatures @@ -1050,26 +1036,6 @@ export class LitNodeClientNodeJs return returnVal; }; - /** - * Generates a promise by sending a command to the Lit node - * - * @param url - The URL to send the command to. - * @param params - The parameters to include in the command. - * @param requestId - The ID of the request. - * @returns A promise that resolves with the response from the server. - */ - #generatePromise = async ( - url: string, - params: any, - requestId: string - ): Promise => { - return await this._sendCommandToNode({ - url, - data: params, - requestId, - }); - }; - /** * Use PKP to sign * @@ -1931,23 +1897,6 @@ export class LitNodeClientNodeJs return signSessionKeyRes; }; - getSignSessionKeyShares = async ( - url: string, - params: GetSignSessionKeySharesProp, - requestId: string - ) => { - log('getSignSessionKeyShares'); - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, - }); - return await this._sendCommandToNode({ - url: urlWithPath, - data: params.body, - requestId, - }); - }; - /** * Get session signatures for a set of resources * @@ -2224,17 +2173,6 @@ const resourceAbilityRequests = [ return this.getPkpSessionSigs(params); }; - /** - * - * Get Session Key URI eg. lit:session:0x1234 - * - * @param publicKey is the public key of the session key - * @returns { string } the session key uri - */ - #getSessionKeyUri = (publicKey: string): string => { - return LIT_SESSION_KEY_URI + publicKey; - }; - /** * Authenticates an Auth Method for claiming a Programmable Key Pair (PKP). * A {@link MintCallback} can be defined for custom on chain interactions diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index 0b108090a7..bc36f3da04 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -64,33 +64,6 @@ export interface ILitNodeClient { // ========== Promise Handlers ========== - /** - * Handle node promises - * - * @param { Array> } nodePromises - * - * @param {string} requestId request Id used for logging - * @param {number} minNodeCount The minimum number of nodes we need a successful response from to continue - * @returns { Promise | RejectedNodePromises> } - * - */ - handleNodePromises( - nodePromises: Promise[], - requestId: string, - minNodeCount: number - ): Promise | RejectedNodePromises>; - - /** - * - * Get Signature - * - * @param { Array } shareData from all node promises - * - * @returns { string } signature - * - */ - getSignature(shareData: any[], requestId: string): Promise; - /** * * Get JS Execution Shares from Nodes diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index c9780b12e7..852f907060 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1053,9 +1053,6 @@ export interface SignSessionKeyResponse { authSig: AuthSig; } -export interface GetSignSessionKeySharesProp { - body: SessionRequestBody; -} export interface CommonGetSessionSigsProps { pkpPublicKey?: string; From e13ce8359d6aa29e1cb6d695a853497e0c49f0a9 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 15:59:04 +0100 Subject: [PATCH 236/263] chore: prettier --- packages/misc/src/lib/misc.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/misc/src/lib/misc.ts b/packages/misc/src/lib/misc.ts index 83afda633a..1456dd4c4b 100644 --- a/packages/misc/src/lib/misc.ts +++ b/packages/misc/src/lib/misc.ts @@ -915,4 +915,3 @@ export function normalizeAndStringify(input: string): string { return normalizeAndStringify(unescaped); } } - From 1662e653bbbe28a738002010cc4d5bc0ca8aef3e Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 18:56:42 +0100 Subject: [PATCH 237/263] chore: reorganised code placement --- .../src/lib/lit-node-client-nodejs.ts | 2208 ++++++++--------- 1 file changed, 1103 insertions(+), 1105 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index d61916214e..c51cce25e5 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -202,7 +202,6 @@ export class LitNodeClientNodeJs return authSig; }; - /** * * Check if a session key needs to be resigned. These are the scenarios where a session key needs to be resigned: @@ -854,21 +853,26 @@ export class LitNodeClientNodeJs /** * - * Execute JS on the nodes and combine and return any resulting signatures + * Encrypt data using the LIT network public key. * - * @param { JsonExecutionSdkParams } params + * @param { EncryptSdkParams } params + * @param params.dataToEncrypt - The data to encrypt + * @param params.accessControlConditions - (optional) The access control conditions for the data + * @param params.evmContractConditions - (optional) The EVM contract conditions for the data + * @param params.solRpcConditions - (optional) The Solidity RPC conditions for the data + * @param params.unifiedAccessControlConditions - (optional) The unified access control conditions for the data * - * @returns { ExecuteJsResponse } + * @return { Promise } The encrypted ciphertext and the hash of the data * + * @throws { Error } if the LIT node client is not ready + * @throws { Error } if the subnetPubKey is null */ - executeJs = async ( - params: JsonExecutionSdkParams - ): Promise => { + encrypt = async (params: EncryptSdkParams): Promise => { // ========== Validate Params ========== + // -- validate if it's ready if (!this.ready) { const message = - '[executeJs] LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; - + '6 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; throwError({ message, errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, @@ -876,393 +880,522 @@ export class LitNodeClientNodeJs }); } + // -- validate if this.subnetPubKey is null + if (!this.subnetPubKey) { + const message = 'subnetPubKey cannot be null'; + return throwError({ + message, + errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, + errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, + }); + } + const paramsIsSafe = safeParams({ - functionName: 'executeJs', - params: params, + functionName: 'encrypt', + params, }); if (!paramsIsSafe) { return throwError({ - message: 'executeJs params are not valid', - errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, - errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, + message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); } - // Format the params - const formattedParams: JsonExecutionSdkParams = { - ...params, - ...(params.jsParams && { jsParams: normalizeJsParams(params.jsParams) }), - ...(params.code && { code: encodeCode(params.code) }), - }; - - // ========== Get Node Promises ========== - // Handle promises for commands sent to Lit nodes - const wrapper = async ( - requestId: string - ): Promise | RejectedNodePromises> => { - const nodePromises = this._getNodePromises(async (url: string) => { - // -- choose the right signature - const sessionSig = this._getSessionSigByUrl({ - sessionSigs: formattedParams.sessionSigs, - url, - }); - - const reqBody: JsonExecutionRequest = { - ...formattedParams, - authSig: sessionSig, - }; + // ========== Validate Access Control Conditions Schema ========== + await this.validateAccessControlConditionsSchema(params); - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.EXECUTE_JS, - }); + // ========== Hashing Access Control Conditions ========= + // hash the access control conditions + const hashOfConditions: ArrayBuffer | undefined = + await this.getHashedAccessControlConditions(params); - return this.#generatePromise(urlWithPath, reqBody, requestId); + if (!hashOfConditions) { + return throwError({ + message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); - - // -- resolve promises - const res = await this._handleNodePromises( - nodePromises, - requestId, - this.connectedNodes.size - ); - - return res; - }; // wrapper end - - // ========== Execute with Retry ========== - const res = await executeWithRetry< - RejectedNodePromises | SuccessNodePromises - >( - wrapper, - (error: any, requestId: string, isFinal: boolean) => { - logError('an error occured, attempting to retry operation'); - }, - this.config.retryTolerance - ); - - // ========== Handle Response ========== - const requestId = res.requestId; - - // -- case: promises rejected - if (!res.success) { - this._throwNodeError(res as RejectedNodePromises, requestId); } - // -- case: promises success (TODO: check the keys of "values") - const responseData = (res as SuccessNodePromises).values; + const hashOfConditionsStr = uint8arrayToString( + new Uint8Array(hashOfConditions), + 'base16' + ); - logWithRequestId( - requestId, - 'executeJs responseData from node : ', - JSON.stringify(responseData, null, 2) + // ========== Hashing Private Data ========== + // hash the private data + const hashOfPrivateData = await crypto.subtle.digest( + 'SHA-256', + params.dataToEncrypt + ); + const hashOfPrivateDataStr = uint8arrayToString( + new Uint8Array(hashOfPrivateData), + 'base16' ); - // -- find the responseData that has the most common response - const mostCommonResponse = findMostCommonResponse( - responseData - ) as NodeShare; + // ========== Assemble identity parameter ========== + const identityParam = this.#getIdentityParamForEncryption( + hashOfConditionsStr, + hashOfPrivateDataStr + ); - const responseFromStrategy: any = processLitActionResponseStrategy( - responseData, - params.responseStrategy ?? { strategy: 'leastCommon' } + // ========== Encrypt ========== + const ciphertext = encrypt( + this.subnetPubKey, + params.dataToEncrypt, + uint8arrayFromString(identityParam, 'utf8') ); - mostCommonResponse.response = responseFromStrategy; - const isSuccess = mostCommonResponse.success; - const hasSignedData = Object.keys(mostCommonResponse.signedData).length > 0; - const hasClaimData = Object.keys(mostCommonResponse.claimData).length > 0; + return { ciphertext, dataToEncryptHash: hashOfPrivateDataStr }; + }; - // -- we must also check for claim responses as a user may have submitted for a claim and signatures must be aggregated before returning - if (isSuccess && !hasSignedData && !hasClaimData) { - return mostCommonResponse as unknown as ExecuteJsResponse; - } + getLitResourceForEncryption = async ( + params: EncryptRequest + ): Promise => { + // ========== Hashing Access Control Conditions ========= + // hash the access control conditions + const hashOfConditions: ArrayBuffer | undefined = + await this.getHashedAccessControlConditions(params); - // -- in the case where we are not signing anything on Lit action and using it as purely serverless function - if (!hasSignedData && !hasClaimData) { - return { - claims: {}, - signatures: null, - decryptions: [], - response: mostCommonResponse.response, - logs: mostCommonResponse.logs, - } as ExecuteJsNoSigningResponse; + if (!hashOfConditions) { + return throwError({ + message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); } - // ========== Extract shares from response data ========== - - // -- 1. combine signed data as a list, and get the signatures from it - const signedDataList = responseData.map((r) => { - return removeDoubleQuotes(r.signedData); - }); - - logWithRequestId( - requestId, - 'signatures shares to combine: ', - signedDataList + const hashOfConditionsStr = uint8arrayToString( + new Uint8Array(hashOfConditions), + 'base16' ); - const signatures = getSignatures({ - requestId, - networkPubKeySet: this.networkPubKeySet, - minNodeCount: this.config.minNodeCount, - signedData: signedDataList, - }); - - // -- 2. combine responses as a string, and parse it as JSON if possible - const parsedResponse = parseAsJsonOrString(mostCommonResponse.response); - - // -- 3. combine logs - const mostCommonLogs: string = mostCommonString( - responseData.map((r: NodeLog) => r.logs) + // ========== Hashing Private Data ========== + // hash the private data + const hashOfPrivateData = await crypto.subtle.digest( + 'SHA-256', + params.dataToEncrypt + ); + const hashOfPrivateDataStr = uint8arrayToString( + new Uint8Array(hashOfPrivateData), + 'base16' ); - // -- 4. combine claims - const claimsList = getClaimsList(responseData); - const claims = claimsList.length > 0 ? getClaims(claimsList) : undefined; - - // ========== Result ========== - const returnVal: ExecuteJsResponse = { - claims, - signatures, - // decryptions: [], - response: parsedResponse, - logs: mostCommonLogs, - }; - - log('returnVal:', returnVal); - - return returnVal; + return new LitAccessControlConditionResource( + `${hashOfConditionsStr}/${hashOfPrivateDataStr}` + ); }; + /** ============================== SESSION ============================== */ /** - * Use PKP to sign + * Get session signatures for a set of resources * - * @param { JsonPkpSignSdkParams } params - * @param params.toSign - The data to sign - * @param params.pubKey - The public key to sign with - * @param params.sessionSigs - The session signatures to use - * @param params.authMethods - (optional) The auth methods to use - */ - pkpSign = async (params: JsonPkpSignSdkParams): Promise => { - // -- validate required params - const requiredParamKeys = ['toSign', 'pubKey']; - - (requiredParamKeys as (keyof JsonPkpSignSdkParams)[]).forEach((key) => { - if (!params[key]) { - throwError({ - message: `"${key}" cannot be undefined, empty, or null. Please provide a valid value.`, - errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, - errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, - }); - } - }); - - // -- validate present of accepted auth methods - if ( - !params.sessionSigs && - (!params.authMethods || params.authMethods.length <= 0) - ) { + * High level, how this works: + * 1. Generate or retrieve session key + * 2. Generate or retrieve the wallet signature of the session key + * 3. Sign the specific resources with the session key + * + * Note: When generating session signatures for different PKPs or auth methods, + * be sure to call disconnectWeb3 to clear auth signatures stored in local storage + * + * @param { GetSessionSigsProps } params + * + * @example + * + * ```ts + * import { LitPKPResource, LitActionResource } from "@lit-protocol/auth-helpers"; +import { LitAbility } from "@lit-protocol/types"; +import { logWithRequestId } from '../../../misc/src/lib/misc'; + +const resourceAbilityRequests = [ + { + resource: new LitPKPResource("*"), + ability: LitAbility.PKPSigning, + }, + { + resource: new LitActionResource("*"), + ability: LitAbility.LitActionExecution, + }, + ]; + * ``` + */ + getSessionSigs = async ( + params: GetSessionSigsProps + ): Promise => { + // -- prepare + // Try to get it from local storage, if not generates one~ + const sessionKey = params.sessionKey ?? this.getSessionKey(); + + const sessionKeyUri = this.#getSessionKeyUri(sessionKey.publicKey); + + // First get or generate the session capability object for the specified resources. + const sessionCapabilityObject = params.sessionCapabilityObject + ? params.sessionCapabilityObject + : await this.generateSessionCapabilityObjectWithWildcards( + params.resourceAbilityRequests.map((r) => r.resource) + ); + const expiration = params.expiration || LitNodeClientNodeJs.getExpiration(); + + if (!this.latestBlockhash) { throwError({ - message: `Either sessionSigs or authMethods (length > 0) must be present.`, - errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, - errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, + message: 'Eth Blockhash is undefined.', + errorKind: LIT_ERROR.INVALID_ETH_BLOCKHASH.kind, + errorCode: LIT_ERROR.INVALID_ETH_BLOCKHASH.name, }); } + const nonce = this.latestBlockhash!; - // ========== Get Node Promises ========== - // Handle promises for commands sent to Lit nodes - const wrapper = async ( - id: string - ): Promise | RejectedNodePromises> => { - const nodePromises = this._getNodePromises((url: string) => { - // -- get the session sig from the url key - const sessionSig = this._getSessionSigByUrl({ - sessionSigs: params.sessionSigs, - url, - }); + // -- (TRY) to get the wallet signature + let authSig = await this.#getWalletSig({ + authNeededCallback: params.authNeededCallback, + chain: params.chain || 'ethereum', + sessionCapabilityObject, + switchChain: params.switchChain, + expiration: expiration, + sessionKey: sessionKey, + sessionKeyUri: sessionKeyUri, + nonce, - const reqBody: JsonPkpSignRequest = { - toSign: normalizeArray(params.toSign), - pubkey: hexPrefixed(params.pubKey), - authSig: sessionSig, + // -- for recap + resourceAbilityRequests: params.resourceAbilityRequests, - // -- optional params - ...(params.authMethods && - params.authMethods.length > 0 && { - authMethods: params.authMethods, - }), - }; + // -- optional fields + ...(params.litActionCode && { litActionCode: params.litActionCode }), + ...(params.litActionIpfsId && { + litActionIpfsId: params.litActionIpfsId, + }), + ...(params.jsParams && { jsParams: params.jsParams }), + }); - logWithRequestId(id, 'reqBody:', reqBody); + const needToResignSessionKey = await this.#checkNeedToResignSessionKey({ + authSig, + sessionKeyUri, + resourceAbilityRequests: params.resourceAbilityRequests, + }); - const urlWithPath = composeLitUrl({ - url, - endpoint: LIT_ENDPOINT.PKP_SIGN, - }); + // -- (CHECK) if we need to resign the session key + if (needToResignSessionKey) { + log('need to re-sign session key. Signing...'); + authSig = await this.#authCallbackAndUpdateStorageItem({ + authCallback: params.authNeededCallback, + authCallbackParams: { + chain: params.chain || 'ethereum', + statement: sessionCapabilityObject.statement, + resources: [sessionCapabilityObject.encodeAsSiweResource()], + switchChain: params.switchChain, + expiration, + sessionKey: sessionKey, + uri: sessionKeyUri, + nonce, + resourceAbilityRequests: params.resourceAbilityRequests, - return this.#generatePromise(urlWithPath, reqBody, id); + // -- optional fields + ...(params.litActionCode && { litActionCode: params.litActionCode }), + ...(params.litActionIpfsId && { + litActionIpfsId: params.litActionIpfsId, + }), + ...(params.jsParams && { jsParams: params.jsParams }), + }, }); + } - const res = await this._handleNodePromises( - nodePromises, - id, - this.connectedNodes.size // ECDSA requires responses from all nodes, but only shares from minNodeCount. - ); - return res; - }; // wrapper end + if ( + authSig.address === '' || + authSig.derivedVia === '' || + authSig.sig === '' || + authSig.signedMessage === '' + ) { + throwError({ + message: 'No wallet signature found', + errorKind: LIT_ERROR.WALLET_SIGNATURE_NOT_FOUND_ERROR.kind, + errorCode: LIT_ERROR.WALLET_SIGNATURE_NOT_FOUND_ERROR.name, + }); + // @ts-ignore - we throw an error above, so below should never be reached + return; + } - // ========== Execute with Retry ========== - const res = await executeWithRetry< - RejectedNodePromises | SuccessNodePromises - >( - wrapper, - (error: any, requestId: string, isFinal: boolean) => { - if (!isFinal) { - logError('errror occured, retrying operation'); - } - }, - this.config.retryTolerance - ); + // ===== AFTER we have Valid Signed Session Key ===== + // - Let's sign the resources with the session key + // - 5 minutes is the default expiration for a session signature + // - Because we can generate a new session sig every time the user wants to access a resource without prompting them to sign with their wallet + const sessionExpiration = + expiration ?? new Date(Date.now() + 1000 * 60 * 5).toISOString(); - // ========== Handle Response ========== - const requestId = res.requestId; + const capabilities = params.capacityDelegationAuthSig + ? [ + ...(params.capabilityAuthSigs ?? []), + params.capacityDelegationAuthSig, + authSig, + ] + : [...(params.capabilityAuthSigs ?? []), authSig]; - // -- case: promises rejected - if (!res.success) { - this._throwNodeError(res as RejectedNodePromises, requestId); - } + const signingTemplate = { + sessionKey: sessionKey.publicKey, + resourceAbilityRequests: params.resourceAbilityRequests, + capabilities, + issuedAt: new Date().toISOString(), + expiration: sessionExpiration, + }; - // -- case: promises success (TODO: check the keys of "values") - const responseData = (res as SuccessNodePromises).values; + const signatures: SessionSigsMap = {}; - logWithRequestId( - requestId, - 'responseData', - JSON.stringify(responseData, null, 2) - ); + this.connectedNodes.forEach((nodeAddress: string) => { + const toSign: SessionSigningTemplate = { + ...signingTemplate, + nodeAddress, + }; - // ========== Extract shares from response data ========== - // -- 1. combine signed data as a list, and get the signatures from it - const signedDataList = parsePkpSignResponse(responseData); + const signedMessage = JSON.stringify(toSign); - const signatures = getSignatures<{ signature: SigResponse }>({ - requestId, - networkPubKeySet: this.networkPubKeySet, - minNodeCount: this.config.minNodeCount, - signedData: signedDataList, + const uint8arrayKey = uint8arrayFromString( + sessionKey.secretKey, + 'base16' + ); + + const uint8arrayMessage = uint8arrayFromString(signedMessage, 'utf8'); + const signature = nacl.sign.detached(uint8arrayMessage, uint8arrayKey); + + signatures[nodeAddress] = { + sig: uint8arrayToString(signature, 'base16'), + derivedVia: 'litSessionSignViaNacl', + signedMessage: signedMessage, + address: sessionKey.publicKey, + algo: 'ed25519', + }; }); - logWithRequestId(requestId, `signature combination`, signatures); + log('signatures:', signatures); - return signatures.signature; // only a single signature is ever present, so we just return it. + return signatures; }; /** + * Retrieves the PKP sessionSigs. * - * Request a signed JWT from the LIT network. Before calling this function, you must know the access control conditions for the item you wish to gain authorization for. - * - * @param { GetSignedTokenRequest } params - * - * @returns { Promise } final JWT - * + * @param params - The parameters for retrieving the PKP sessionSigs. + * @returns A promise that resolves to the PKP sessionSigs. + * @throws An error if any of the required parameters are missing or if `litActionCode` and `ipfsId` exist at the same time. */ - getSignedToken = async (params: GetSignedTokenRequest): Promise => { - // ========== Prepare Params ========== - const { chain, authSig, sessionSigs } = params; + getPkpSessionSigs = async (params: GetPkpSessionSigs) => { + const chain = params?.chain || 'ethereum'; - // ========== Validation ========== - // -- validate if it's ready - if (!this.ready) { - const message = - '3 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; - throwError({ - message, - errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, - errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, - }); + const pkpSessionSigs = this.getSessionSigs({ + chain, + ...params, + authNeededCallback: async (props: AuthCallbackParams) => { + // -- validate + if (!props.expiration) { + throw new Error( + '[getPkpSessionSigs/callback] expiration is required' + ); + } + + if (!props.resources) { + throw new Error('[getPkpSessionSigs/callback]resources is required'); + } + + if (!props.resourceAbilityRequests) { + throw new Error( + '[getPkpSessionSigs/callback]resourceAbilityRequests is required' + ); + } + + // lit action code and ipfs id cannot exist at the same time + if (props.litActionCode && props.litActionIpfsId) { + throw new Error( + '[getPkpSessionSigs/callback]litActionCode and litActionIpfsId cannot exist at the same time' + ); + } + + /** + * We must provide an empty array for authMethods even if we are not using any auth methods. + * So that the nodes can serialize the request correctly. + */ + const authMethods = params.authMethods || []; + + const response = await this.signSessionKey({ + sessionKey: props.sessionKey, + statement: props.statement || 'Some custom statement.', + authMethods: [...authMethods], + pkpPublicKey: params.pkpPublicKey, + expiration: props.expiration, + resources: props.resources, + chainId: 1, + + // -- required fields + resourceAbilityRequests: props.resourceAbilityRequests, + + // -- optional fields + ...(props.litActionCode && { litActionCode: props.litActionCode }), + ...(props.litActionIpfsId && { + litActionIpfsId: props.litActionIpfsId, + }), + ...(props.jsParams && { jsParams: props.jsParams }), + }); + + return response.authSig; + }, + }); + + return pkpSessionSigs; + }; + + /** + * Retrieves session signatures specifically for Lit Actions. + * Unlike `getPkpSessionSigs`, this function requires either `litActionCode` or `litActionIpfsId`, and `jsParams` must be provided. + * + * @param params - The parameters required for retrieving the session signatures. + * @returns A promise that resolves with the session signatures. + */ + getLitActionSessionSigs = async (params: GetLitActionSessionSigs) => { + // Check if either litActionCode or litActionIpfsId is provided + if (!params.litActionCode && !params.litActionIpfsId) { + throw new Error( + "Either 'litActionCode' or 'litActionIpfsId' must be provided." + ); } - // -- validate if this.networkPubKeySet is null - if (this.networkPubKeySet === null) { - return throwError({ - message: 'networkPubKeySet cannot be null', - errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, - errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, - }); + // Check if jsParams is provided + if (!params.jsParams) { + throw new Error("'jsParams' is required."); } - const paramsIsSafe = safeParams({ - functionName: 'getSignedToken', - params, - }); + return this.getPkpSessionSigs(params); + }; - if (!paramsIsSafe) { - return throwError({ - message: `Parameter validation failed.`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + /** ============================== END POINTS ============================== */ + /** + * Sign a session public key using a PKP, which generates an authSig. + * @returns {Object} An object containing the resulting signature. + */ + signSessionKey = async ( + params: SignSessionKeyProp + ): Promise => { + log(`[signSessionKey] params:`, params); + + // ========== Validate Params ========== + // -- validate: If it's NOT ready + if (!this.ready) { + const message = + '[signSessionKey] ]LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; + + throwError({ + message, + errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, + errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, }); } - // ========== Prepare ========== - // we need to send jwt params iat (issued at) and exp (expiration) - // because the nodes may have different wall clock times - // the nodes will verify that these params are withing a grace period - const { iat, exp } = this.#getJWTParams(); + // -- construct SIWE message that will be signed by node to generate an authSig. + const _expiration = + params.expiration || + new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(); - // ========== Formatting Access Control Conditions ========= - const { - error, - formattedAccessControlConditions, - formattedEVMContractConditions, - formattedSolRpcConditions, - formattedUnifiedAccessControlConditions, - }: FormattedMultipleAccs = this.getFormattedAccessControlConditions(params); + // Try to get it from local storage, if not generates one~ + const sessionKey: SessionKeyPair = + params.sessionKey ?? this.getSessionKey(); + const sessionKeyUri = LIT_SESSION_KEY_URI + sessionKey.publicKey; - if (error) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + log( + `[signSessionKey] sessionKeyUri is not found in params, generating a new one`, + sessionKeyUri + ); + + if (!sessionKeyUri) { + throw new Error( + '[signSessionKey] sessionKeyUri is not defined. Please provide a sessionKeyUri or a sessionKey.' + ); + } + + // Compute the address from the public key if it's provided. Otherwise, the node will compute it. + const pkpEthAddress = (function () { + // prefix '0x' if it's not already prefixed + params.pkpPublicKey = hexPrefixed(params.pkpPublicKey!); + + if (params.pkpPublicKey) return computeAddress(params.pkpPublicKey); + + // This will be populated by the node, using dummy value for now. + return '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; + })(); + + let siwe_statement = 'Lit Protocol PKP session signature'; + if (params.statement) { + siwe_statement += ' ' + params.statement; + log(`[signSessionKey] statement found in params: "${params.statement}"`); + } + + let siweMessage; + + const siweParams = { + domain: params?.domain || globalThis.location?.host || 'litprotocol.com', + walletAddress: pkpEthAddress, + statement: siwe_statement, + uri: sessionKeyUri, + version: '1', + chainId: params.chainId ?? 1, + expiration: _expiration, + nonce: this.latestBlockhash!, + }; + + if (params.resourceAbilityRequests) { + siweMessage = await createSiweMessageWithRecaps({ + ...siweParams, + resources: params.resourceAbilityRequests, + litNodeClient: this, }); + } else { + siweMessage = await createSiweMessage(siweParams); } // ========== Get Node Promises ========== + // -- fetch shares from nodes + const body: JsonSignSessionKeyRequestV1 = { + sessionKey: sessionKeyUri, + authMethods: params.authMethods, + ...(params?.pkpPublicKey && { pkpPublicKey: params.pkpPublicKey }), + siweMessage: siweMessage, + curveType: LIT_CURVE.BLS, + + // -- custom auths + ...(params?.litActionIpfsId && { + litActionIpfsId: params.litActionIpfsId, + }), + ...(params?.litActionCode && { code: params.litActionCode }), + ...(params?.jsParams && { jsParams: params.jsParams }), + ...(this.currentEpochNumber && { epoch: this.currentEpochNumber }), + }; + + log(`[signSessionKey] body:`, body); + const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { + logWithRequestId(id, 'signSessionKey body', body); const nodePromises = this._getNodePromises((url: string) => { - // -- if session key is available, use it - const authSigToSend = sessionSigs ? sessionSigs[url] : authSig; - - const reqBody: SigningAccessControlConditionRequest = { - accessControlConditions: formattedAccessControlConditions, - evmContractConditions: formattedEVMContractConditions, - solRpcConditions: formattedSolRpcConditions, - unifiedAccessControlConditions: - formattedUnifiedAccessControlConditions, - chain, - authSig: authSigToSend, - iat, - exp, - }; + const reqBody: JsonSignSessionKeyRequestV1 = body; const urlWithPath = composeLitUrl({ url, - endpoint: LIT_ENDPOINT.SIGN_ACCS, + endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, }); return this.#generatePromise(urlWithPath, reqBody, id); }); // -- resolve promises - const res = await this._handleNodePromises( - nodePromises, - id, - this.config.minNodeCount - ); + let res; + try { + res = await this._handleNodePromises( + nodePromises, + id, + this.connectedNodes.size + ); + log('signSessionKey node promises:', res); + } catch (e) { + throw new Error(`Error when handling node promises: ${e}`); + } return res; }; @@ -1270,159 +1403,180 @@ export class LitNodeClientNodeJs RejectedNodePromises | SuccessNodePromises >( wrapper, - (error: any, requestId: string, isFinal: boolean) => { + (_error: any, _requestId: string, isFinal: boolean) => { if (!isFinal) { logError('an error occured, attempting to retry '); } }, this.config.retryTolerance ); + const requestId = res.requestId; + logWithRequestId(requestId, 'handleNodePromises res:', res); // -- case: promises rejected - if (res.success === false) { + if (!this.#isSuccessNodePromises(res)) { this._throwNodeError(res as RejectedNodePromises, requestId); + return {} as SignSessionKeyResponse; } - const signatureShares: NodeBlsSigningShare[] = ( - res as SuccessNodePromises - ).values; - - log('signatureShares', signatureShares); - - // ========== Result ========== - const finalJwt: string = this.#combineSharesAndGetJWT( - signatureShares, - requestId + const responseData: BlsResponseData[] = res.values; + logWithRequestId( + requestId, + '[signSessionKey] responseData', + JSON.stringify(responseData, null, 2) ); - return finalJwt; - }; + // ========== Extract shares from response data ========== + // -- 1. combine signed data as a list, and get the signatures from it + let curveType = responseData[0]?.curveType; - /** - * - * Encrypt data using the LIT network public key. - * - * @param { EncryptSdkParams } params - * @param params.dataToEncrypt - The data to encrypt - * @param params.accessControlConditions - (optional) The access control conditions for the data - * @param params.evmContractConditions - (optional) The EVM contract conditions for the data - * @param params.solRpcConditions - (optional) The Solidity RPC conditions for the data - * @param params.unifiedAccessControlConditions - (optional) The unified access control conditions for the data - * - * @return { Promise } The encrypted ciphertext and the hash of the data - * - * @throws { Error } if the LIT node client is not ready - * @throws { Error } if the subnetPubKey is null - */ - encrypt = async (params: EncryptSdkParams): Promise => { - // ========== Validate Params ========== - // -- validate if it's ready - if (!this.ready) { - const message = - '6 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; - throwError({ - message, - errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, - errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, - }); + if (!curveType) { + log(`[signSessionKey] curveType not found. Defaulting to ECDSA.`); + curveType = 'ECDSA'; } - // -- validate if this.subnetPubKey is null - if (!this.subnetPubKey) { - const message = 'subnetPubKey cannot be null'; - return throwError({ - message, - errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, - errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, - }); - } + log(`[signSessionKey] curveType is "${curveType}"`); - const paramsIsSafe = safeParams({ - functionName: 'encrypt', - params, - }); + let signedDataList = responseData.map((s) => s.dataSigned); - if (!paramsIsSafe) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); + if (signedDataList.length <= 0) { + const err = `[signSessionKey] signedDataList is empty.`; + log(err); + throw new Error(err); } - // ========== Validate Access Control Conditions Schema ========== - await this.validateAccessControlConditionsSchema(params); + logWithRequestId( + requestId, + '[signSessionKey] signedDataList', + signedDataList + ); - // ========== Hashing Access Control Conditions ========= - // hash the access control conditions - const hashOfConditions: ArrayBuffer | undefined = - await this.getHashedAccessControlConditions(params); + // -- checking if we have enough shares + const validatedSignedDataList = responseData + .map((data: BlsResponseData) => { + // each of this field cannot be empty + let requiredFields = [ + 'signatureShare', + 'curveType', + 'shareIndex', + 'siweMessage', + 'dataSigned', + 'blsRootPubkey', + 'result', + ]; - if (!hashOfConditions) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } + // check if all required fields are present + for (const field of requiredFields) { + const key: keyof BlsResponseData = field as keyof BlsResponseData; - const hashOfConditionsStr = uint8arrayToString( - new Uint8Array(hashOfConditions), - 'base16' - ); + if (!data[key] || data[key] === '') { + log( + `[signSessionKey] Invalid signed data. "${field}" is missing. Not a problem, we only need ${this.config.minNodeCount} nodes to sign the session key.` + ); + return null; + } + } - // ========== Hashing Private Data ========== - // hash the private data - const hashOfPrivateData = await crypto.subtle.digest( - 'SHA-256', - params.dataToEncrypt + if (!data.signatureShare.ProofOfPossession) { + const err = `[signSessionKey] Invalid signed data. "ProofOfPossession" is missing.`; + log(err); + throw new Error(err); + } + + return data; + }) + .filter((item) => item !== null); + + logWithRequestId( + requestId, + '[signSessionKey] requested length:', + signedDataList.length ); - const hashOfPrivateDataStr = uint8arrayToString( - new Uint8Array(hashOfPrivateData), - 'base16' + logWithRequestId( + requestId, + '[signSessionKey] validated length:', + validatedSignedDataList.length + ); + logWithRequestId( + requestId, + '[signSessionKey] minimum required length:', + this.config.minNodeCount ); + if (validatedSignedDataList.length < this.config.minNodeCount) { + throw new Error( + `[signSessionKey] not enough nodes signed the session key. Expected ${this.config.minNodeCount}, got ${validatedSignedDataList.length}` + ); + } - // ========== Assemble identity parameter ========== - const identityParam = this.#getIdentityParamForEncryption( - hashOfConditionsStr, - hashOfPrivateDataStr + const blsSignedData: BlsResponseData[] = + validatedSignedDataList as BlsResponseData[]; + + const sigType = mostCommonString(blsSignedData.map((s) => s.curveType)); + log(`[signSessionKey] sigType:`, sigType); + + const signatureShares = getBlsSignatures(blsSignedData); + + log(`[signSessionKey] signatureShares:`, signatureShares); + + const blsCombinedSignature = blsSdk.combine_signature_shares( + signatureShares.map((s) => JSON.stringify(s)) ); - // ========== Encrypt ========== - const ciphertext = encrypt( - this.subnetPubKey, - params.dataToEncrypt, - uint8arrayFromString(identityParam, 'utf8') + log(`[signSessionKey] blsCombinedSignature:`, blsCombinedSignature); + + const publicKey = removeHexPrefix(params.pkpPublicKey); + log(`[signSessionKey] publicKey:`, publicKey); + + const dataSigned = mostCommonString( + blsSignedData.map((s: any) => s.dataSigned) ); + log(`[signSessionKey] dataSigned:`, dataSigned); - return { ciphertext, dataToEncryptHash: hashOfPrivateDataStr }; + const mostCommonSiweMessage = mostCommonString( + blsSignedData.map((s: any) => s.siweMessage) + ); + + log(`[signSessionKey] mostCommonSiweMessage:`, mostCommonSiweMessage); + + const signedMessage = normalizeAndStringify(mostCommonSiweMessage); + + log(`[signSessionKey] signedMessage:`, signedMessage); + + const signSessionKeyRes: SignSessionKeyResponse = { + authSig: { + sig: JSON.stringify({ + ProofOfPossession: blsCombinedSignature, + }), + algo: 'LIT_BLS', + derivedVia: 'lit.bls', + signedMessage, + address: computeAddress(hexPrefixed(publicKey)), + }, + pkpPublicKey: publicKey, + }; + + return signSessionKeyRes; }; /** * - * Decrypt ciphertext with the LIT network. + * Execute JS on the nodes and combine and return any resulting signatures + * + * @param { JsonExecutionSdkParams } params + * + * @returns { ExecuteJsResponse } * */ - decrypt = async (params: DecryptRequest): Promise => { - const { sessionSigs, chain, ciphertext, dataToEncryptHash } = params; - + executeJs = async ( + params: JsonExecutionSdkParams + ): Promise => { // ========== Validate Params ========== - // -- validate if it's ready if (!this.ready) { const message = - '6 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; - throwError({ - message, - errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, - errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, - }); - } + '[executeJs] LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; - // -- validate if this.subnetPubKey is null - if (!this.subnetPubKey) { - const message = 'subnetPubKey cannot be null'; - return throwError({ + throwError({ message, errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, @@ -1430,762 +1584,582 @@ export class LitNodeClientNodeJs } const paramsIsSafe = safeParams({ - functionName: 'decrypt', - params, + functionName: 'executeJs', + params: params, }); if (!paramsIsSafe) { return throwError({ - message: `Parameter validation failed.`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + message: 'executeJs params are not valid', + errorKind: LIT_ERROR.INVALID_PARAM_TYPE.kind, + errorCode: LIT_ERROR.INVALID_PARAM_TYPE.name, }); } - // ========== Hashing Access Control Conditions ========= - // hash the access control conditions - const hashOfConditions: ArrayBuffer | undefined = - await this.getHashedAccessControlConditions(params); + // Format the params + const formattedParams: JsonExecutionSdkParams = { + ...params, + ...(params.jsParams && { jsParams: normalizeJsParams(params.jsParams) }), + ...(params.code && { code: encodeCode(params.code) }), + }; - if (!hashOfConditions) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } - - const hashOfConditionsStr = uint8arrayToString( - new Uint8Array(hashOfConditions), - 'base16' - ); - - // ========== Formatting Access Control Conditions ========= - const { - error, - formattedAccessControlConditions, - formattedEVMContractConditions, - formattedSolRpcConditions, - formattedUnifiedAccessControlConditions, - }: FormattedMultipleAccs = this.getFormattedAccessControlConditions(params); - - if (error) { - throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } - - // ========== Assemble identity parameter ========== - const identityParam = this.#getIdentityParamForEncryption( - hashOfConditionsStr, - dataToEncryptHash - ); - - log('identityParam', identityParam); - - // ========== Get Network Signature ========== + // ========== Get Node Promises ========== + // Handle promises for commands sent to Lit nodes const wrapper = async ( - id: string + requestId: string ): Promise | RejectedNodePromises> => { - const nodePromises = this._getNodePromises((url: string) => { - // -- if session key is available, use it - const authSigToSend = sessionSigs ? sessionSigs[url] : params.authSig; - - if (!authSigToSend) { - return throwError({ - message: `authSig is required`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } + const nodePromises = this._getNodePromises(async (url: string) => { + // -- choose the right signature + const sessionSig = this._getSessionSigByUrl({ + sessionSigs: formattedParams.sessionSigs, + url, + }); - const reqBody: EncryptionSignRequest = { - accessControlConditions: formattedAccessControlConditions, - evmContractConditions: formattedEVMContractConditions, - solRpcConditions: formattedSolRpcConditions, - unifiedAccessControlConditions: - formattedUnifiedAccessControlConditions, - dataToEncryptHash, - chain, - authSig: authSigToSend, - epoch: this.currentEpochNumber!, + const reqBody: JsonExecutionRequest = { + ...formattedParams, + authSig: sessionSig, }; - const urlWithParh = composeLitUrl({ + const urlWithPath = composeLitUrl({ url, - endpoint: LIT_ENDPOINT.ENCRYPTION_SIGN, + endpoint: LIT_ENDPOINT.EXECUTE_JS, }); - return this.#generatePromise(urlWithParh, reqBody, id); + return this.#generatePromise(urlWithPath, reqBody, requestId); }); // -- resolve promises const res = await this._handleNodePromises( nodePromises, - id, - this.config.minNodeCount + requestId, + this.connectedNodes.size ); + return res; - }; + }; // wrapper end + // ========== Execute with Retry ========== const res = await executeWithRetry< RejectedNodePromises | SuccessNodePromises >( wrapper, - (_error: string, _requestId: string, _isFinal: boolean) => { - logError('an error occured attempting to retry'); + (error: any, requestId: string, isFinal: boolean) => { + logError('an error occured, attempting to retry operation'); }, this.config.retryTolerance ); + // ========== Handle Response ========== const requestId = res.requestId; // -- case: promises rejected - if (res.success === false) { + if (!res.success) { this._throwNodeError(res as RejectedNodePromises, requestId); } - const signatureShares: NodeBlsSigningShare[] = ( - res as SuccessNodePromises - ).values; + // -- case: promises success (TODO: check the keys of "values") + const responseData = (res as SuccessNodePromises).values; - logWithRequestId(requestId, 'signatureShares', signatureShares); + logWithRequestId( + requestId, + 'executeJs responseData from node : ', + JSON.stringify(responseData, null, 2) + ); - // ========== Result ========== - const decryptedData = this.#decryptWithSignatureShares( - this.subnetPubKey, - uint8arrayFromString(identityParam, 'utf8'), - ciphertext, - signatureShares + // -- find the responseData that has the most common response + const mostCommonResponse = findMostCommonResponse( + responseData + ) as NodeShare; + + const responseFromStrategy: any = processLitActionResponseStrategy( + responseData, + params.responseStrategy ?? { strategy: 'leastCommon' } ); + mostCommonResponse.response = responseFromStrategy; - return { decryptedData }; - }; + const isSuccess = mostCommonResponse.success; + const hasSignedData = Object.keys(mostCommonResponse.signedData).length > 0; + const hasClaimData = Object.keys(mostCommonResponse.claimData).length > 0; - getLitResourceForEncryption = async ( - params: EncryptRequest - ): Promise => { - // ========== Hashing Access Control Conditions ========= - // hash the access control conditions - const hashOfConditions: ArrayBuffer | undefined = - await this.getHashedAccessControlConditions(params); + // -- we must also check for claim responses as a user may have submitted for a claim and signatures must be aggregated before returning + if (isSuccess && !hasSignedData && !hasClaimData) { + return mostCommonResponse as unknown as ExecuteJsResponse; + } - if (!hashOfConditions) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); + // -- in the case where we are not signing anything on Lit action and using it as purely serverless function + if (!hasSignedData && !hasClaimData) { + return { + claims: {}, + signatures: null, + decryptions: [], + response: mostCommonResponse.response, + logs: mostCommonResponse.logs, + } as ExecuteJsNoSigningResponse; } - const hashOfConditionsStr = uint8arrayToString( - new Uint8Array(hashOfConditions), - 'base16' - ); + // ========== Extract shares from response data ========== - // ========== Hashing Private Data ========== - // hash the private data - const hashOfPrivateData = await crypto.subtle.digest( - 'SHA-256', - params.dataToEncrypt - ); - const hashOfPrivateDataStr = uint8arrayToString( - new Uint8Array(hashOfPrivateData), - 'base16' + // -- 1. combine signed data as a list, and get the signatures from it + const signedDataList = responseData.map((r) => { + return removeDoubleQuotes(r.signedData); + }); + + logWithRequestId( + requestId, + 'signatures shares to combine: ', + signedDataList ); - return new LitAccessControlConditionResource( - `${hashOfConditionsStr}/${hashOfPrivateDataStr}` + const signatures = getSignatures({ + requestId, + networkPubKeySet: this.networkPubKeySet, + minNodeCount: this.config.minNodeCount, + signedData: signedDataList, + }); + + // -- 2. combine responses as a string, and parse it as JSON if possible + const parsedResponse = parseAsJsonOrString(mostCommonResponse.response); + + // -- 3. combine logs + const mostCommonLogs: string = mostCommonString( + responseData.map((r: NodeLog) => r.logs) ); - }; - /** ============================== SESSION ============================== */ + // -- 4. combine claims + const claimsList = getClaimsList(responseData); + const claims = claimsList.length > 0 ? getClaims(claimsList) : undefined; + + // ========== Result ========== + const returnVal: ExecuteJsResponse = { + claims, + signatures, + // decryptions: [], + response: parsedResponse, + logs: mostCommonLogs, + }; + + log('returnVal:', returnVal); + + return returnVal; + }; /** - * Sign a session public key using a PKP, which generates an authSig. - * @returns {Object} An object containing the resulting signature. + * Use PKP to sign + * + * @param { JsonPkpSignSdkParams } params + * @param params.toSign - The data to sign + * @param params.pubKey - The public key to sign with + * @param params.sessionSigs - The session signatures to use + * @param params.authMethods - (optional) The auth methods to use */ + pkpSign = async (params: JsonPkpSignSdkParams): Promise => { + // -- validate required params + const requiredParamKeys = ['toSign', 'pubKey']; - signSessionKey = async ( - params: SignSessionKeyProp - ): Promise => { - log(`[signSessionKey] params:`, params); - - // ========== Validate Params ========== - // -- validate: If it's NOT ready - if (!this.ready) { - const message = - '[signSessionKey] ]LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; + (requiredParamKeys as (keyof JsonPkpSignSdkParams)[]).forEach((key) => { + if (!params[key]) { + throwError({ + message: `"${key}" cannot be undefined, empty, or null. Please provide a valid value.`, + errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, + errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, + }); + } + }); + // -- validate present of accepted auth methods + if ( + !params.sessionSigs && + (!params.authMethods || params.authMethods.length <= 0) + ) { throwError({ - message, - errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, - errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, + message: `Either sessionSigs or authMethods (length > 0) must be present.`, + errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, + errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, }); } - // -- construct SIWE message that will be signed by node to generate an authSig. - const _expiration = - params.expiration || - new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(); - - // Try to get it from local storage, if not generates one~ - const sessionKey: SessionKeyPair = - params.sessionKey ?? this.getSessionKey(); - const sessionKeyUri = LIT_SESSION_KEY_URI + sessionKey.publicKey; - - log( - `[signSessionKey] sessionKeyUri is not found in params, generating a new one`, - sessionKeyUri - ); - - if (!sessionKeyUri) { - throw new Error( - '[signSessionKey] sessionKeyUri is not defined. Please provide a sessionKeyUri or a sessionKey.' - ); - } - - // Compute the address from the public key if it's provided. Otherwise, the node will compute it. - const pkpEthAddress = (function () { - // prefix '0x' if it's not already prefixed - params.pkpPublicKey = hexPrefixed(params.pkpPublicKey!); - - if (params.pkpPublicKey) return computeAddress(params.pkpPublicKey); - - // This will be populated by the node, using dummy value for now. - return '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; - })(); - - let siwe_statement = 'Lit Protocol PKP session signature'; - if (params.statement) { - siwe_statement += ' ' + params.statement; - log(`[signSessionKey] statement found in params: "${params.statement}"`); - } - - let siweMessage; - - const siweParams = { - domain: params?.domain || globalThis.location?.host || 'litprotocol.com', - walletAddress: pkpEthAddress, - statement: siwe_statement, - uri: sessionKeyUri, - version: '1', - chainId: params.chainId ?? 1, - expiration: _expiration, - nonce: this.latestBlockhash!, - }; - - if (params.resourceAbilityRequests) { - siweMessage = await createSiweMessageWithRecaps({ - ...siweParams, - resources: params.resourceAbilityRequests, - litNodeClient: this, - }); - } else { - siweMessage = await createSiweMessage(siweParams); - } - // ========== Get Node Promises ========== - // -- fetch shares from nodes - const body: JsonSignSessionKeyRequestV1 = { - sessionKey: sessionKeyUri, - authMethods: params.authMethods, - ...(params?.pkpPublicKey && { pkpPublicKey: params.pkpPublicKey }), - siweMessage: siweMessage, - curveType: LIT_CURVE.BLS, - - // -- custom auths - ...(params?.litActionIpfsId && { - litActionIpfsId: params.litActionIpfsId, - }), - ...(params?.litActionCode && { code: params.litActionCode }), - ...(params?.jsParams && { jsParams: params.jsParams }), - ...(this.currentEpochNumber && { epoch: this.currentEpochNumber }), - }; - - log(`[signSessionKey] body:`, body); - + // Handle promises for commands sent to Lit nodes const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { - logWithRequestId(id, 'signSessionKey body', body); const nodePromises = this._getNodePromises((url: string) => { - const reqBody: JsonSignSessionKeyRequestV1 = body; + // -- get the session sig from the url key + const sessionSig = this._getSessionSigByUrl({ + sessionSigs: params.sessionSigs, + url, + }); + + const reqBody: JsonPkpSignRequest = { + toSign: normalizeArray(params.toSign), + pubkey: hexPrefixed(params.pubKey), + authSig: sessionSig, + + // -- optional params + ...(params.authMethods && + params.authMethods.length > 0 && { + authMethods: params.authMethods, + }), + }; + + logWithRequestId(id, 'reqBody:', reqBody); const urlWithPath = composeLitUrl({ url, - endpoint: LIT_ENDPOINT.SIGN_SESSION_KEY, + endpoint: LIT_ENDPOINT.PKP_SIGN, }); return this.#generatePromise(urlWithPath, reqBody, id); }); - // -- resolve promises - let res; - try { - res = await this._handleNodePromises( - nodePromises, - id, - this.connectedNodes.size - ); - log('signSessionKey node promises:', res); - } catch (e) { - throw new Error(`Error when handling node promises: ${e}`); - } + const res = await this._handleNodePromises( + nodePromises, + id, + this.connectedNodes.size // ECDSA requires responses from all nodes, but only shares from minNodeCount. + ); return res; - }; + }; // wrapper end + // ========== Execute with Retry ========== const res = await executeWithRetry< RejectedNodePromises | SuccessNodePromises >( wrapper, - (_error: any, _requestId: string, isFinal: boolean) => { + (error: any, requestId: string, isFinal: boolean) => { if (!isFinal) { - logError('an error occured, attempting to retry '); + logError('errror occured, retrying operation'); } }, this.config.retryTolerance ); + // ========== Handle Response ========== const requestId = res.requestId; - logWithRequestId(requestId, 'handleNodePromises res:', res); // -- case: promises rejected - if (!this.#isSuccessNodePromises(res)) { + if (!res.success) { this._throwNodeError(res as RejectedNodePromises, requestId); - return {} as SignSessionKeyResponse; } - const responseData: BlsResponseData[] = res.values; + // -- case: promises success (TODO: check the keys of "values") + const responseData = (res as SuccessNodePromises).values; + logWithRequestId( requestId, - '[signSessionKey] responseData', + 'responseData', JSON.stringify(responseData, null, 2) ); // ========== Extract shares from response data ========== // -- 1. combine signed data as a list, and get the signatures from it - let curveType = responseData[0]?.curveType; + const signedDataList = parsePkpSignResponse(responseData); - if (!curveType) { - log(`[signSessionKey] curveType not found. Defaulting to ECDSA.`); - curveType = 'ECDSA'; - } + const signatures = getSignatures<{ signature: SigResponse }>({ + requestId, + networkPubKeySet: this.networkPubKeySet, + minNodeCount: this.config.minNodeCount, + signedData: signedDataList, + }); - log(`[signSessionKey] curveType is "${curveType}"`); + logWithRequestId(requestId, `signature combination`, signatures); - let signedDataList = responseData.map((s) => s.dataSigned); + return signatures.signature; // only a single signature is ever present, so we just return it. + }; - if (signedDataList.length <= 0) { - const err = `[signSessionKey] signedDataList is empty.`; - log(err); - throw new Error(err); + /** + * Authenticates an Auth Method for claiming a Programmable Key Pair (PKP). + * A {@link MintCallback} can be defined for custom on chain interactions + * by default the callback will forward to a relay server for minting on chain. + * @param {ClaimKeyRequest} params an Auth Method and {@link MintCallback} + * @returns {Promise} + */ + async claimKeyId( + params: ClaimRequest + ): Promise { + if (!this.ready) { + const message = + 'LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; + throwError({ + message, + errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, + errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, + }); } - logWithRequestId( - requestId, - '[signSessionKey] signedDataList', - signedDataList - ); - - // -- checking if we have enough shares - const validatedSignedDataList = responseData - .map((data: BlsResponseData) => { - // each of this field cannot be empty - let requiredFields = [ - 'signatureShare', - 'curveType', - 'shareIndex', - 'siweMessage', - 'dataSigned', - 'blsRootPubkey', - 'result', - ]; - - // check if all required fields are present - for (const field of requiredFields) { - const key: keyof BlsResponseData = field as keyof BlsResponseData; - - if (!data[key] || data[key] === '') { - log( - `[signSessionKey] Invalid signed data. "${field}" is missing. Not a problem, we only need ${this.config.minNodeCount} nodes to sign the session key.` - ); - return null; - } + if (params.authMethod.authMethodType == AuthMethodType.WebAuthn) { + throwError({ + message: + 'Unsupported auth method type. Webauthn, and Lit Actions are not supported for claiming', + errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, + errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, + }); + } + let requestId; + const wrapper = async ( + id: string + ): Promise | RejectedNodePromises> => { + const nodePromises = this._getNodePromises((url: string) => { + if (!params.authMethod) { + throw new Error('authMethod is required'); } - if (!data.signatureShare.ProofOfPossession) { - const err = `[signSessionKey] Invalid signed data. "ProofOfPossession" is missing.`; - log(err); - throw new Error(err); - } + const reqBody: JsonPKPClaimKeyRequest = { + authMethod: params.authMethod, + }; - return data; - }) - .filter((item) => item !== null); + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.PKP_CLAIM, + }); - logWithRequestId( - requestId, - '[signSessionKey] requested length:', - signedDataList.length - ); - logWithRequestId( - requestId, - '[signSessionKey] validated length:', - validatedSignedDataList.length - ); - logWithRequestId( - requestId, - '[signSessionKey] minimum required length:', - this.config.minNodeCount - ); - if (validatedSignedDataList.length < this.config.minNodeCount) { - throw new Error( - `[signSessionKey] not enough nodes signed the session key. Expected ${this.config.minNodeCount}, got ${validatedSignedDataList.length}` + return this.#generatePromise(urlWithPath, reqBody, id); + }); + + const responseData = await this._handleNodePromises( + nodePromises, + id, + this.connectedNodes.size ); - } - const blsSignedData: BlsResponseData[] = - validatedSignedDataList as BlsResponseData[]; + return responseData; + }; - const sigType = mostCommonString(blsSignedData.map((s) => s.curveType)); - log(`[signSessionKey] sigType:`, sigType); - - const signatureShares = getBlsSignatures(blsSignedData); - - log(`[signSessionKey] signatureShares:`, signatureShares); - - const blsCombinedSignature = blsSdk.combine_signature_shares( - signatureShares.map((s) => JSON.stringify(s)) + const responseData = await executeWithRetry< + RejectedNodePromises | SuccessNodePromises + >( + wrapper, + (_error: any, _requestId: string, isFinal: boolean) => { + if (!isFinal) { + logError('an error occured, attempting to retry'); + } + }, + this.config.retryTolerance ); + requestId = responseData.requestId; - log(`[signSessionKey] blsCombinedSignature:`, blsCombinedSignature); - - const publicKey = removeHexPrefix(params.pkpPublicKey); - log(`[signSessionKey] publicKey:`, publicKey); - - const dataSigned = mostCommonString( - blsSignedData.map((s: any) => s.dataSigned) - ); - log(`[signSessionKey] dataSigned:`, dataSigned); + if (responseData.success === true) { + const nodeSignatures: Signature[] = ( + responseData as SuccessNodePromises + ).values.map((r: any) => { + const sig = ethers.utils.splitSignature(`0x${r.signature}`); + return { + r: sig.r, + s: sig.s, + v: sig.v, + }; + }); - const mostCommonSiweMessage = mostCommonString( - blsSignedData.map((s: any) => s.siweMessage) - ); + logWithRequestId( + requestId, + `responseData: ${JSON.stringify(responseData, null, 2)}` + ); - log(`[signSessionKey] mostCommonSiweMessage:`, mostCommonSiweMessage); + const derivedKeyId = (responseData as SuccessNodePromises).values[0] + .derivedKeyId; - const signedMessage = normalizeAndStringify(mostCommonSiweMessage); + const pubkey: string = this.computeHDPubKey(derivedKeyId); + logWithRequestId( + requestId, + `pubkey ${pubkey} derived from key id ${derivedKeyId}` + ); - log(`[signSessionKey] signedMessage:`, signedMessage); + const relayParams: ClaimRequest<'relay'> = + params as ClaimRequest<'relay'>; - const signSessionKeyRes: SignSessionKeyResponse = { - authSig: { - sig: JSON.stringify({ - ProofOfPossession: blsCombinedSignature, - }), - algo: 'LIT_BLS', - derivedVia: 'lit.bls', - signedMessage, - address: computeAddress(hexPrefixed(publicKey)), - }, - pkpPublicKey: publicKey, - }; + let mintTx = ''; + if (params.mintCallback && 'signer' in params) { + mintTx = await params.mintCallback( + { + derivedKeyId, + authMethodType: params.authMethod.authMethodType, + signatures: nodeSignatures, + pubkey, + signer: (params as ClaimRequest<'client'>).signer, + ...relayParams, + }, + this.config.litNetwork as LitNetwork + ); + } else { + mintTx = await defaultMintClaimCallback( + { + derivedKeyId, + authMethodType: params.authMethod.authMethodType, + signatures: nodeSignatures, + pubkey, + ...relayParams, + }, + this.config.litNetwork as LitNetwork + ); + } - return signSessionKeyRes; - }; + return { + signatures: nodeSignatures, + claimedKeyId: derivedKeyId, + pubkey, + mintTx, + }; + } else { + return throwError({ + message: `Claim request has failed. Request trace id: lit_${requestId} `, + errorKind: LIT_ERROR.UNKNOWN_ERROR.kind, + errorCode: LIT_ERROR.UNKNOWN_ERROR.code, + }); + } + } /** - * Get session signatures for a set of resources * - * High level, how this works: - * 1. Generate or retrieve session key - * 2. Generate or retrieve the wallet signature of the session key - * 3. Sign the specific resources with the session key + * Request a signed JWT from the LIT network. Before calling this function, you must know the access control conditions for the item you wish to gain authorization for. * - * Note: When generating session signatures for different PKPs or auth methods, - * be sure to call disconnectWeb3 to clear auth signatures stored in local storage + * @param { GetSignedTokenRequest } params + * + * @returns { Promise } final JWT * - * @param { GetSessionSigsProps } params - * - * @example - * - * ```ts - * import { LitPKPResource, LitActionResource } from "@lit-protocol/auth-helpers"; -import { LitAbility } from "@lit-protocol/types"; -import { logWithRequestId } from '../../../misc/src/lib/misc'; - -const resourceAbilityRequests = [ - { - resource: new LitPKPResource("*"), - ability: LitAbility.PKPSigning, - }, - { - resource: new LitActionResource("*"), - ability: LitAbility.LitActionExecution, - }, - ]; - * ``` */ - getSessionSigs = async ( - params: GetSessionSigsProps - ): Promise => { - // -- prepare - // Try to get it from local storage, if not generates one~ - const sessionKey = params.sessionKey ?? this.getSessionKey(); - - const sessionKeyUri = this.#getSessionKeyUri(sessionKey.publicKey); - - // First get or generate the session capability object for the specified resources. - const sessionCapabilityObject = params.sessionCapabilityObject - ? params.sessionCapabilityObject - : await this.generateSessionCapabilityObjectWithWildcards( - params.resourceAbilityRequests.map((r) => r.resource) - ); - const expiration = params.expiration || LitNodeClientNodeJs.getExpiration(); + getSignedToken = async (params: GetSignedTokenRequest): Promise => { + // ========== Prepare Params ========== + const { chain, authSig, sessionSigs } = params; - if (!this.latestBlockhash) { + // ========== Validation ========== + // -- validate if it's ready + if (!this.ready) { + const message = + '3 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; throwError({ - message: 'Eth Blockhash is undefined.', - errorKind: LIT_ERROR.INVALID_ETH_BLOCKHASH.kind, - errorCode: LIT_ERROR.INVALID_ETH_BLOCKHASH.name, + message, + errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, + errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, }); } - const nonce = this.latestBlockhash!; - - // -- (TRY) to get the wallet signature - let authSig = await this.#getWalletSig({ - authNeededCallback: params.authNeededCallback, - chain: params.chain || 'ethereum', - sessionCapabilityObject, - switchChain: params.switchChain, - expiration: expiration, - sessionKey: sessionKey, - sessionKeyUri: sessionKeyUri, - nonce, - // -- for recap - resourceAbilityRequests: params.resourceAbilityRequests, - - // -- optional fields - ...(params.litActionCode && { litActionCode: params.litActionCode }), - ...(params.litActionIpfsId && { - litActionIpfsId: params.litActionIpfsId, - }), - ...(params.jsParams && { jsParams: params.jsParams }), - }); + // -- validate if this.networkPubKeySet is null + if (this.networkPubKeySet === null) { + return throwError({ + message: 'networkPubKeySet cannot be null', + errorKind: LIT_ERROR.PARAM_NULL_ERROR.kind, + errorCode: LIT_ERROR.PARAM_NULL_ERROR.name, + }); + } - const needToResignSessionKey = await this.#checkNeedToResignSessionKey({ - authSig, - sessionKeyUri, - resourceAbilityRequests: params.resourceAbilityRequests, + const paramsIsSafe = safeParams({ + functionName: 'getSignedToken', + params, }); - // -- (CHECK) if we need to resign the session key - if (needToResignSessionKey) { - log('need to re-sign session key. Signing...'); - authSig = await this.#authCallbackAndUpdateStorageItem({ - authCallback: params.authNeededCallback, - authCallbackParams: { - chain: params.chain || 'ethereum', - statement: sessionCapabilityObject.statement, - resources: [sessionCapabilityObject.encodeAsSiweResource()], - switchChain: params.switchChain, - expiration, - sessionKey: sessionKey, - uri: sessionKeyUri, - nonce, - resourceAbilityRequests: params.resourceAbilityRequests, - - // -- optional fields - ...(params.litActionCode && { litActionCode: params.litActionCode }), - ...(params.litActionIpfsId && { - litActionIpfsId: params.litActionIpfsId, - }), - ...(params.jsParams && { jsParams: params.jsParams }), - }, + if (!paramsIsSafe) { + return throwError({ + message: `Parameter validation failed.`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, }); } - if ( - authSig.address === '' || - authSig.derivedVia === '' || - authSig.sig === '' || - authSig.signedMessage === '' - ) { - throwError({ - message: 'No wallet signature found', - errorKind: LIT_ERROR.WALLET_SIGNATURE_NOT_FOUND_ERROR.kind, - errorCode: LIT_ERROR.WALLET_SIGNATURE_NOT_FOUND_ERROR.name, - }); - // @ts-ignore - we throw an error above, so below should never be reached - return; - } + // ========== Prepare ========== + // we need to send jwt params iat (issued at) and exp (expiration) + // because the nodes may have different wall clock times + // the nodes will verify that these params are withing a grace period + const { iat, exp } = this.#getJWTParams(); - // ===== AFTER we have Valid Signed Session Key ===== - // - Let's sign the resources with the session key - // - 5 minutes is the default expiration for a session signature - // - Because we can generate a new session sig every time the user wants to access a resource without prompting them to sign with their wallet - const sessionExpiration = - expiration ?? new Date(Date.now() + 1000 * 60 * 5).toISOString(); + // ========== Formatting Access Control Conditions ========= + const { + error, + formattedAccessControlConditions, + formattedEVMContractConditions, + formattedSolRpcConditions, + formattedUnifiedAccessControlConditions, + }: FormattedMultipleAccs = this.getFormattedAccessControlConditions(params); - const capabilities = params.capacityDelegationAuthSig - ? [ - ...(params.capabilityAuthSigs ?? []), - params.capacityDelegationAuthSig, - authSig, - ] - : [...(params.capabilityAuthSigs ?? []), authSig]; + if (error) { + return throwError({ + message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); + } - const signingTemplate = { - sessionKey: sessionKey.publicKey, - resourceAbilityRequests: params.resourceAbilityRequests, - capabilities, - issuedAt: new Date().toISOString(), - expiration: sessionExpiration, - }; + // ========== Get Node Promises ========== + const wrapper = async ( + id: string + ): Promise | RejectedNodePromises> => { + const nodePromises = this._getNodePromises((url: string) => { + // -- if session key is available, use it + const authSigToSend = sessionSigs ? sessionSigs[url] : authSig; - const signatures: SessionSigsMap = {}; + const reqBody: SigningAccessControlConditionRequest = { + accessControlConditions: formattedAccessControlConditions, + evmContractConditions: formattedEVMContractConditions, + solRpcConditions: formattedSolRpcConditions, + unifiedAccessControlConditions: + formattedUnifiedAccessControlConditions, + chain, + authSig: authSigToSend, + iat, + exp, + }; - this.connectedNodes.forEach((nodeAddress: string) => { - const toSign: SessionSigningTemplate = { - ...signingTemplate, - nodeAddress, - }; + const urlWithPath = composeLitUrl({ + url, + endpoint: LIT_ENDPOINT.SIGN_ACCS, + }); - const signedMessage = JSON.stringify(toSign); + return this.#generatePromise(urlWithPath, reqBody, id); + }); - const uint8arrayKey = uint8arrayFromString( - sessionKey.secretKey, - 'base16' + // -- resolve promises + const res = await this._handleNodePromises( + nodePromises, + id, + this.config.minNodeCount ); + return res; + }; - const uint8arrayMessage = uint8arrayFromString(signedMessage, 'utf8'); - const signature = nacl.sign.detached(uint8arrayMessage, uint8arrayKey); - - signatures[nodeAddress] = { - sig: uint8arrayToString(signature, 'base16'), - derivedVia: 'litSessionSignViaNacl', - signedMessage: signedMessage, - address: sessionKey.publicKey, - algo: 'ed25519', - }; - }); - - log('signatures:', signatures); - - return signatures; - }; - - /** - * Retrieves the PKP sessionSigs. - * - * @param params - The parameters for retrieving the PKP sessionSigs. - * @returns A promise that resolves to the PKP sessionSigs. - * @throws An error if any of the required parameters are missing or if `litActionCode` and `ipfsId` exist at the same time. - */ - getPkpSessionSigs = async (params: GetPkpSessionSigs) => { - const chain = params?.chain || 'ethereum'; - - const pkpSessionSigs = this.getSessionSigs({ - chain, - ...params, - authNeededCallback: async (props: AuthCallbackParams) => { - // -- validate - if (!props.expiration) { - throw new Error( - '[getPkpSessionSigs/callback] expiration is required' - ); - } - - if (!props.resources) { - throw new Error('[getPkpSessionSigs/callback]resources is required'); - } - - if (!props.resourceAbilityRequests) { - throw new Error( - '[getPkpSessionSigs/callback]resourceAbilityRequests is required' - ); - } - - // lit action code and ipfs id cannot exist at the same time - if (props.litActionCode && props.litActionIpfsId) { - throw new Error( - '[getPkpSessionSigs/callback]litActionCode and litActionIpfsId cannot exist at the same time' - ); + const res = await executeWithRetry< + RejectedNodePromises | SuccessNodePromises + >( + wrapper, + (error: any, requestId: string, isFinal: boolean) => { + if (!isFinal) { + logError('an error occured, attempting to retry '); } + }, + this.config.retryTolerance + ); + const requestId = res.requestId; - /** - * We must provide an empty array for authMethods even if we are not using any auth methods. - * So that the nodes can serialize the request correctly. - */ - const authMethods = params.authMethods || []; - - const response = await this.signSessionKey({ - sessionKey: props.sessionKey, - statement: props.statement || 'Some custom statement.', - authMethods: [...authMethods], - pkpPublicKey: params.pkpPublicKey, - expiration: props.expiration, - resources: props.resources, - chainId: 1, + // -- case: promises rejected + if (res.success === false) { + this._throwNodeError(res as RejectedNodePromises, requestId); + } - // -- required fields - resourceAbilityRequests: props.resourceAbilityRequests, + const signatureShares: NodeBlsSigningShare[] = ( + res as SuccessNodePromises + ).values; - // -- optional fields - ...(props.litActionCode && { litActionCode: props.litActionCode }), - ...(props.litActionIpfsId && { - litActionIpfsId: props.litActionIpfsId, - }), - ...(props.jsParams && { jsParams: props.jsParams }), - }); + log('signatureShares', signatureShares); - return response.authSig; - }, - }); + // ========== Result ========== + const finalJwt: string = this.#combineSharesAndGetJWT( + signatureShares, + requestId + ); - return pkpSessionSigs; + return finalJwt; }; /** - * Retrieves session signatures specifically for Lit Actions. - * Unlike `getPkpSessionSigs`, this function requires either `litActionCode` or `litActionIpfsId`, and `jsParams` must be provided. * - * @param params - The parameters required for retrieving the session signatures. - * @returns A promise that resolves with the session signatures. + * Decrypt ciphertext with the LIT network. + * */ - getLitActionSessionSigs = async (params: GetLitActionSessionSigs) => { - // Check if either litActionCode or litActionIpfsId is provided - if (!params.litActionCode && !params.litActionIpfsId) { - throw new Error( - "Either 'litActionCode' or 'litActionIpfsId' must be provided." - ); - } - - // Check if jsParams is provided - if (!params.jsParams) { - throw new Error("'jsParams' is required."); - } - - return this.getPkpSessionSigs(params); - }; + decrypt = async (params: DecryptRequest): Promise => { + const { sessionSigs, chain, ciphertext, dataToEncryptHash } = params; - /** - * Authenticates an Auth Method for claiming a Programmable Key Pair (PKP). - * A {@link MintCallback} can be defined for custom on chain interactions - * by default the callback will forward to a relay server for minting on chain. - * @param {ClaimKeyRequest} params an Auth Method and {@link MintCallback} - * @returns {Promise} - */ - async claimKeyId( - params: ClaimRequest - ): Promise { + // ========== Validate Params ========== + // -- validate if it's ready if (!this.ready) { const message = - 'LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; + '6 LitNodeClient is not ready. Please call await litNodeClient.connect() first.'; throwError({ message, errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, @@ -2193,124 +2167,148 @@ const resourceAbilityRequests = [ }); } - if (params.authMethod.authMethodType == AuthMethodType.WebAuthn) { - throwError({ - message: - 'Unsupported auth method type. Webauthn, and Lit Actions are not supported for claiming', + // -- validate if this.subnetPubKey is null + if (!this.subnetPubKey) { + const message = 'subnetPubKey cannot be null'; + return throwError({ + message, errorKind: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.kind, errorCode: LIT_ERROR.LIT_NODE_CLIENT_NOT_READY_ERROR.name, }); } - let requestId; + + const paramsIsSafe = safeParams({ + functionName: 'decrypt', + params, + }); + + if (!paramsIsSafe) { + return throwError({ + message: `Parameter validation failed.`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); + } + + // ========== Hashing Access Control Conditions ========= + // hash the access control conditions + const hashOfConditions: ArrayBuffer | undefined = + await this.getHashedAccessControlConditions(params); + + if (!hashOfConditions) { + return throwError({ + message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); + } + + const hashOfConditionsStr = uint8arrayToString( + new Uint8Array(hashOfConditions), + 'base16' + ); + + // ========== Formatting Access Control Conditions ========= + const { + error, + formattedAccessControlConditions, + formattedEVMContractConditions, + formattedSolRpcConditions, + formattedUnifiedAccessControlConditions, + }: FormattedMultipleAccs = this.getFormattedAccessControlConditions(params); + + if (error) { + throwError({ + message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); + } + + // ========== Assemble identity parameter ========== + const identityParam = this.#getIdentityParamForEncryption( + hashOfConditionsStr, + dataToEncryptHash + ); + + log('identityParam', identityParam); + + // ========== Get Network Signature ========== const wrapper = async ( id: string ): Promise | RejectedNodePromises> => { const nodePromises = this._getNodePromises((url: string) => { - if (!params.authMethod) { - throw new Error('authMethod is required'); + // -- if session key is available, use it + const authSigToSend = sessionSigs ? sessionSigs[url] : params.authSig; + + if (!authSigToSend) { + return throwError({ + message: `authSig is required`, + errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, + errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, + }); } - const reqBody: JsonPKPClaimKeyRequest = { - authMethod: params.authMethod, + const reqBody: EncryptionSignRequest = { + accessControlConditions: formattedAccessControlConditions, + evmContractConditions: formattedEVMContractConditions, + solRpcConditions: formattedSolRpcConditions, + unifiedAccessControlConditions: + formattedUnifiedAccessControlConditions, + dataToEncryptHash, + chain, + authSig: authSigToSend, + epoch: this.currentEpochNumber!, }; - const urlWithPath = composeLitUrl({ + const urlWithParh = composeLitUrl({ url, - endpoint: LIT_ENDPOINT.PKP_CLAIM, + endpoint: LIT_ENDPOINT.ENCRYPTION_SIGN, }); - return this.#generatePromise(urlWithPath, reqBody, id); + return this.#generatePromise(urlWithParh, reqBody, id); }); - const responseData = await this._handleNodePromises( + // -- resolve promises + const res = await this._handleNodePromises( nodePromises, id, - this.connectedNodes.size + this.config.minNodeCount ); - - return responseData; + return res; }; - const responseData = await executeWithRetry< + const res = await executeWithRetry< RejectedNodePromises | SuccessNodePromises >( wrapper, - (_error: any, _requestId: string, isFinal: boolean) => { - if (!isFinal) { - logError('an error occured, attempting to retry'); - } + (_error: string, _requestId: string, _isFinal: boolean) => { + logError('an error occured attempting to retry'); }, this.config.retryTolerance ); - requestId = responseData.requestId; - - if (responseData.success === true) { - const nodeSignatures: Signature[] = ( - responseData as SuccessNodePromises - ).values.map((r: any) => { - const sig = ethers.utils.splitSignature(`0x${r.signature}`); - return { - r: sig.r, - s: sig.s, - v: sig.v, - }; - }); - logWithRequestId( - requestId, - `responseData: ${JSON.stringify(responseData, null, 2)}` - ); + const requestId = res.requestId; - const derivedKeyId = (responseData as SuccessNodePromises).values[0] - .derivedKeyId; + // -- case: promises rejected + if (res.success === false) { + this._throwNodeError(res as RejectedNodePromises, requestId); + } - const pubkey: string = this.computeHDPubKey(derivedKeyId); - logWithRequestId( - requestId, - `pubkey ${pubkey} derived from key id ${derivedKeyId}` - ); + const signatureShares: NodeBlsSigningShare[] = ( + res as SuccessNodePromises + ).values; - const relayParams: ClaimRequest<'relay'> = - params as ClaimRequest<'relay'>; + logWithRequestId(requestId, 'signatureShares', signatureShares); - let mintTx = ''; - if (params.mintCallback && 'signer' in params) { - mintTx = await params.mintCallback( - { - derivedKeyId, - authMethodType: params.authMethod.authMethodType, - signatures: nodeSignatures, - pubkey, - signer: (params as ClaimRequest<'client'>).signer, - ...relayParams, - }, - this.config.litNetwork as LitNetwork - ); - } else { - mintTx = await defaultMintClaimCallback( - { - derivedKeyId, - authMethodType: params.authMethod.authMethodType, - signatures: nodeSignatures, - pubkey, - ...relayParams, - }, - this.config.litNetwork as LitNetwork - ); - } + // ========== Result ========== + const decryptedData = this.#decryptWithSignatureShares( + this.subnetPubKey, + uint8arrayFromString(identityParam, 'utf8'), + ciphertext, + signatureShares + ); - return { - signatures: nodeSignatures, - claimedKeyId: derivedKeyId, - pubkey, - mintTx, - }; - } else { - return throwError({ - message: `Claim request has failed. Request trace id: lit_${requestId} `, - errorKind: LIT_ERROR.UNKNOWN_ERROR.kind, - errorCode: LIT_ERROR.UNKNOWN_ERROR.code, - }); - } - } + return { decryptedData }; + }; } From 628fb8cb29cc1f65ce931ac2e56fc0516cc15509 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 18:57:04 +0100 Subject: [PATCH 238/263] refactor: remove `getLitResourceForEncryption` as it's unused --- .../src/lib/lit-node-client-nodejs.ts | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index c51cce25e5..f418ff4e20 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -951,43 +951,6 @@ export class LitNodeClientNodeJs return { ciphertext, dataToEncryptHash: hashOfPrivateDataStr }; }; - getLitResourceForEncryption = async ( - params: EncryptRequest - ): Promise => { - // ========== Hashing Access Control Conditions ========= - // hash the access control conditions - const hashOfConditions: ArrayBuffer | undefined = - await this.getHashedAccessControlConditions(params); - - if (!hashOfConditions) { - return throwError({ - message: `You must provide either accessControlConditions or evmContractConditions or solRpcConditions or unifiedAccessControlConditions`, - errorKind: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.kind, - errorCode: LIT_ERROR.INVALID_ARGUMENT_EXCEPTION.name, - }); - } - - const hashOfConditionsStr = uint8arrayToString( - new Uint8Array(hashOfConditions), - 'base16' - ); - - // ========== Hashing Private Data ========== - // hash the private data - const hashOfPrivateData = await crypto.subtle.digest( - 'SHA-256', - params.dataToEncrypt - ); - const hashOfPrivateDataStr = uint8arrayToString( - new Uint8Array(hashOfPrivateData), - 'base16' - ); - - return new LitAccessControlConditionResource( - `${hashOfConditionsStr}/${hashOfPrivateDataStr}` - ); - }; - /** ============================== SESSION ============================== */ /** * Get session signatures for a set of resources From 5d80a722c0b3395c80a4908879997f313f25f684 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 19:03:42 +0100 Subject: [PATCH 239/263] chore: improve jsDoc --- .../src/lib/lit-node-client-nodejs.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index f418ff4e20..4224f3b94b 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -316,7 +316,6 @@ export class LitNodeClientNodeJs `${hashOfConditionsStr}/${hashOfPrivateDataStr}` ).getResourceKey(); }; - /** * * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period @@ -451,7 +450,6 @@ export class LitNodeClientNodeJs log('getWalletSig - flow 3'); return walletSig!; }; - /** * * Combine Shares from network public key set and signature shares @@ -677,9 +675,7 @@ export class LitNodeClientNodeJs } /** - * * Get expiration for session default time is 1 day / 24 hours - * */ static getExpiration = () => { return new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(); @@ -1231,6 +1227,7 @@ const resourceAbilityRequests = [ /** ============================== END POINTS ============================== */ /** * Sign a session public key using a PKP, which generates an authSig. + * Endpoint: /web/sign_session_key endpoint. * @returns {Object} An object containing the resulting signature. */ signSessionKey = async ( @@ -1525,7 +1522,7 @@ const resourceAbilityRequests = [ /** * * Execute JS on the nodes and combine and return any resulting signatures - * + * Endpoint: /web/execute * @param { JsonExecutionSdkParams } params * * @returns { ExecuteJsResponse } @@ -1709,6 +1706,8 @@ const resourceAbilityRequests = [ /** * Use PKP to sign * + * Endpoint: /web/pkp/sign + * * @param { JsonPkpSignSdkParams } params * @param params.toSign - The data to sign * @param params.pubKey - The public key to sign with @@ -1833,6 +1832,9 @@ const resourceAbilityRequests = [ * Authenticates an Auth Method for claiming a Programmable Key Pair (PKP). * A {@link MintCallback} can be defined for custom on chain interactions * by default the callback will forward to a relay server for minting on chain. + * + * Endpoint: /web/pkp/claim + * * @param {ClaimKeyRequest} params an Auth Method and {@link MintCallback} * @returns {Promise} */ @@ -1974,6 +1976,8 @@ const resourceAbilityRequests = [ * * Request a signed JWT from the LIT network. Before calling this function, you must know the access control conditions for the item you wish to gain authorization for. * + * Endpoint: /web/signing/access_control_condition + * * @param { GetSignedTokenRequest } params * * @returns { Promise } final JWT @@ -2114,6 +2118,8 @@ const resourceAbilityRequests = [ * * Decrypt ciphertext with the LIT network. * + * Endpoint: /web/encryption/sign + * */ decrypt = async (params: DecryptRequest): Promise => { const { sessionSigs, chain, ciphertext, dataToEncryptHash } = params; From 3d2a66b10011af09d0456fd8cd8a137695ded03e Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 19:08:09 +0100 Subject: [PATCH 240/263] chore: move `getExpiration` as helper --- .../src/lib/helpers/get-expiration.test.ts | 17 +++++++++++++++++ .../src/lib/helpers/get-expiration.ts | 9 +++++++++ .../src/lib/lit-node-client-nodejs.ts | 5 +++-- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.test.ts create mode 100644 packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.ts diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.test.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.test.ts new file mode 100644 index 0000000000..a345e1586e --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.test.ts @@ -0,0 +1,17 @@ +import { getExpiration } from './get-expiration'; + +describe('getExpiration', () => { + it('should return the expiration date and time as an ISO string', () => { + // Arrange + const currentDate = new Date(); + const expectedExpiration = new Date( + currentDate.getTime() + 1000 * 60 * 60 * 24 + ).toISOString(); + + // Act + const result = getExpiration(); + + // Assert + expect(result).toBe(expectedExpiration); + }); +}); diff --git a/packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.ts b/packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.ts new file mode 100644 index 0000000000..73eef94d9d --- /dev/null +++ b/packages/lit-node-client-nodejs/src/lib/helpers/get-expiration.ts @@ -0,0 +1,9 @@ +/** + * Returns the expiration date and time as an ISO string. + * The expiration is set to 24 hours from the current date and time. + * + * @returns {string} The expiration date and time as an ISO string. + */ +export const getExpiration = () => { + return new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(); +}; diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 4224f3b94b..984e87c8a4 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -124,6 +124,7 @@ import { normalizeArray } from './helpers/normalize-array'; import { parsePkpSignResponse } from './helpers/parse-pkp-sign-response'; import { getBlsSignatures } from './helpers/get-bls-signatures'; import { processLitActionResponseStrategy } from './helpers/process-lit-action-response-strategy'; +import { getExpiration } from './helpers/get-expiration'; export class LitNodeClientNodeJs extends LitCore @@ -678,12 +679,12 @@ export class LitNodeClientNodeJs * Get expiration for session default time is 1 day / 24 hours */ static getExpiration = () => { - return new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(); + return getExpiration(); }; // backward compatibility getExpiration = () => { - return LitNodeClientNodeJs.getExpiration(); + return getExpiration(); }; // ========== Promise Handlers ========== From 5e5cfd36d7b8a6d68d9ac9e252a284670472b1a0 Mon Sep 17 00:00:00 2001 From: Anson Date: Wed, 29 May 2024 19:09:43 +0100 Subject: [PATCH 241/263] doc: improve `getJWTParams` jsDoc --- .../src/lib/lit-node-client-nodejs.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 984e87c8a4..31a86b96d5 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -318,11 +318,15 @@ export class LitNodeClientNodeJs ).getResourceKey(); }; /** + * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have + * different wall clock times, the nodes will verify that these params are withing a grace period * - * we need to send jwt params iat (issued at) and exp (expiration) because the nodes may have different wall clock times, the nodes will verify that these params are withing a grace period - * + * @returns { { iat: number, exp: number } } the jwt params */ - #getJWTParams = () => { + #getJWTParams = (): { + iat: number; + exp: number; + } => { const now = Date.now(); const iat = Math.floor(now / 1000); const exp = iat + 12 * 60 * 60; // 12 hours in seconds From 647e48944ee7eb195cd8d5d24f77d3b152f5921e Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 14:25:19 -0400 Subject: [PATCH 242/263] ref(contracts-sdk): remove sequencer rpc for replica rpc url --- local-tests/setup/tinny-environment.ts | 1 - packages/contracts-sdk/src/lib/contracts-sdk.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 65da822020..648b90f551 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -52,7 +52,6 @@ export class TinnyEnvironment { // (8) "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f" (10000.000000000000000000 ETH) // (9) "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" (10000.000000000000000000 ETH) PRIVATE_KEYS: process.env['PRIVATE_KEYS']?.split(',') || [ - '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index c7315a8797..00cb9d6f7f 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -68,6 +68,7 @@ import { AuthMethodScope, AuthMethodType } from '@lit-protocol/constants'; const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; const DEFAULT_READ_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; + const BLOCK_EXPLORER = 'https://chain.litprotocol.com/'; // This function asynchronously executes a provided callback function for each item in the given array. From 7f13dcbb2aa5f7631d344baf8f24546e8b08cd50 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 14:31:06 -0400 Subject: [PATCH 243/263] ref(tinny): remove default wallet 0 --- local-tests/setup/tinny-environment.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 648b90f551..cf45818671 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -41,7 +41,6 @@ export class TinnyEnvironment { // Available Accounts // ================== - // (0) "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" (10000.000000000000000000 ETH) // (1) "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (10000.000000000000000000 ETH) // (2) "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" (10000.000000000000000000 ETH) // (3) "0x90F79bf6EB2c4f870365E785982E1f101E93b906" (10000.000000000000000000 ETH) From b31834929fe8530f568d168f7a29ab41c3b0a010 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 16:38:19 -0400 Subject: [PATCH 244/263] wip: block hash changes --- packages/core/src/lib/lit-core.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 39dec183b8..3d24e72e51 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -103,7 +103,7 @@ export type LitNodeClientConfigWithDefaults = Required< // On epoch change, we wait this many seconds for the nodes to update to the new epoch before using the new epoch # const EPOCH_PROPAGATION_DELAY = 30_000; // This interval is responsible for keeping latest block hash up to date -const NETWORK_SYNC_INTERVAL = 30_000; +const BLOCKHASH_SYNC_INTERVAL = 30_000; export class LitCore { config: LitNodeClientConfigWithDefaults = { @@ -139,7 +139,7 @@ export class LitCore { currentNumber: null, lastUpdateTime: null, }; - + private _blockHashUrl = "http://0.0.0.0:8080/get_most_recent_valid_block"; // ========== Constructor ========== constructor(config: LitNodeClientConfig | CustomNetwork) { // Initialize default config based on litNetwork @@ -827,32 +827,34 @@ export class LitCore { this._networkSyncInterval = setInterval(async () => { if ( !this.lastBlockHashRetrieved || - Date.now() - this.lastBlockHashRetrieved >= NETWORK_SYNC_INTERVAL + Date.now() - this.lastBlockHashRetrieved >= BLOCKHASH_SYNC_INTERVAL ) { log( - 'Syncing state for new network context current config: ', - this.config, + 'Syncing state for new blockhash ', 'current blockhash: ', this.lastBlockHashRetrieved ); try { - await this.connect(); + const blockHashFetchResp = await fetch(this._blockHashUrl); + const blockHashBody: any = await blockHashFetchResp.json(); + this.latestBlockhash = blockHashBody.blockhash; + this.lastBlockHashRetrieved = Date.now(); log( - 'Done syncing state new config: ', - this.config, + 'Done syncing state new blockhash: ', + this.lastBlockHashRetrieved, 'new blockhash: ', - this.lastBlockHashRetrieved + blockHashBody.blockhash ); } catch (err: unknown) { // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError const { message = '' } = err as Error | NodeClientErrorV1; logError( - 'Error while attempting to refresh nodes to fetch new latestBlockhash:', + 'Error while attempting fetch new latestBlockhash:', message ); } } - }, NETWORK_SYNC_INTERVAL); + }, BLOCKHASH_SYNC_INTERVAL); } /** From de8a2e4426971e473ef21c3751eca884333b36e0 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 17:30:54 -0400 Subject: [PATCH 245/263] ref(contracts-sdk): update contract write calls to use replica --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 00cb9d6f7f..9419001fda 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -66,7 +66,7 @@ import { } from './helpers/getBytes32FromMultihash'; import { AuthMethodScope, AuthMethodType } from '@lit-protocol/constants'; -const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; +const DEFAULT_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; const DEFAULT_READ_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; const BLOCK_EXPLORER = 'https://chain.litprotocol.com/'; @@ -1092,7 +1092,9 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope tokenId = events[0].topics[1]; console.warn('tokenId:', tokenId); - + await new Promise((resolve, _reject) => { + setTimeout(resolve, 10_000); + }); let publicKey = await this.pkpNftContract.read.getPubkey(tokenId); if (publicKey.startsWith('0x')) { @@ -1624,11 +1626,13 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope tokenIdFromEvent = events[0].topics[1]; console.warn('tokenIdFromEvent:', tokenIdFromEvent); - + await new Promise((resolve, _reject) => { + setTimeout(resolve, 5_000); + }); let publicKey = await this.pkpNftContract.read.getPubkey( tokenIdFromEvent ); - + console.warn("public key from token id", publicKey); if (publicKey.startsWith('0x')) { publicKey = publicKey.slice(2); } From 12b7f2a68a2b65c2bd45b034428c1ff8a9756963 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 17:35:59 -0400 Subject: [PATCH 246/263] Revert "Merge pull request #481 from LIT-Protocol/ref/replace-sequencer-with-replica-url" This reverts commit aa0d877e24ff1cd861295b9710ca9e922b4461bf, reversing changes made to ad8ee19747b8d39833d4559373d3ef9fff6a1ec2. --- local-tests/setup/tinny-environment.ts | 2 ++ packages/constants/src/lib/constants/constants.ts | 4 ++-- packages/contracts-sdk/src/lib/addresses.ts | 2 +- packages/contracts-sdk/src/lib/contracts-sdk.spec.ts | 2 +- packages/contracts-sdk/src/lib/contracts-sdk.ts | 4 +--- packages/lit-auth-client/src/lib/lit-auth-client.ts | 3 +-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index cf45818671..65da822020 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -41,6 +41,7 @@ export class TinnyEnvironment { // Available Accounts // ================== + // (0) "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" (10000.000000000000000000 ETH) // (1) "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (10000.000000000000000000 ETH) // (2) "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" (10000.000000000000000000 ETH) // (3) "0x90F79bf6EB2c4f870365E785982E1f101E93b906" (10000.000000000000000000 ETH) @@ -51,6 +52,7 @@ export class TinnyEnvironment { // (8) "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f" (10000.000000000000000000 ETH) // (9) "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" (10000.000000000000000000 ETH) PRIVATE_KEYS: process.env['PRIVATE_KEYS']?.split(',') || [ + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', diff --git a/packages/constants/src/lib/constants/constants.ts b/packages/constants/src/lib/constants/constants.ts index f17747a01c..713e491808 100644 --- a/packages/constants/src/lib/constants/constants.ts +++ b/packages/constants/src/lib/constants/constants.ts @@ -472,7 +472,7 @@ export const LIT_CHAINS: LITChain = { name: 'Chronicle - Lit Protocol Testnet', symbol: 'testLPX', decimals: 18, - rpcUrls: ['https://lit-protocol.calderachain.xyz/replica-http'], + rpcUrls: ['https://chain-rpc.litprotocol.com/http'], blockExplorerUrls: ['https://chain.litprotocol.com/'], type: null, vmType: 'EVM', @@ -483,7 +483,7 @@ export const LIT_CHAINS: LITChain = { name: 'Chronicle - Lit Protocol Testnet', symbol: 'testLPX', decimals: 18, - rpcUrls: ['https://lit-protocol.calderachain.xyz/replica-http'], + rpcUrls: ['https://chain-rpc.litprotocol.com/http'], blockExplorerUrls: ['https://chain.litprotocol.com/'], type: null, vmType: 'EVM', diff --git a/packages/contracts-sdk/src/lib/addresses.ts b/packages/contracts-sdk/src/lib/addresses.ts index 35dd73ff98..efd106ee7b 100644 --- a/packages/contracts-sdk/src/lib/addresses.ts +++ b/packages/contracts-sdk/src/lib/addresses.ts @@ -47,7 +47,7 @@ export const derivedAddresses = async ({ // if default RPC url is not provided, use the default one https://endpoints.omniatech.io/v1/matic/mumbai/public if (!defaultRPCUrl) { - defaultRPCUrl = 'https://lit-protocol.calderachain.xyz/replica-http'; + defaultRPCUrl = 'https://chain-rpc.litprotocol.com/http'; } // if pkpTokenId is provided, get the public key from it diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts b/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts index bfa8040bdd..4e17643a5b 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.spec.ts @@ -29,7 +29,7 @@ describe('contractsSdk', () => { }); it('Test that connection from custom context resolves contracts in correct mapping', async () => { - const DEFAULT_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; + const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; const provider = new ethers.providers.JsonRpcProvider(DEFAULT_RPC); litContracts = new LitContracts({ customContext: { diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 00cb9d6f7f..dcacf0560e 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -67,8 +67,6 @@ import { import { AuthMethodScope, AuthMethodType } from '@lit-protocol/constants'; const DEFAULT_RPC = 'https://chain-rpc.litprotocol.com/http'; -const DEFAULT_READ_RPC = 'https://lit-protocol.calderachain.xyz/replica-http'; - const BLOCK_EXPLORER = 'https://chain.litprotocol.com/'; // This function asynchronously executes a provided callback function for each item in the given array. @@ -577,7 +575,7 @@ export class LitContracts { rpcUrl?: string ) { let provider: ethers.providers.JsonRpcProvider; - rpcUrl = rpcUrl ?? DEFAULT_READ_RPC; + rpcUrl = rpcUrl ?? DEFAULT_RPC; if (context && 'provider' in context!) { provider = context.provider; } else { diff --git a/packages/lit-auth-client/src/lib/lit-auth-client.ts b/packages/lit-auth-client/src/lib/lit-auth-client.ts index d2d4dc0574..8089d0fbf9 100644 --- a/packages/lit-auth-client/src/lib/lit-auth-client.ts +++ b/packages/lit-auth-client/src/lib/lit-auth-client.ts @@ -138,8 +138,7 @@ export class LitAuthClient { } // Set RPC URL - this.rpcUrl = - options?.rpcUrl || 'https://lit-protocol.calderachain.xyz/replica-http'; + this.rpcUrl = options?.rpcUrl || 'https://chain-rpc.litprotocol.com/http'; log('rpc url: ', this.rpcUrl); log('relay config: ', options.litRelayConfig); log('relay instance: ', this.relay); From a36fe46dda3e33ccc31e39109c3695b7acb5bd14 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 17:41:24 -0400 Subject: [PATCH 247/263] ref(tinny): remove first test key due to failure on mint calls --- local-tests/setup/tinny-environment.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 65da822020..648b90f551 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -52,7 +52,6 @@ export class TinnyEnvironment { // (8) "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f" (10000.000000000000000000 ETH) // (9) "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" (10000.000000000000000000 ETH) PRIVATE_KEYS: process.env['PRIVATE_KEYS']?.split(',') || [ - '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a', '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6', From 96d748cdd96d8d0f6ec8fa11a7260fbc53b50fb5 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 18:04:18 -0400 Subject: [PATCH 248/263] ref(contracts-sdk): add max retry to contract pkp pub key reads for replication delay issues. --- .../contracts-sdk/src/lib/contracts-sdk.ts | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 9419001fda..edb646fc75 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1092,10 +1092,21 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope tokenId = events[0].topics[1]; console.warn('tokenId:', tokenId); - await new Promise((resolve, _reject) => { - setTimeout(resolve, 10_000); - }); - let publicKey = await this.pkpNftContract.read.getPubkey(tokenId); + let tries = 0; + let maxAttempts = 10; + let publicKey = ''; + while (tries < maxAttempts) { + publicKey = await this.pkpNftContract.read.getPubkey(tokenId); + console.log("pkp pub key: ", publicKey) + if (publicKey !== "0x") { + break; + } + tries++; + await new Promise((resolve, _reject) => { + setTimeout(resolve, 10_000); + }); + } + if (publicKey.startsWith('0x')) { publicKey = publicKey.slice(2); @@ -1626,12 +1637,21 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope tokenIdFromEvent = events[0].topics[1]; console.warn('tokenIdFromEvent:', tokenIdFromEvent); - await new Promise((resolve, _reject) => { - setTimeout(resolve, 5_000); - }); - let publicKey = await this.pkpNftContract.read.getPubkey( - tokenIdFromEvent - ); + let tries = 0; + let maxAttempts = 10; + let publicKey = ''; + while (tries < maxAttempts) { + publicKey = await this.pkpNftContract.read.getPubkey(tokenId); + console.log("pkp pub key: ", publicKey) + if (publicKey !== "0x") { + break; + } + tries++; + await new Promise((resolve, _reject) => { + setTimeout(resolve, 10_000); + }); + } + console.warn("public key from token id", publicKey); if (publicKey.startsWith('0x')) { publicKey = publicKey.slice(2); From 2b869559d3652b0d77f4d735d56b0e3834f85d2b Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 18:04:54 -0400 Subject: [PATCH 249/263] chore: fmt --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index edb646fc75..3c71345514 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1097,8 +1097,8 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope let publicKey = ''; while (tries < maxAttempts) { publicKey = await this.pkpNftContract.read.getPubkey(tokenId); - console.log("pkp pub key: ", publicKey) - if (publicKey !== "0x") { + console.log('pkp pub key: ', publicKey); + if (publicKey !== '0x') { break; } tries++; @@ -1107,7 +1107,6 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope }); } - if (publicKey.startsWith('0x')) { publicKey = publicKey.slice(2); } @@ -1642,8 +1641,8 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope let publicKey = ''; while (tries < maxAttempts) { publicKey = await this.pkpNftContract.read.getPubkey(tokenId); - console.log("pkp pub key: ", publicKey) - if (publicKey !== "0x") { + console.log('pkp pub key: ', publicKey); + if (publicKey !== '0x') { break; } tries++; @@ -1652,7 +1651,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope }); } - console.warn("public key from token id", publicKey); + console.warn('public key from token id', publicKey); if (publicKey.startsWith('0x')) { publicKey = publicKey.slice(2); } From f6499bad538ba0c3de8e13a06792c90a0023b294 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 18:06:08 -0400 Subject: [PATCH 250/263] chore: change version for testing publish "6.0.0-testing.4" --- lerna.json | 2 +- packages/constants/src/lib/version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 0a888f9cfd..ce9ff7a9de 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "useNx": true, "useWorkspaces": true, - "version": "6.0.0-beta.4" + "version": "6.0.0-testing.4" } diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index 1b8c7c6e9e..2db97ac5f1 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = '6.0.0-beta.4'; +export const version = "6.0.0-testing.4"; From ce34e543379faf83581453b58f3dc54f5613ceb9 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 18:44:03 -0400 Subject: [PATCH 251/263] ref(contracts-sdk): fix var name --- packages/contracts-sdk/src/lib/contracts-sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 3c71345514..2955d6d9d2 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1640,7 +1640,7 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope let maxAttempts = 10; let publicKey = ''; while (tries < maxAttempts) { - publicKey = await this.pkpNftContract.read.getPubkey(tokenId); + publicKey = await this.pkpNftContract.read.getPubkey(tokenIdFromEvent); console.log('pkp pub key: ', publicKey); if (publicKey !== '0x') { break; From d35a75e30883bc33e4e3da1411232624470b7c48 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Wed, 29 May 2024 18:46:49 -0400 Subject: [PATCH 252/263] Publish 6.0.0-testing.4 --- packages/access-control-conditions/package.json | 4 ++-- packages/auth-browser/package.json | 4 ++-- packages/auth-helpers/package.json | 4 ++-- packages/bls-sdk/package.json | 4 ++-- packages/constants/package.json | 4 ++-- packages/contracts-sdk/package.json | 4 ++-- packages/core/package.json | 4 ++-- packages/crypto/package.json | 4 ++-- packages/ecdsa-sdk/package.json | 4 ++-- packages/encryption/package.json | 4 ++-- packages/lit-auth-client/package.json | 4 ++-- packages/lit-node-client-nodejs/package.json | 4 ++-- packages/lit-node-client/package.json | 4 ++-- packages/logger/package.json | 4 ++-- packages/misc-browser/package.json | 4 ++-- packages/misc/package.json | 4 ++-- packages/nacl/package.json | 4 ++-- packages/pkp-base/package.json | 4 ++-- packages/pkp-client/package.json | 4 ++-- packages/pkp-cosmos/package.json | 4 ++-- packages/pkp-ethers/package.json | 4 ++-- packages/pkp-sui/package.json | 4 ++-- packages/pkp-walletconnect/package.json | 4 ++-- packages/sev-snp-utils-sdk/package.json | 4 ++-- packages/types/package.json | 4 ++-- packages/uint8arrays/package.json | 4 ++-- tsconfig.json | 17 +++++++++++++---- 27 files changed, 65 insertions(+), 56 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 80a3421371..77c257ecfe 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index d4f77871b6..404c30a4f2 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -30,7 +30,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 2f4a6e197e..2f5f52fb5e 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index c290e8cecd..f0b7065887 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/constants/package.json b/packages/constants/package.json index d25e77fb5e..4a34a2c3fe 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index e6b9e53dfc..53b0e9a532 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -32,7 +32,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index aaf2261fbf..d4e3ac3653 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/core", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 553e900121..96255dcd09 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index faf66d11a3..dbba053750 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 0281ef2b68..920078e13e 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -25,7 +25,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index c52c0668c5..9f66022f73 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/lit-auth-client", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 6f60d9de64..4ada04b1fc 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -24,7 +24,7 @@ "tags": [ "nodejs" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index 65a42336a0..3a95a2fa93 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -28,7 +28,7 @@ "crypto": false, "stream": false }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/logger/package.json b/packages/logger/package.json index 1292dd2d08..b701733f89 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/logger", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "tags": [ "universal" @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index 1bdaaf3d3f..af1f7acfec 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -21,7 +21,7 @@ "tags": [ "browser" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/misc/package.json b/packages/misc/package.json index f13a758c4e..8c486120f2 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -24,7 +24,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 237805d876..57f2fb0dc2 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -21,7 +21,7 @@ "access": "public", "directory": "../../dist/packages/nacl" }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index a71ab5d5f2..87ba13a289 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-base", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index dfbeb5eb4e..47ebc93693 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-client", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index 666c99169f..fec47b15b8 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-cosmos", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index f42b7b5e10..0807d36cbd 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -20,7 +20,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index e12863949d..00a766a37b 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-sui", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 89381a89ac..800435ac04 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@lit-protocol/pkp-walletconnect", - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "type": "commonjs", "license": "MIT", "homepage": "https://github.com/Lit-Protocol/js-sdk", @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index 8c90087e31..e8ba9f330d 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -27,7 +27,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/types/package.json b/packages/types/package.json index 2eae993602..2380f0673d 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -23,7 +23,7 @@ "buildOptions": { "genReact": false }, - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index 2c5ea4435e..adbadf3976 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -21,7 +21,7 @@ "tags": [ "universal" ], - "version": "6.0.0-beta.4", + "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d79d1c4238..e8f4e19b50 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,15 +10,24 @@ "importHelpers": true, "target": "ES2020", "module": "ES2020", - "lib": ["ES2020", "dom", "ES2021.String"], + "lib": [ + "ES2020", + "dom", + "ES2021.String" + ], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "paths": { - "@lit-protocol/*": ["packages/*/src"] + "@lit-protocol/*": [ + "packages/*/src" + ] } }, - "exclude": ["node_modules", "tmp"] -} + "exclude": [ + "node_modules", + "tmp" + ] +} \ No newline at end of file From 7a6ea8254f52de6f1f5870d5f80af58f7b3d357f Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 30 May 2024 07:49:08 -0400 Subject: [PATCH 253/263] ref(core): rename blockhash helper --- packages/core/src/lib/lit-core.ts | 62 ++++++++++++++++--------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 3d24e72e51..40de7c42da 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -519,7 +519,7 @@ export class LitCore { * @returns { Promise } latest blockhash */ getLatestBlockhash = async (): Promise => { - await this.connect(); + await this._syncBlockhash(); if (!this.latestBlockhash) { throw new Error( @@ -809,6 +809,36 @@ export class LitCore { }; } + private async _syncBlockhash() { + if ( + !this.lastBlockHashRetrieved || + Date.now() - this.lastBlockHashRetrieved >= BLOCKHASH_SYNC_INTERVAL + ) { + log( + 'Syncing state for new blockhash ', + 'current blockhash: ', + this.latestBlockhash + ); + try { + const blockHashFetchResp = await fetch(this._blockHashUrl); + const blockHashBody: any = await blockHashFetchResp.json(); + this.latestBlockhash = blockHashBody.blockhash; + this.lastBlockHashRetrieved = Date.now(); + log( + 'Done syncing state new blockhash: ', + this.latestBlockhash + ); + } catch (err: unknown) { + // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError + const { message = '' } = err as Error | NodeClientErrorV1; + logError( + 'Error while attempting fetch new latestBlockhash:', + message + ); + } + } + } + /** Currently, we perform a full sync every 30s, including handshaking with every node * However, we also have a state change listener that watches for staking contract state change events, which * _should_ be the only time that we need to perform handshakes with every node. @@ -825,35 +855,7 @@ export class LitCore { } this._networkSyncInterval = setInterval(async () => { - if ( - !this.lastBlockHashRetrieved || - Date.now() - this.lastBlockHashRetrieved >= BLOCKHASH_SYNC_INTERVAL - ) { - log( - 'Syncing state for new blockhash ', - 'current blockhash: ', - this.lastBlockHashRetrieved - ); - try { - const blockHashFetchResp = await fetch(this._blockHashUrl); - const blockHashBody: any = await blockHashFetchResp.json(); - this.latestBlockhash = blockHashBody.blockhash; - this.lastBlockHashRetrieved = Date.now(); - log( - 'Done syncing state new blockhash: ', - this.lastBlockHashRetrieved, - 'new blockhash: ', - blockHashBody.blockhash - ); - } catch (err: unknown) { - // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError - const { message = '' } = err as Error | NodeClientErrorV1; - logError( - 'Error while attempting fetch new latestBlockhash:', - message - ); - } - } + await this._syncBlockhash(); }, BLOCKHASH_SYNC_INTERVAL); } From 623a039de023daad7c291907058d3cb400a73c4c Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 30 May 2024 07:52:07 -0400 Subject: [PATCH 254/263] chore: fmt --- packages/access-control-conditions/package.json | 2 +- packages/auth-browser/package.json | 2 +- packages/auth-helpers/package.json | 2 +- packages/bls-sdk/package.json | 2 +- packages/constants/package.json | 2 +- packages/constants/src/lib/version.ts | 2 +- packages/contracts-sdk/package.json | 2 +- packages/contracts-sdk/src/lib/contracts-sdk.ts | 4 +++- packages/core/package.json | 2 +- packages/crypto/package.json | 2 +- packages/ecdsa-sdk/package.json | 2 +- packages/encryption/package.json | 2 +- packages/lit-auth-client/package.json | 2 +- packages/lit-node-client-nodejs/package.json | 2 +- packages/lit-node-client/package.json | 2 +- packages/logger/package.json | 2 +- packages/misc-browser/package.json | 2 +- packages/misc/package.json | 2 +- packages/nacl/package.json | 2 +- packages/pkp-base/package.json | 2 +- packages/pkp-client/package.json | 2 +- packages/pkp-cosmos/package.json | 2 +- packages/pkp-ethers/package.json | 2 +- packages/pkp-sui/package.json | 2 +- packages/pkp-walletconnect/package.json | 2 +- packages/sev-snp-utils-sdk/package.json | 2 +- packages/types/package.json | 2 +- packages/uint8arrays/package.json | 2 +- tsconfig.json | 17 ++++------------- 29 files changed, 34 insertions(+), 41 deletions(-) diff --git a/packages/access-control-conditions/package.json b/packages/access-control-conditions/package.json index 77c257ecfe..d1fc822d44 100644 --- a/packages/access-control-conditions/package.json +++ b/packages/access-control-conditions/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-browser/package.json b/packages/auth-browser/package.json index 404c30a4f2..fd221ac8cc 100644 --- a/packages/auth-browser/package.json +++ b/packages/auth-browser/package.json @@ -33,4 +33,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/auth-helpers/package.json b/packages/auth-helpers/package.json index 2f5f52fb5e..f69c56ad35 100644 --- a/packages/auth-helpers/package.json +++ b/packages/auth-helpers/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/bls-sdk/package.json b/packages/bls-sdk/package.json index f0b7065887..23bd0fec81 100644 --- a/packages/bls-sdk/package.json +++ b/packages/bls-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/package.json b/packages/constants/package.json index 4a34a2c3fe..9d0076c365 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/constants/src/lib/version.ts b/packages/constants/src/lib/version.ts index 2db97ac5f1..a39a859ada 100644 --- a/packages/constants/src/lib/version.ts +++ b/packages/constants/src/lib/version.ts @@ -1 +1 @@ -export const version = "6.0.0-testing.4"; +export const version = '6.0.0-testing.4'; diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 53b0e9a532..79b4a8d05d 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -35,4 +35,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/contracts-sdk/src/lib/contracts-sdk.ts b/packages/contracts-sdk/src/lib/contracts-sdk.ts index 2955d6d9d2..fcec26e8ba 100644 --- a/packages/contracts-sdk/src/lib/contracts-sdk.ts +++ b/packages/contracts-sdk/src/lib/contracts-sdk.ts @@ -1640,7 +1640,9 @@ https://developer.litprotocol.com/v3/sdk/wallets/auth-methods/#auth-method-scope let maxAttempts = 10; let publicKey = ''; while (tries < maxAttempts) { - publicKey = await this.pkpNftContract.read.getPubkey(tokenIdFromEvent); + publicKey = await this.pkpNftContract.read.getPubkey( + tokenIdFromEvent + ); console.log('pkp pub key: ', publicKey); if (publicKey !== '0x') { break; diff --git a/packages/core/package.json b/packages/core/package.json index d4e3ac3653..a02ac83c4c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 96255dcd09..93ac2c9ec8 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/ecdsa-sdk/package.json b/packages/ecdsa-sdk/package.json index dbba053750..f5e065c43b 100644 --- a/packages/ecdsa-sdk/package.json +++ b/packages/ecdsa-sdk/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 920078e13e..b002155b59 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -28,4 +28,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-auth-client/package.json b/packages/lit-auth-client/package.json index 9f66022f73..c695db0d6a 100644 --- a/packages/lit-auth-client/package.json +++ b/packages/lit-auth-client/package.json @@ -32,4 +32,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client-nodejs/package.json b/packages/lit-node-client-nodejs/package.json index 4ada04b1fc..0a457491e6 100644 --- a/packages/lit-node-client-nodejs/package.json +++ b/packages/lit-node-client-nodejs/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/lit-node-client/package.json b/packages/lit-node-client/package.json index 3a95a2fa93..37b044cf1c 100644 --- a/packages/lit-node-client/package.json +++ b/packages/lit-node-client/package.json @@ -31,4 +31,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/logger/package.json b/packages/logger/package.json index b701733f89..aaa851c141 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,4 +11,4 @@ }, "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc-browser/package.json b/packages/misc-browser/package.json index af1f7acfec..ad4b74ee8d 100644 --- a/packages/misc-browser/package.json +++ b/packages/misc-browser/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/misc/package.json b/packages/misc/package.json index 8c486120f2..f3dd97a52f 100644 --- a/packages/misc/package.json +++ b/packages/misc/package.json @@ -27,4 +27,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/nacl/package.json b/packages/nacl/package.json index 57f2fb0dc2..31918dc856 100644 --- a/packages/nacl/package.json +++ b/packages/nacl/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-base/package.json b/packages/pkp-base/package.json index 87ba13a289..de8da3117d 100644 --- a/packages/pkp-base/package.json +++ b/packages/pkp-base/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-client/package.json b/packages/pkp-client/package.json index 47ebc93693..8bec1337de 100644 --- a/packages/pkp-client/package.json +++ b/packages/pkp-client/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-cosmos/package.json b/packages/pkp-cosmos/package.json index fec47b15b8..e083674e58 100644 --- a/packages/pkp-cosmos/package.json +++ b/packages/pkp-cosmos/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-ethers/package.json b/packages/pkp-ethers/package.json index 0807d36cbd..4a7f77ad39 100644 --- a/packages/pkp-ethers/package.json +++ b/packages/pkp-ethers/package.json @@ -23,4 +23,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-sui/package.json b/packages/pkp-sui/package.json index 00a766a37b..eeab5ed338 100644 --- a/packages/pkp-sui/package.json +++ b/packages/pkp-sui/package.json @@ -27,4 +27,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/pkp-walletconnect/package.json b/packages/pkp-walletconnect/package.json index 800435ac04..1930bc7b80 100644 --- a/packages/pkp-walletconnect/package.json +++ b/packages/pkp-walletconnect/package.json @@ -34,4 +34,4 @@ ], "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/sev-snp-utils-sdk/package.json b/packages/sev-snp-utils-sdk/package.json index e8ba9f330d..5d5ba06174 100644 --- a/packages/sev-snp-utils-sdk/package.json +++ b/packages/sev-snp-utils-sdk/package.json @@ -30,4 +30,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/types/package.json b/packages/types/package.json index 2380f0673d..a2f83bf79e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,4 +26,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/packages/uint8arrays/package.json b/packages/uint8arrays/package.json index adbadf3976..e55b8adeb4 100644 --- a/packages/uint8arrays/package.json +++ b/packages/uint8arrays/package.json @@ -24,4 +24,4 @@ "version": "6.0.0-testing.4", "main": "./dist/src/index.js", "typings": "./dist/src/index.d.ts" -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index e8f4e19b50..d79d1c4238 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,24 +10,15 @@ "importHelpers": true, "target": "ES2020", "module": "ES2020", - "lib": [ - "ES2020", - "dom", - "ES2021.String" - ], + "lib": ["ES2020", "dom", "ES2021.String"], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "paths": { - "@lit-protocol/*": [ - "packages/*/src" - ] + "@lit-protocol/*": ["packages/*/src"] } }, - "exclude": [ - "node_modules", - "tmp" - ] -} \ No newline at end of file + "exclude": ["node_modules", "tmp"] +} From 6b568af3396c04ec6972a096bea4950a4f5accde Mon Sep 17 00:00:00 2001 From: Josh Long Date: Thu, 30 May 2024 10:23:59 -0400 Subject: [PATCH 255/263] ref(core): move timestamp check to interval polling --- .../session-sigs/get-eoa-session-sigs.ts | 2 +- local-tests/setup/tinny-environment.ts | 4 +- local-tests/setup/tinny-person.ts | 2 +- packages/core/src/lib/lit-core.ts | 53 ++++++++++--------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/local-tests/setup/session-sigs/get-eoa-session-sigs.ts b/local-tests/setup/session-sigs/get-eoa-session-sigs.ts index e6afeaef70..19f0a860e9 100644 --- a/local-tests/setup/session-sigs/get-eoa-session-sigs.ts +++ b/local-tests/setup/session-sigs/get-eoa-session-sigs.ts @@ -136,7 +136,7 @@ export const getEoaSessionSigsWithCapacityDelegations = async ( expiration: expiration, resources: resourceAbilityRequests, walletAddress: fromWallet.address, - nonce: await devEnv.litNodeClient.getLatestBlockhash(), + nonce: devEnv.litNodeClient.latestBlockhash, litNodeClient: devEnv.litNodeClient, }); diff --git a/local-tests/setup/tinny-environment.ts b/local-tests/setup/tinny-environment.ts index 648b90f551..30b55e2ee8 100644 --- a/local-tests/setup/tinny-environment.ts +++ b/local-tests/setup/tinny-environment.ts @@ -21,7 +21,7 @@ export class TinnyEnvironment { public processEnvs: ProcessEnvs = { MAX_ATTEMPTS: parseInt(process.env['MAX_ATTEMPTS']) || 1, NETWORK: (process.env['NETWORK'] as LIT_TESTNET) || LIT_TESTNET.LOCALCHAIN, - DEBUG: Boolean(process.env['DEBUG']) || false, + DEBUG: process.env['DEBUG'] === 'true', REQUEST_PER_KILOSECOND: parseInt(process.env['REQUEST_PER_KILOSECOND']) || 200, LIT_RPC_URL: process.env['LIT_RPC_URL'] || 'http://127.0.0.1:8545', @@ -326,7 +326,7 @@ export class TinnyEnvironment { const toSign = await createSiweMessage({ walletAddress: wallet.address, - nonce: await this.litNodeClient.getLatestBlockhash(), + nonce: this.litNodeClient.latestBlockhash, expiration: new Date(Date.now() + 29 * 24 * 60 * 60 * 1000).toISOString(), litNodeClient: this.litNodeClient, }); diff --git a/local-tests/setup/tinny-person.ts b/local-tests/setup/tinny-person.ts index e77044620f..39296f7587 100644 --- a/local-tests/setup/tinny-person.ts +++ b/local-tests/setup/tinny-person.ts @@ -74,7 +74,7 @@ export class TinnyPerson { * ==================================== */ this.siweMessage = await createSiweMessage({ - nonce: await this.envConfig.litNodeClient.getLatestBlockhash(), + nonce: this.envConfig.litNodeClient.latestBlockhash, walletAddress: this.wallet.address, }); diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 40de7c42da..fcd9bae5b2 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -519,8 +519,9 @@ export class LitCore { * @returns { Promise } latest blockhash */ getLatestBlockhash = async (): Promise => { + console.log('querying latest blockhash curent value is ', this.latestBlockhash); await this._syncBlockhash(); - + console.log(`querying latest blockhash current value is `, this.latestBlockhash); if (!this.latestBlockhash) { throw new Error( `latestBlockhash is not available. Received: "${this.latestBlockhash}"` @@ -810,33 +811,28 @@ export class LitCore { } private async _syncBlockhash() { - if ( - !this.lastBlockHashRetrieved || - Date.now() - this.lastBlockHashRetrieved >= BLOCKHASH_SYNC_INTERVAL - ) { + log( + 'Syncing state for new blockhash ', + 'current blockhash: ', + this.latestBlockhash + ); + try { + const blockHashFetchResp = await fetch(this._blockHashUrl); + const blockHashBody: any = await blockHashFetchResp.json(); + this.latestBlockhash = blockHashBody.blockhash; + this.lastBlockHashRetrieved = Date.now(); log( - 'Syncing state for new blockhash ', - 'current blockhash: ', + 'Done syncing state new blockhash: ', this.latestBlockhash ); - try { - const blockHashFetchResp = await fetch(this._blockHashUrl); - const blockHashBody: any = await blockHashFetchResp.json(); - this.latestBlockhash = blockHashBody.blockhash; - this.lastBlockHashRetrieved = Date.now(); - log( - 'Done syncing state new blockhash: ', - this.latestBlockhash - ); - } catch (err: unknown) { - // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError - const { message = '' } = err as Error | NodeClientErrorV1; - logError( - 'Error while attempting fetch new latestBlockhash:', - message - ); - } - } + } catch (err: unknown) { + // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError + const { message = '' } = err as Error | NodeClientErrorV1; + logError( + 'Error while attempting fetch new latestBlockhash:', + message + ); + } } /** Currently, we perform a full sync every 30s, including handshaking with every node @@ -855,7 +851,12 @@ export class LitCore { } this._networkSyncInterval = setInterval(async () => { - await this._syncBlockhash(); + if ( + !this.lastBlockHashRetrieved || + Date.now() - this.lastBlockHashRetrieved >= BLOCKHASH_SYNC_INTERVAL + ) { + await this._syncBlockhash(); + } }, BLOCKHASH_SYNC_INTERVAL); } From 92a4ac55fb01a3dd49c8d62abc6bb472c4c12ee4 Mon Sep 17 00:00:00 2001 From: Anson Date: Fri, 31 May 2024 14:34:36 +0100 Subject: [PATCH 256/263] fix(lit-node-client-nodejs): build --- .../src/lib/lit-node-client-nodejs.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 4e944401ed..59cdb0dca7 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -16,7 +16,6 @@ import { createSiweMessage, } from '@lit-protocol/auth-helpers'; import { - AUTH_METHOD_TYPE_IDS, AuthMethodType, EITHER_TYPE, LIT_ACTION_IPFS_HASH, @@ -64,7 +63,6 @@ import { import type { AuthCallback, AuthCallbackParams, - AuthMethod, AuthSig, ClaimKeyResponse, ClaimProcessor, @@ -112,6 +110,9 @@ import type { EncryptSdkParams, GetLitActionSessionSigs, GetSignSessionKeySharesProp, + EncryptionSignRequest, + SigningAccessControlConditionRequest, + JsonPKPClaimKeyRequest, } from '@lit-protocol/types'; import * as blsSdk from '@lit-protocol/bls-sdk'; @@ -126,11 +127,6 @@ import { normalizeArray } from './helpers/normalize-array'; import { parsePkpSignResponse } from './helpers/parse-pkp-sign-response'; import { getBlsSignatures } from './helpers/get-bls-signatures'; import { processLitActionResponseStrategy } from './helpers/process-lit-action-response-strategy'; -import { - EncryptionSignRequest, - JsonPKPClaimKeyRequest, - SigningAccessControlConditionRequest, -} from 'packages/types/src/lib/node-interfaces/node-interfaces'; export class LitNodeClientNodeJs extends LitCore From 990ea2f408581db7f41136a1492a8f64a5ed9966 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 31 May 2024 15:15:20 -0400 Subject: [PATCH 257/263] ref(core): Move staking event from locked to active. --- packages/core/src/lib/lit-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index fcd9bae5b2..5734f574ba 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -374,7 +374,7 @@ export class LitCore { private async _handleStakingContractStateChange(state: StakingStates) { log(`New state detected: "${state}"`); - if (state === StakingStates.NextValidatorSetLocked) { + if (state === StakingStates.Active) { // We always want to track the most recent epoch number on _all_ networks this._scheduleEpochNumberUpdate(); From d08d059ae5383c397077cedfb31a43f8391f0bd1 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 31 May 2024 17:46:43 -0400 Subject: [PATCH 258/263] ref(core): swap local url for remote url. --- packages/core/src/lib/lit-core.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 5734f574ba..8b83ebc958 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -139,7 +139,7 @@ export class LitCore { currentNumber: null, lastUpdateTime: null, }; - private _blockHashUrl = "http://0.0.0.0:8080/get_most_recent_valid_block"; + private _blockHashUrl = 'http://block-indexer.litgateway.com/get_most_recent_valid_block'; // ========== Constructor ========== constructor(config: LitNodeClientConfig | CustomNetwork) { // Initialize default config based on litNetwork @@ -519,9 +519,15 @@ export class LitCore { * @returns { Promise } latest blockhash */ getLatestBlockhash = async (): Promise => { - console.log('querying latest blockhash curent value is ', this.latestBlockhash); - await this._syncBlockhash(); - console.log(`querying latest blockhash current value is `, this.latestBlockhash); + console.log( + 'querying latest blockhash curent value is ', + this.latestBlockhash + ); + await this._syncBlockhash(); + console.log( + `querying latest blockhash current value is `, + this.latestBlockhash + ); if (!this.latestBlockhash) { throw new Error( `latestBlockhash is not available. Received: "${this.latestBlockhash}"` @@ -820,19 +826,13 @@ export class LitCore { const blockHashFetchResp = await fetch(this._blockHashUrl); const blockHashBody: any = await blockHashFetchResp.json(); this.latestBlockhash = blockHashBody.blockhash; - this.lastBlockHashRetrieved = Date.now(); - log( - 'Done syncing state new blockhash: ', - this.latestBlockhash - ); + this.lastBlockHashRetrieved = Date.now(); + log('Done syncing state new blockhash: ', this.latestBlockhash); } catch (err: unknown) { // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError const { message = '' } = err as Error | NodeClientErrorV1; - logError( - 'Error while attempting fetch new latestBlockhash:', - message - ); - } + logError('Error while attempting fetch new latestBlockhash:', message); + } } /** Currently, we perform a full sync every 30s, including handshaking with every node From 6cdc0cd1bae3ccab4ad68de173d3d123e47301c2 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Fri, 31 May 2024 18:31:43 -0400 Subject: [PATCH 259/263] chore: fmt --- packages/core/src/lib/lit-core.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 8b83ebc958..7e537cad87 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -139,7 +139,8 @@ export class LitCore { currentNumber: null, lastUpdateTime: null, }; - private _blockHashUrl = 'http://block-indexer.litgateway.com/get_most_recent_valid_block'; + private _blockHashUrl = + 'http://block-indexer.litgateway.com/get_most_recent_valid_block'; // ========== Constructor ========== constructor(config: LitNodeClientConfig | CustomNetwork) { // Initialize default config based on litNetwork From 08a1635bdba0d35af3912f4acfdba45e45c64ce2 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Sat, 1 Jun 2024 12:28:14 -0400 Subject: [PATCH 260/263] feat(core): add types and error handling for latest blockhash --- packages/core/src/lib/lit-core.ts | 36 +++++++++++++++++++--------- packages/types/src/lib/interfaces.ts | 12 ++++++++++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 7e537cad87..51c99ce069 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -64,9 +64,13 @@ import type { SessionSigsMap, SuccessNodePromises, SupportedJsonRequests, + BlockHashErrorResponse, + EthBlockhashInfo } from '@lit-protocol/types'; import { composeLitUrl } from './endpoint-version'; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any type Listener = (...args: any[]) => void; @@ -817,23 +821,33 @@ export class LitCore { }; } + /** + * Fetches the latest block hash and log any errors that are returned + * @returns void + */ private async _syncBlockhash() { log( 'Syncing state for new blockhash ', 'current blockhash: ', this.latestBlockhash ); - try { - const blockHashFetchResp = await fetch(this._blockHashUrl); - const blockHashBody: any = await blockHashFetchResp.json(); - this.latestBlockhash = blockHashBody.blockhash; - this.lastBlockHashRetrieved = Date.now(); - log('Done syncing state new blockhash: ', this.latestBlockhash); - } catch (err: unknown) { - // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError - const { message = '' } = err as Error | NodeClientErrorV1; - logError('Error while attempting fetch new latestBlockhash:', message); - } + + return fetch(this._blockHashUrl) + .then(async (resp: Response) => { + const blockHashBody: EthBlockhashInfo = await resp.json(); + this.latestBlockhash = blockHashBody.blockhash; + this.lastBlockHashRetrieved = Date.now(); + log('Done syncing state new blockhash: ', this.latestBlockhash); + }) + .catch((err: BlockHashErrorResponse) => { + // Don't let error from this setInterval handler bubble up to runtime; it'd be an unhandledRejectionError + logError( + 'Error while attempting fetch new latestBlockhash:', + err.messages, + 'reason: ', + err.reason + ); + }); } /** Currently, we perform a full sync every 30s, including handshaking with every node diff --git a/packages/types/src/lib/interfaces.ts b/packages/types/src/lib/interfaces.ts index f86377b4df..e55eafe08c 100644 --- a/packages/types/src/lib/interfaces.ts +++ b/packages/types/src/lib/interfaces.ts @@ -1964,3 +1964,15 @@ export interface MintWithAuthResponse { }; tx: T; } + +export interface BlockHashErrorResponse { + messages: string[]; + reason: String; + codde: Number; +} + +export interface EthBlockhashInfo { + blockhash: string; + timestamp: string; + blockNumber: number; +} From 58792f669a88cadc472fb029af31ea96c14a98db Mon Sep 17 00:00:00 2001 From: Josh Long Date: Sun, 2 Jun 2024 20:35:37 -0400 Subject: [PATCH 261/263] chore: fmt --- packages/core/src/lib/lit-core.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/core/src/lib/lit-core.ts b/packages/core/src/lib/lit-core.ts index 51c99ce069..fca499a804 100644 --- a/packages/core/src/lib/lit-core.ts +++ b/packages/core/src/lib/lit-core.ts @@ -65,12 +65,10 @@ import type { SuccessNodePromises, SupportedJsonRequests, BlockHashErrorResponse, - EthBlockhashInfo + EthBlockhashInfo, } from '@lit-protocol/types'; import { composeLitUrl } from './endpoint-version'; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any type Listener = (...args: any[]) => void; From 31ce5c71369ef48e7761d2f5beeeda1bce9f0001 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 3 Jun 2024 13:02:13 +0100 Subject: [PATCH 262/263] chore: remove unused imports --- packages/types/src/lib/ILitNodeClient.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/types/src/lib/ILitNodeClient.ts b/packages/types/src/lib/ILitNodeClient.ts index bc36f3da04..d2310b20a5 100644 --- a/packages/types/src/lib/ILitNodeClient.ts +++ b/packages/types/src/lib/ILitNodeClient.ts @@ -6,18 +6,10 @@ import { ExecuteJsResponse, FormattedMultipleAccs, GetSignedTokenRequest, - HandshakeWithNode, - JsonExecutionRequest, JsonExecutionSdkParams, JsonHandshakeResponse, LitNodeClientConfig, MultipleAccessControlConditions, - NodeBlsSigningShare, - NodeCommandResponse, - NodeCommandServerKeysResponse, - RejectedNodePromises, - SendNodeCommand, - SuccessNodePromises, } from './interfaces'; import { ILitResource, ISessionCapabilityObject } from './models'; import { SupportedJsonRequests } from './types'; From 0b55cae330496486335cebf36ac18e2aed14d2e0 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 3 Jun 2024 13:02:42 +0100 Subject: [PATCH 263/263] chore: remove unused imports --- .../lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts index 31a86b96d5..ca5df0f27a 100644 --- a/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts +++ b/packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts @@ -69,7 +69,6 @@ import type { CustomNetwork, DecryptRequest, DecryptResponse, - EncryptRequest, EncryptResponse, ExecuteJsResponse, FormattedMultipleAccs,