diff --git a/background/main.ts b/background/main.ts index bdf071c310..4420b5eec1 100644 --- a/background/main.ts +++ b/background/main.ts @@ -115,9 +115,16 @@ import { signingSliceEmitter, typedDataRequest, signDataRequest, + getPLUMESignatureRequest, + signedPLUME, } from "./redux-slices/signing" -import { SignTypedDataRequest, MessageSigningRequest } from "./utils/signing" +import { + SignTypedDataRequest, + MessageSigningRequest, + PLUMESigningRequest, + PLUMESigningResponse, +} from "./utils/signing" import { emitter as earnSliceEmitter, setVaultsAsStale, @@ -132,6 +139,7 @@ import { ETHEREUM, FLASHBOTS_RPC_URL, OPTIMISM, USD } from "./constants" import { clearApprovalInProgress, clearSwapQuote } from "./redux-slices/0x-swap" import { AccountSigner, + PLUMESignatureResponse, SignatureResponse, TXSignatureResponse, } from "./services/signing" @@ -984,6 +992,18 @@ export default class Main extends BaseService { this.store.dispatch(signedDataAction(signedData)) }, ) + signingSliceEmitter.on( + "requestSignPLUME", + async ({ rawSigningData, account, accountSigner, plumeVersion }) => { + const signedData = await this.signingService.signPLUME( + account, + rawSigningData, + accountSigner, + plumeVersion, + ) + this.store.dispatch(signedPLUME(signedData)) + }, + ) this.chainService.emitter.on( "blockPrices", @@ -1342,6 +1362,61 @@ export default class Main extends BaseService { signingSliceEmitter.on("signatureRejected", rejectAndClear) }, ) + this.internalEthereumProviderService.emitter.on( + "getPLUMESignatureRequest", + async ({ + payload, + resolver, + rejecter, + }: { + payload: PLUMESigningRequest + resolver: ( + result: PLUMESigningResponse | PromiseLike, + ) => void + rejecter: () => void + }) => { + await this.signingService.prepareForSigningRequest() + + this.store.dispatch(getPLUMESignatureRequest(payload)) + + const clear = () => { + this.signingService.emitter.off( + "PLUMESigningResponse", + // Mutual dependency to handleAndClear. + // eslint-disable-next-line @typescript-eslint/no-use-before-define + handleAndClear, + ) + + signingSliceEmitter.off( + "signatureRejected", + // Mutual dependency to rejectAndClear. + // eslint-disable-next-line @typescript-eslint/no-use-before-define + rejectAndClear, + ) + } + + const handleAndClear = (response: PLUMESignatureResponse) => { + clear() + switch (response.type) { + case "success-data": + resolver(response.plume) + break + default: + rejecter() + break + } + } + + const rejectAndClear = () => { + clear() + rejecter() + } + + this.signingService.emitter.on("PLUMESigningResponse", handleAndClear) + + signingSliceEmitter.on("signatureRejected", rejectAndClear) + }, + ) this.internalEthereumProviderService.emitter.on( "signDataRequest", async ({ diff --git a/background/package.json b/background/package.json index 1bcd961a75..0818222d48 100644 --- a/background/package.json +++ b/background/package.json @@ -61,6 +61,7 @@ "immer": "^9.0.1", "jsondiffpatch": "^0.4.1", "lodash": "^4.17.21", + "plume-sig": "^2.0.2", "sinon": "^14.0.0", "siwe": "^1.1.0", "util": "^0.12.4", diff --git a/background/redux-slices/signing.ts b/background/redux-slices/signing.ts index e389064544..5193bf692b 100644 --- a/background/redux-slices/signing.ts +++ b/background/redux-slices/signing.ts @@ -1,6 +1,11 @@ import { createSelector, createSlice } from "@reduxjs/toolkit" import Emittery from "emittery" -import { MessageSigningRequest, SignTypedDataRequest } from "../utils/signing" +import { + MessageSigningRequest, + PLUMESigningRequest, + PLUMESigningResponse, + SignTypedDataRequest, +} from "../utils/signing" import { createBackgroundAsyncThunk } from "./utils" import { EnrichedSignTypedDataRequest } from "../services/enrichment" import { EIP712TypedData } from "../types" @@ -20,6 +25,7 @@ export type SignOperationType = | SignTypedDataRequest | EIP1559TransactionRequest | LegacyEVMTransactionRequest + | PLUMESigningRequest /** * A request for a signing operation carrying the AccountSigner whose signature @@ -39,6 +45,9 @@ type Events = { requestSignData: MessageSigningRequest & { accountSigner: AccountSigner } + requestSignPLUME: PLUMESigningRequest & { + accountSigner: AccountSigner + } signatureRejected: never } @@ -50,6 +59,7 @@ type SigningState = { signedData: string | undefined signDataRequest: MessageSigningRequest | undefined + getPLUMESignatureRequest: PLUMESigningRequest | undefined additionalSigningStatus: "editing" | undefined } @@ -60,6 +70,7 @@ export const initialState: SigningState = { signedData: undefined, signDataRequest: undefined, + getPLUMESignatureRequest: undefined, additionalSigningStatus: undefined, } @@ -91,6 +102,17 @@ export const signData = createBackgroundAsyncThunk( }, ) +export const signPLUME = createBackgroundAsyncThunk( + "signing/signPLUME", + async (data: SignOperation) => { + const { request, accountSigner } = data + await signingSliceEmitter.emit("requestSignPLUME", { + ...request, + accountSigner, + }) + }, +) + const signingSlice = createSlice({ name: "signing", initialState, @@ -114,6 +136,18 @@ const signingSlice = createSlice({ ...state, signDataRequest: payload, }), + getPLUMESignatureRequest: ( + state, + { payload }: { payload: PLUMESigningRequest }, + ) => ({ + ...state, + getPLUMESignatureRequest: payload, + }), + signedPLUME: (state, { payload }: { payload: PLUMESigningResponse }) => ({ + ...state, + signedPLUME: payload, + getPLUMESignatureRequest: undefined, + }), signedData: (state, { payload }: { payload: string }) => ({ ...state, signedData: payload, @@ -124,6 +158,7 @@ const signingSlice = createSlice({ typedDataRequest: undefined, signDataRequest: undefined, additionalSigningStatus: undefined, + getPLUMESignatureRequest: undefined, }), updateAdditionalSigningStatus: ( state, @@ -142,6 +177,8 @@ export const { signDataRequest, clearSigningState, updateAdditionalSigningStatus, + getPLUMESignatureRequest, + signedPLUME, } = signingSlice.actions export default signingSlice.reducer @@ -156,6 +193,11 @@ export const selectSigningData = createSelector( (signTypes) => signTypes, ) +export const selectPLUMESigningData = createSelector( + (state: { signing: SigningState }) => state.signing.getPLUMESignatureRequest, + (signTypes) => signTypes, +) + export const selectAdditionalSigningStatus = createSelector( (state: { signing: SigningState }) => state.signing.additionalSigningStatus, (additionalSigningStatus) => additionalSigningStatus, diff --git a/background/services/internal-ethereum-provider/index.ts b/background/services/internal-ethereum-provider/index.ts index ae12acdeba..d287c112b6 100644 --- a/background/services/internal-ethereum-provider/index.ts +++ b/background/services/internal-ethereum-provider/index.ts @@ -31,6 +31,8 @@ import { SignTypedDataRequest, MessageSigningRequest, parseSigningData, + PLUMESigningResponse, + PLUMESigningRequest, } from "../../utils/signing" import { getOrCreateDB, InternalEthereumProviderDatabase } from "./db" import { TAHO_INTERNAL_ORIGIN } from "./constants" @@ -114,6 +116,10 @@ type Events = ServiceLifecycleEvents & { > signTypedDataRequest: DAppRequestEvent signDataRequest: DAppRequestEvent + getPLUMESignatureRequest: DAppRequestEvent< + PLUMESigningRequest, + PLUMESigningResponse + > selectedNetwork: EVMNetwork watchAssetRequest: { contractAddress: string; network: EVMNetwork } // connect @@ -182,6 +188,15 @@ export default class InternalEthereumProviderService extends BaseService }, typedData: JSON.parse(params[1] as string), }) + case "eth_getPlumeSignature": + return this.getPlumeSignature( + { + input: params[0] as string, + account: params[1] as string, + version: params[2] as string, + }, + origin, + ) case "eth_chainId": // TODO Decide on a better way to track whether a particular chain is // allowed to have an RPC call made to it. Ideally this would be based @@ -571,4 +586,40 @@ export default class InternalEthereumProviderService extends BaseService }) }) } + + private async getPlumeSignature( + { + input, + account, + version, + }: { + input: string + account: string + version?: string + }, + origin: string, + ) { + const currentNetwork = + await this.getCurrentOrDefaultNetworkForOrigin(origin) + const plumeVersion = version !== undefined ? Number(version) : 2 + + if (plumeVersion < 1 || plumeVersion > 2) { + throw new Error("Unsupported PLUME version.") + } + + return new Promise((resolve, reject) => { + this.emitter.emit("getPLUMESignatureRequest", { + payload: { + account: { + address: account, + network: currentNetwork, + }, + rawSigningData: input, + plumeVersion, + }, + resolver: resolve, + rejecter: reject, + }) + }) + } } diff --git a/background/services/internal-signer/index.ts b/background/services/internal-signer/index.ts index 7f81e5096c..be6c99f01e 100644 --- a/background/services/internal-signer/index.ts +++ b/background/services/internal-signer/index.ts @@ -4,6 +4,7 @@ import HDKeyring, { SerializedHDKeyring } from "@tallyho/hd-keyring" import { arrayify } from "ethers/lib/utils" import { Wallet } from "ethers" +import { computeAllInputs } from "plume-sig" import { normalizeEVMAddress, sameEVMAddress } from "../../lib/utils" import { ServiceCreatorFunction, ServiceLifecycleEvents } from "../types" import { @@ -29,6 +30,7 @@ import { AddressOnNetwork } from "../../accounts" import logger from "../../lib/logger" import PreferenceService from "../preferences" import { DEFAULT_AUTOLOCK_INTERVAL } from "../preferences/defaults" +import { PLUMESigningResponse } from "../../utils/signing" export enum SignerInternalTypes { mnemonicBIP39S128 = "mnemonic#bip39:128", @@ -1020,6 +1022,64 @@ export default class InternalSignerService extends BaseService { } } + /** + * Generate a Pseudonymously Linked Unique Message Entity based on EIP-7524 with the usage of eth_getPlumeSignature method, + * more information about the EIP can be found at https://eips.ethereum.org/EIPS/eip-7524 + * + * @param message - the message to generate a PLUME for + * @param account - signers account address + */ + async generatePLUME({ + message, + account, + version, + }: { + message: string + account: HexString + version?: number + }): Promise { + this.requireUnlocked() + const signerWithType = this.#findSigner(account) + + if (!signerWithType) { + throw new Error( + `PLUME generation failed. Signer for address ${account} was not found.`, + ) + } + + try { + let privateKey + if (isPrivateKey(signerWithType)) { + privateKey = signerWithType.signer.privateKey + } else { + privateKey = await signerWithType.signer.exportPrivateKey( + account, + "I solemnly swear that I am treating this private key material with great care.", + ) + } + if (!privateKey) { + throw new Error("Private key unavailable") + } + if (privateKey.startsWith("0x")) { + privateKey = privateKey.substring(2) + } + + const { plume, s, publicKey, c, gPowR, hashMPKPowR } = + await computeAllInputs(message, privateKey, undefined, version) + + return { + plume: `0x${plume.toHex(true)}`, + publicKey: `0x${Buffer.from(publicKey).toString("hex")}`, + hashMPKPowR: `0x${hashMPKPowR.toHex(true)}`, + gPowR: `0x${gPowR.toHex(true)}`, + c: `0x${c}`, + s: `0x${s}`, + } + } catch (error) { + throw new Error("Signing data failed") + } + } + #emitInternalSigners(): void { if (this.locked()) { this.emitter.emit("internalSigners", { diff --git a/background/services/provider-bridge/index.ts b/background/services/provider-bridge/index.ts index 072186d14c..394f0df346 100644 --- a/background/services/provider-bridge/index.ts +++ b/background/services/provider-bridge/index.ts @@ -479,6 +479,15 @@ export default class ProviderBridgeService extends BaseService { origin, showExtensionPopup(AllowedQueryParamPage.signData), ) + case "eth_getPlumeSignature": + checkPermissionSign(params[1] as HexString, enablingPermission) + + return await this.routeSafeRequest( + method, + params, + origin, + showExtensionPopup(AllowedQueryParamPage.SignPLUMEData), + ) case "eth_sign": checkPermissionSign(params[0] as HexString, enablingPermission) diff --git a/background/services/signing/index.ts b/background/services/signing/index.ts index 1fb808626c..54125af48a 100644 --- a/background/services/signing/index.ts +++ b/background/services/signing/index.ts @@ -15,6 +15,7 @@ import { ServiceCreatorFunction, ServiceLifecycleEvents } from "../types" import ChainService from "../chain" import { AddressOnNetwork } from "../../accounts" import { assertUnreachable } from "../../lib/utils/type-guards" +import { PLUMESigningResponse } from "../../utils/signing" type SigningErrorReason = "userRejected" | "genericError" type ErrorResponse = { @@ -36,10 +37,18 @@ export type SignatureResponse = } | ErrorResponse +export type PLUMESignatureResponse = + | { + type: "success-data" + plume: PLUMESigningResponse + } + | ErrorResponse + type Events = ServiceLifecycleEvents & { signingTxResponse: TXSignatureResponse signingDataResponse: SignatureResponse personalSigningResponse: SignatureResponse + PLUMESigningResponse: PLUMESignatureResponse } /** @@ -352,4 +361,59 @@ export default class SigningService extends BaseService { throw err } } + + async signPLUME( + addressOnNetwork: AddressOnNetwork, + dataToSign: string, + accountSigner: AccountSigner, + version?: number, + ): Promise { + try { + let plume: PLUMESigningResponse + switch (accountSigner.type) { + case "ledger": + throw new Error( + "Ledger does not currently support generating PLUMEs.", + ) + break + case "private-key": + case "keyring": + plume = await this.internalSignerService.generatePLUME({ + message: dataToSign, + account: addressOnNetwork.address, + version, + }) + break + case "read-only": + throw new Error("Read-only signers cannot sign.") + default: + assertUnreachable(accountSigner) + } + + this.emitter.emit("PLUMESigningResponse", { + type: "success-data", + plume, + }) + return plume + } catch (err) { + if (err instanceof TransportStatusError) { + const transportError = err as Error & { statusCode: number } + switch (transportError.statusCode) { + case StatusCodes.CONDITIONS_OF_USE_NOT_SATISFIED: + this.emitter.emit("PLUMESigningResponse", { + type: "error", + reason: "userRejected", + }) + throw err + default: + break + } + } + this.emitter.emit("PLUMESigningResponse", { + type: "error", + reason: "genericError", + }) + throw err + } + } } diff --git a/background/utils/signing.ts b/background/utils/signing.ts index b29484ddff..cb52ee5087 100644 --- a/background/utils/signing.ts +++ b/background/utils/signing.ts @@ -72,6 +72,21 @@ export type EIP2612TypedData = { // FIXME Add network info. } +export type PLUMESigningRequest = { + account: AddressOnNetwork + rawSigningData: string + plumeVersion: number +} + +export type PLUMESigningResponse = { + plume: HexString + c: HexString + s: HexString + publicKey: HexString + gPowR: HexString + hashMPKPowR: HexString +} + const checkEIP4361: (message: string) => EIP4361Data | undefined = ( message, ) => { diff --git a/provider-bridge-shared/runtime-typechecks.ts b/provider-bridge-shared/runtime-typechecks.ts index 5ac56bb55d..93baba1224 100644 --- a/provider-bridge-shared/runtime-typechecks.ts +++ b/provider-bridge-shared/runtime-typechecks.ts @@ -67,6 +67,7 @@ export const AllowedQueryParamPage = { dappPermission: "/dapp-permission", signData: "/sign-data", personalSignData: "/personal-sign", + SignPLUMEData: "/sign-plume", } as const export type AllowedQueryParamPageType = diff --git a/ui/components/SignData/EIP7524Info.tsx b/ui/components/SignData/EIP7524Info.tsx new file mode 100644 index 0000000000..e17868bba4 --- /dev/null +++ b/ui/components/SignData/EIP7524Info.tsx @@ -0,0 +1,45 @@ +import React, { ReactElement } from "react" +import { MessageSigningRequest } from "@tallyho/tally-background/utils/signing" +import { useTranslation } from "react-i18next" + +type Props = { + signingData: MessageSigningRequest["signingData"] +} + +export default function EIP7524Info({ signingData }: Props): ReactElement { + const { t } = useTranslation("translation", { keyPrefix: "signing" }) + + return ( + <> +
+
{t("message")}
+
{`${signingData}`}
+
+ + + ) +} diff --git a/ui/components/Signing/SignatureDetails/DataSignatureDetails/PLUMESignatureDetails.tsx b/ui/components/Signing/SignatureDetails/DataSignatureDetails/PLUMESignatureDetails.tsx new file mode 100644 index 0000000000..2ca7763d7b --- /dev/null +++ b/ui/components/Signing/SignatureDetails/DataSignatureDetails/PLUMESignatureDetails.tsx @@ -0,0 +1,21 @@ +import { PLUMESigningRequest } from "@tallyho/tally-background/utils/signing" +import React, { ReactElement } from "react" +import EIP7524Info from "../../../SignData/EIP7524Info" +import DataSignatureDetails from "." + +export type PLUMESignatureDetailsProps = { + PLUMERequest: PLUMESigningRequest +} + +export default function PLUMESignatureDetails({ + PLUMERequest, +}: PLUMESignatureDetailsProps): ReactElement { + return ( + + + + ) +} diff --git a/ui/components/Signing/SignatureDetails/DataSignatureDetails/index.tsx b/ui/components/Signing/SignatureDetails/DataSignatureDetails/index.tsx index 34d8e75212..51b3c5616c 100644 --- a/ui/components/Signing/SignatureDetails/DataSignatureDetails/index.tsx +++ b/ui/components/Signing/SignatureDetails/DataSignatureDetails/index.tsx @@ -6,11 +6,13 @@ type DataSignatureDetailsProps = { requestingSource?: string | undefined excludeTitle?: boolean children: ReactNode + alternativeTitle?: string } export default function DataSignatureDetails({ requestingSource, excludeTitle = false, + alternativeTitle = undefined, children, }: DataSignatureDetailsProps): ReactElement { const { t } = useTranslation("translation", { keyPrefix: "signing" }) @@ -19,9 +21,12 @@ export default function DataSignatureDetails({
- {!excludeTitle && ( + {!excludeTitle && !alternativeTitle && (
{t("signatureRequired")}
)} + {alternativeTitle && ( +
{alternativeTitle}
+ )}
diff --git a/ui/components/Signing/SignatureDetails/index.tsx b/ui/components/Signing/SignatureDetails/index.tsx index ec390eaa08..4ccd634d3b 100644 --- a/ui/components/Signing/SignatureDetails/index.tsx +++ b/ui/components/Signing/SignatureDetails/index.tsx @@ -9,6 +9,7 @@ import { SignOperation, SignOperationType, signTypedData, + signPLUME, } from "@tallyho/tally-background/redux-slices/signing" import { rejectTransactionSignature, @@ -16,6 +17,7 @@ import { } from "@tallyho/tally-background/redux-slices/transaction-construction" import { MessageSigningRequest, + PLUMESigningRequest, SignTypedDataRequest, } from "@tallyho/tally-background/utils/signing" import { AccountSigner } from "@tallyho/tally-background/services/signing" @@ -24,6 +26,7 @@ import { AnyAction } from "redux" import TransactionSignatureDetails from "./TransactionSignatureDetails" import MessageDataSignatureDetails from "./DataSignatureDetails/MessageDataSignatureDetails" import TypedDataSignatureDetails from "./DataSignatureDetails/TypedDataSignatureDetails" +import PLUMESignatureDetails from "./DataSignatureDetails/PLUMESignatureDetails" /** * Details regarding a signature request, resolved for a signer ahead of time @@ -105,6 +108,20 @@ export function resolveTypedDataSignatureDetails({ } } +export function resolvePLUMESignatureDetails({ + request, + accountSigner, +}: SignOperation): ResolvedSignatureDetails { + return { + signer: accountSigner, + signingAddress: request.account, + signingActionLabelI18nKey: "signTransaction.confirmButtonLabel", + renderedSigningData: , + signActionCreator: () => signPLUME({ request, accountSigner }), + rejectActionCreator: rejectDataSignature, + } +} + // Takes a signing request and resolves the signer that should be used to sign // it and the details of signing data for user presentation. export function resolveSignatureDetails({ @@ -117,6 +134,9 @@ export function resolveSignatureDetails({ if ("typedData" in request) { return resolveTypedDataSignatureDetails({ request, accountSigner }) } + if ("plumeVersion" in request) { + return resolvePLUMESignatureDetails({ request, accountSigner }) + } return resolveTransactionSignatureDetails({ request, accountSigner }) } diff --git a/ui/components/Signing/Signer/SignerLedger/SignerLedgerSigning/index.tsx b/ui/components/Signing/Signer/SignerLedger/SignerLedgerSigning/index.tsx index 3a1f9b4591..4dc219d7e3 100644 --- a/ui/components/Signing/Signer/SignerLedger/SignerLedgerSigning/index.tsx +++ b/ui/components/Signing/Signer/SignerLedger/SignerLedgerSigning/index.tsx @@ -168,6 +168,10 @@ export default function SignerLedgerSigning({ return } + if ("plumeVersion" in request) { + throw new Error("PLUME signing is not supported by Ledger.") + } + return ( +} diff --git a/ui/routes/routes.tsx b/ui/routes/routes.tsx index 47c34956ae..be3f0e6161 100644 --- a/ui/routes/routes.tsx +++ b/ui/routes/routes.tsx @@ -3,6 +3,7 @@ import Wallet from "../pages/Wallet" import SignTransaction from "../pages/SignTransaction" import SignData from "../pages/SignData" import PersonalSign from "../pages/PersonalSign" +import PLUMESign from "../pages/PLUMESign" import Overview from "../pages/Overview" import SingleAsset from "../pages/SingleAsset" import Earn from "../pages/Earn" @@ -86,6 +87,13 @@ const pageList: PageList[] = [ hasTopBar: false, persistOnClose: true, }, + { + path: "/sign-plume", + Component: PLUMESign, + hasTabBar: false, + hasTopBar: false, + persistOnClose: true, + }, { path: "/portfolio", Component: Overview, diff --git a/yarn.lock b/yarn.lock index 5b582093c6..ca7ae5919e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1626,6 +1626,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -3241,6 +3246,11 @@ semver "^7.3.5" tar "^6.1.11" +"@noble/secp256k1@^1.7.0": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -5693,6 +5703,13 @@ ajv@^8.0.0, ajv@^8.6.2: require-from-string "^2.0.2" uri-js "^4.2.2" +amcl-js@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/amcl-js/-/amcl-js-3.1.0.tgz#96ed3c7b18f91bf9ac991843ec9dff45a1ced744" + integrity sha512-36dd2w+cqK2NPww9w3ATPqbUeFgDHyTgeyXAk9jd7PXQh3uqSIdjiVCiqijIyAMDCzlkXdotkr8Sv0nmd1/UMQ== + dependencies: + prompt "^1.0.0" + anser@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/anser/-/anser-2.1.1.tgz#8afae28d345424c82de89cc0e4d1348eb0c5af7c" @@ -6034,6 +6051,11 @@ async-stream-emitter@^4.0.0: dependencies: stream-demux "^8.1.0" +async@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" @@ -6041,6 +6063,13 @@ async@^2.6.2: dependencies: lodash "^4.17.14" +async@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + async@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8" @@ -6984,6 +7013,11 @@ colorette@^1.2.1, colorette@^1.3.0: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af" integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w== +colors@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== + colors@^1.1.2: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -7360,6 +7394,11 @@ custom-event@1.0.0: resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.0.tgz#2e4628be19dc4b214b5c02630c5971e811618062" integrity sha512-6nOXX3UitrmdvSJWoVR2dlzhbX5bEUqmqsMUyx1ypCLZkHHkcuYtdpW3p94RGvcFkTV7DkLo+Ilbwnlwi8L+jw== +cycle@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" + integrity sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA== + "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: version "3.2.4" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" @@ -8979,6 +9018,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= +eyes@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + fake-indexeddb@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-4.0.0.tgz#1dfb2023a3be175e35a6d84975218b432041934d" @@ -10436,7 +10480,7 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isstream@~0.1.2: +isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= @@ -10945,6 +10989,11 @@ jest@^29.5.0: import-local "^3.0.2" jest-cli "^29.5.0" +js-sha256@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.10.1.tgz#b40104ba1368e823fdd5f41b66b104b15a0da60d" + integrity sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw== + js-sha3@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" @@ -13023,6 +13072,15 @@ playwright-core@1.31.0: resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.31.0.tgz#dbd184771535e76c6743ef5c082def5564f07e85" integrity sha512-/KquBjS5DcASCh8cGeNVHuC0kyb7c9plKTwaKxgOGtxT7+DZO2fjmFvPDBSXslEIK5CeOO/2kk5rOCktFXKEdA== +plume-sig@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/plume-sig/-/plume-sig-2.0.2.tgz#b3cf862a41e8a9fade94dd677aa6274b6235180b" + integrity sha512-z6wQNVb5J7j09nLJSYrwKV4QfddXPWGHM+dCdxggK8CD5p3//7Dw6fGSs7Z8DkMj16a/Sn0RDK0AkS4d/84qtA== + dependencies: + "@noble/secp256k1" "^1.7.0" + amcl-js "^3.1.0" + js-sha256 "^0.10.1" + portfinder@^1.0.17: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -13144,6 +13202,17 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" +prompt@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.3.0.tgz#b1f6d47cb1b6beed4f0660b470f5d3ec157ad7ce" + integrity sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg== + dependencies: + "@colors/colors" "1.5.0" + async "3.2.3" + read "1.0.x" + revalidator "0.1.x" + winston "2.x" + prompts@^2.0.1: version "2.4.1" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" @@ -13597,7 +13666,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -read@1, read@^1.0.7, read@~1.0.1, read@~1.0.7: +read@1, read@1.0.x, 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 sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= @@ -13932,6 +14001,11 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +revalidator@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" + integrity sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg== + rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -14601,6 +14675,11 @@ ssri@^8.0.0, ssri@^8.0.1: dependencies: minipass "^3.1.1" +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -15924,6 +16003,18 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== +winston@2.x: + version "2.4.7" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.7.tgz#5791fe08ea7e90db090f1cb31ef98f32531062f1" + integrity sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg== + dependencies: + async "^2.6.4" + colors "1.0.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + stack-trace "0.0.x" + word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"