UNPKG

@reclaimprotocol/js-sdk

Version:

Designed to request proofs from the Reclaim protocol and manage the flow of claims and witness interactions.

1,593 lines (1,577 loc) 52.3 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // package.json var require_package = __commonJS({ "package.json"(exports2, module2) { module2.exports = { name: "@reclaimprotocol/js-sdk", version: "2.3.3", description: "Designed to request proofs from the Reclaim protocol and manage the flow of claims and witness interactions.", main: "dist/index.js", types: "dist/index.d.ts", keywords: [ "reclaim", "protocol", "blockchain", "proof", "verification", "identity", "claims", "witness", "sdk", "javascript", "typescript", "decentralized", "web3" ], files: [ "dist" ], tsup: { entry: [ "src/index.ts" ], splitting: false, sourcemap: true, clean: true }, scripts: { build: "sh scripts/build.sh", release: "release-it", test: 'echo "Error: no test specified" && exit 1', commitlint: "commitlint --edit" }, repository: { type: "git", url: "https://github.com/reclaimprotocol/reclaim-js-sdk" }, author: "ali <ali@creatoros.co>", license: "See License in <https://github.com/reclaimprotocol/.github/blob/main/LICENSE>", bugs: { url: "https://github.com/reclaimprotocol/reclaim-js-sdk/issues" }, homepage: "https://github.com/reclaimprotocol/reclaim-js-sdk/", publishConfig: { registry: "https://registry.npmjs.org/", access: "public" }, "release-it": { git: { commitMessage: "chore: release ${version}", tagName: "v${version}" }, npm: { publish: true, tag: "latest" }, github: { release: true }, plugins: { "@release-it/conventional-changelog": { preset: "angular" } } }, devDependencies: { "@bconnorwhite/bob": "^2.9.5", "@commitlint/cli": "^17.7.1", "@commitlint/config-conventional": "^17.7.0", "@release-it/conventional-changelog": "^5.0.0", "@types/qs": "^6.9.11", "@types/url-parse": "^1.4.11", "@types/uuid": "^9.0.7", "release-it": "^15.0.0", tsup: "^8.0.1", typescript: "^5.3.3" }, dependencies: { canonicalize: "^2.0.0", ethers: "^6.9.1", qs: "^6.11.2", "url-parse": "^1.5.10", uuid: "^9.0.1" } }; } }); // src/index.ts var index_exports = {}; __export(index_exports, { ReclaimProofRequest: () => ReclaimProofRequest, transformForOnchain: () => transformForOnchain, verifyProof: () => verifyProof }); module.exports = __toCommonJS(index_exports); // src/witness.ts var import_ethers = require("ethers"); function fetchWitnessListForClaim({ witnesses, witnessesRequiredForClaim, epoch }, params, timestampS) { const identifier = typeof params === "string" ? params : getIdentifierFromClaimInfo(params); const completeInput = [ identifier, epoch.toString(), witnessesRequiredForClaim.toString(), timestampS.toString() ].join("\n"); const completeHashStr = import_ethers.ethers.keccak256(strToUint8Array(completeInput)); const completeHash = import_ethers.ethers.getBytes(completeHashStr); const completeHashView = uint8ArrayToDataView(completeHash); const witnessesLeft = [...witnesses]; const selectedWitnesses = []; let byteOffset = 0; for (let i = 0; i < witnessesRequiredForClaim; i++) { const randomSeed = completeHashView.getUint32(byteOffset); const witnessIndex = randomSeed % witnessesLeft.length; const witness = witnessesLeft[witnessIndex]; selectedWitnesses.push(witness); witnessesLeft[witnessIndex] = witnessesLeft[witnessesLeft.length - 1]; witnessesLeft.pop(); byteOffset = (byteOffset + 4) % completeHash.length; } return selectedWitnesses; } function getIdentifierFromClaimInfo(info) { const str = `${info.provider} ${info.parameters} ${info.context || ""}`; return import_ethers.ethers.keccak256(strToUint8Array(str)).toLowerCase(); } function strToUint8Array(str) { return new TextEncoder().encode(str); } function uint8ArrayToDataView(arr) { return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); } function createSignDataForClaim(data) { const identifier = "identifier" in data ? data.identifier : getIdentifierFromClaimInfo(data); const lines = [ identifier, data.owner.toLowerCase(), data.timestampS.toString(), data.epoch.toString() ]; return lines.join("\n"); } // src/Reclaim.ts var import_ethers6 = require("ethers"); var import_canonicalize2 = __toESM(require("canonicalize")); // src/utils/errors.ts function createErrorClass(name) { return class extends Error { constructor(message, innerError) { const fullMessage = innerError ? `${message || ""} caused by ${innerError.name}: ${innerError.message}` : message; super(fullMessage); this.innerError = innerError; this.name = name; if (innerError) { this.stack += ` Caused by: ${innerError.stack}`; } } }; } var TimeoutError = createErrorClass("TimeoutError"); var ProofNotVerifiedError = createErrorClass("ProofNotVerifiedError"); var SessionNotStartedError = createErrorClass("SessionNotStartedError"); var ProviderNotFoundError = createErrorClass("ProviderNotFoundError"); var SignatureGeneratingError = createErrorClass("SignatureGeneratingError"); var SignatureNotFoundError = createErrorClass("SignatureNotFoundError"); var InvalidSignatureError = createErrorClass("InvalidSignatureError"); var UpdateSessionError = createErrorClass("UpdateSessionError"); var InitSessionError = createErrorClass("InitSessionError"); var ProviderFailedError = createErrorClass("ProviderFailedError"); var InvalidParamError = createErrorClass("InvalidParamError"); var ApplicationError = createErrorClass("ApplicationError"); var InitError = createErrorClass("InitError"); var BackendServerError = createErrorClass("BackendServerError"); var GetStatusUrlError = createErrorClass("GetStatusUrlError"); var NoProviderParamsError = createErrorClass("NoProviderParamsError"); var SetParamsError = createErrorClass("SetParamsError"); var AddContextError = createErrorClass("AddContextError"); var SetSignatureError = createErrorClass("SetSignatureError"); var GetAppCallbackUrlError = createErrorClass("GetAppCallbackUrlError"); var StatusUrlError = createErrorClass("StatusUrlError"); var InavlidParametersError = createErrorClass("InavlidParametersError"); var ProofSubmissionFailedError = createErrorClass("ProofSubmissionFailedError"); // src/utils/logger.ts var SimpleLogger = class { constructor() { this.level = "info"; } setLevel(level) { this.level = level; } shouldLog(messageLevel) { const levels = ["error", "warn", "info", "silent"]; return levels.indexOf(this.level) >= levels.indexOf(messageLevel); } log(level, message, ...args) { if (this.shouldLog(level) && this.level !== "silent") { const logFunction = this.getLogFunction(level); console.log("current level", this.level); logFunction(`[${level.toUpperCase()}]`, message, ...args); } } getLogFunction(level) { switch (level) { case "error": return console.error; case "warn": return console.warn; case "info": return console.info; default: return () => { }; } } info(message, ...args) { this.log("info", message, ...args); } warn(message, ...args) { this.log("warn", message, ...args); } error(message, ...args) { this.log("error", message, ...args); } }; var logger = new SimpleLogger(); function setLogLevel(level) { logger.setLevel(level); } var logger_default = { logger, setLogLevel }; // src/utils/helper.ts var logger2 = logger_default.logger; function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function replaceAll(str, find, replace) { if (find === "") return str; return str.replace(new RegExp(escapeRegExp(find), "g"), replace); } function scheduleIntervalEndingTask(sessionId, intervals, onFailureCallback, timeout = 1e3 * 60 * 10) { setTimeout(() => { if (intervals.has(sessionId)) { const message = "Interval ended without receiving proofs"; onFailureCallback(new TimeoutError(message)); logger2.info(message); clearInterval(intervals.get(sessionId)); intervals.delete(sessionId); } }, timeout); } // src/utils/constants.ts var BACKEND_BASE_URL = "https://api.reclaimprotocol.org"; function setBackendBaseUrl(url) { BACKEND_BASE_URL = url; } var constants = { // Default callback URL for Reclaim protocol get DEFAULT_RECLAIM_CALLBACK_URL() { return `${BACKEND_BASE_URL}/api/sdk/callback?callbackId=`; }, // Default status URL for Reclaim sessions get DEFAULT_RECLAIM_STATUS_URL() { return `${BACKEND_BASE_URL}/api/sdk/session/`; }, // URL for sharing Reclaim templates RECLAIM_SHARE_URL: "https://share.reclaimprotocol.org/verifier/?template=" }; // src/utils/validationUtils.ts var import_ethers2 = require("ethers"); var import_canonicalize = __toESM(require("canonicalize")); var logger3 = logger_default.logger; function validateFunctionParams(params, functionName) { params.forEach(({ input, paramName, isString }) => { if (input == null) { logger3.info(`Validation failed: ${paramName} in ${functionName} is null or undefined`); throw new InvalidParamError(`${paramName} passed to ${functionName} must not be null or undefined.`); } if (isString && typeof input !== "string") { logger3.info(`Validation failed: ${paramName} in ${functionName} is not a string`); throw new InvalidParamError(`${paramName} passed to ${functionName} must be a string.`); } if (isString && input.trim() === "") { logger3.info(`Validation failed: ${paramName} in ${functionName} is an empty string`); throw new InvalidParamError(`${paramName} passed to ${functionName} must not be an empty string.`); } }); } function validateParameters(parameters) { try { if (typeof parameters !== "object" || parameters === null) { logger3.info(`Parameters validation failed: Provided parameters is not an object`); throw new InavlidParametersError(`The provided parameters is not an object`); } for (const [key, value] of Object.entries(parameters)) { if (typeof key !== "string" || typeof value !== "string") { logger3.info(`Parameters validation failed: Provided parameters is not an object of key value pairs of string and string`); throw new InavlidParametersError(`The provided parameters is not an object of key value pairs of string and string`); } } } catch (e) { logger3.info(`Parameters validation failed: ${e.message}`); throw new InavlidParametersError(`Invalid parameters passed to validateParameters.`, e); } } function validateURL(url, functionName) { try { new URL(url); } catch (e) { logger3.info(`URL validation failed for ${url} in ${functionName}: ${e.message}`); throw new InvalidParamError(`Invalid URL format ${url} passed to ${functionName}.`, e); } } function validateSignature(providerId, signature, applicationId, timestamp) { try { logger3.info(`Starting signature validation for providerId: ${providerId}, applicationId: ${applicationId}, timestamp: ${timestamp}`); const message = (0, import_canonicalize.default)({ providerId, timestamp }); if (!message) { logger3.info("Failed to canonicalize message for signature validation"); throw new Error("Failed to canonicalize message"); } const messageHash = import_ethers2.ethers.keccak256(new TextEncoder().encode(message)); let appId = import_ethers2.ethers.verifyMessage( import_ethers2.ethers.getBytes(messageHash), import_ethers2.ethers.hexlify(signature) ).toLowerCase(); if (import_ethers2.ethers.getAddress(appId) !== import_ethers2.ethers.getAddress(applicationId)) { logger3.info(`Signature validation failed: Mismatch between derived appId (${appId}) and provided applicationId (${applicationId})`); throw new InvalidSignatureError(`Signature does not match the application id: ${appId}`); } logger3.info(`Signature validated successfully for applicationId: ${applicationId}`); } catch (err) { logger3.info(`Signature validation failed: ${err.message}`); if (err instanceof InvalidSignatureError) { throw err; } throw new InvalidSignatureError(`Failed to validate signature: ${err.message}`); } } function validateContext(context) { if (!context.contextAddress) { logger3.info(`Context validation failed: Provided context address in context is not valid`); throw new InvalidParamError(`The provided context address in context is not valid`); } if (!context.contextMessage) { logger3.info(`Context validation failed: Provided context message in context is not valid`); throw new InvalidParamError(`The provided context message in context is not valid`); } validateFunctionParams([ { input: context.contextAddress, paramName: "contextAddress", isString: true }, { input: context.contextMessage, paramName: "contextMessage", isString: true } ], "validateContext"); } // src/utils/sessionUtils.ts var logger4 = logger_default.logger; function initSession(providerId, appId, timestamp, signature) { return __async(this, null, function* () { logger4.info(`Initializing session for providerId: ${providerId}, appId: ${appId}`); try { const response = yield fetch(`${BACKEND_BASE_URL}/api/sdk/init/session/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ providerId, appId, timestamp, signature }) }); const res = yield response.json(); if (!response.ok) { logger4.info(`Session initialization failed: ${res.message || "Unknown error"}`); throw new InitSessionError(res.message || `Error initializing session with providerId: ${providerId}`); } return res; } catch (err) { logger4.info(`Failed to initialize session for providerId: ${providerId}, appId: ${appId}`, err); throw err; } }); } function updateSession(sessionId, status) { return __async(this, null, function* () { logger4.info(`Updating session status for sessionId: ${sessionId}, new status: ${status}`); validateFunctionParams( [{ input: sessionId, paramName: "sessionId", isString: true }], "updateSession" ); try { const response = yield fetch(`${BACKEND_BASE_URL}/api/sdk/update/session/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sessionId, status }) }); const res = yield response.json(); if (!response.ok) { const errorMessage = `Error updating session with sessionId: ${sessionId}. Status Code: ${response.status}`; logger4.info(errorMessage, res); throw new UpdateSessionError(errorMessage); } logger4.info(`Session status updated successfully for sessionId: ${sessionId}`); return res; } catch (err) { const errorMessage = `Failed to update session with sessionId: ${sessionId}`; logger4.info(errorMessage, err); throw new UpdateSessionError(`Error updating session with sessionId: ${sessionId}`); } }); } function fetchStatusUrl(sessionId) { return __async(this, null, function* () { validateFunctionParams( [{ input: sessionId, paramName: "sessionId", isString: true }], "fetchStatusUrl" ); try { const response = yield fetch(`${constants.DEFAULT_RECLAIM_STATUS_URL}${sessionId}`, { method: "GET", headers: { "Content-Type": "application/json" } }); const res = yield response.json(); if (!response.ok) { const errorMessage = `Error fetching status URL for sessionId: ${sessionId}. Status Code: ${response.status}`; logger4.info(errorMessage, res); throw new StatusUrlError(errorMessage); } return res; } catch (err) { const errorMessage = `Failed to fetch status URL for sessionId: ${sessionId}`; logger4.info(errorMessage, err); throw new StatusUrlError(`Error fetching status URL for sessionId: ${sessionId}`); } }); } // src/utils/proofUtils.ts var import_ethers5 = require("ethers"); // src/contract-types/contracts/factories/Reclaim__factory.ts var import_ethers3 = require("ethers"); var _abi = [ { anonymous: false, inputs: [ { indexed: false, internalType: "address", name: "previousAdmin", type: "address" }, { indexed: false, internalType: "address", name: "newAdmin", type: "address" } ], name: "AdminChanged", type: "event" }, { anonymous: false, inputs: [ { indexed: true, internalType: "address", name: "beacon", type: "address" } ], name: "BeaconUpgraded", type: "event" }, { anonymous: false, inputs: [ { components: [ { internalType: "uint32", name: "id", type: "uint32" }, { internalType: "uint32", name: "timestampStart", type: "uint32" }, { internalType: "uint32", name: "timestampEnd", type: "uint32" }, { components: [ { internalType: "address", name: "addr", type: "address" }, { internalType: "string", name: "host", type: "string" } ], internalType: "struct Reclaim.Witness[]", name: "witnesses", type: "tuple[]" }, { internalType: "uint8", name: "minimumWitnessesForClaimCreation", type: "uint8" } ], indexed: false, internalType: "struct Reclaim.Epoch", name: "epoch", type: "tuple" } ], name: "EpochAdded", type: "event" }, { anonymous: false, inputs: [ { indexed: false, internalType: "uint8", name: "version", type: "uint8" } ], name: "Initialized", 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: "address", name: "implementation", type: "address" } ], name: "Upgraded", type: "event" }, { inputs: [ { internalType: "address", name: "witnessAddress", type: "address" }, { internalType: "string", name: "host", type: "string" } ], name: "addAsWitness", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [], name: "addNewEpoch", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [ { internalType: "uint32", name: "epochNum", type: "uint32" }, { components: [ { internalType: "string", name: "provider", type: "string" }, { internalType: "string", name: "parameters", type: "string" }, { internalType: "string", name: "context", type: "string" } ], internalType: "struct Claims.ClaimInfo", name: "claimInfo", type: "tuple" }, { components: [ { internalType: "bytes32", name: "identifier", type: "bytes32" }, { internalType: "address", name: "owner", type: "address" }, { internalType: "uint32", name: "timestampS", type: "uint32" }, { internalType: "uint256", name: "epoch", type: "uint256" } ], internalType: "struct Claims.CompleteClaimData", name: "claimData", type: "tuple" }, { internalType: "bytes[]", name: "signatures", type: "bytes[]" } ], name: "assertValidEpochAndSignedClaim", outputs: [], stateMutability: "view", type: "function" }, { inputs: [], name: "currentEpoch", outputs: [ { internalType: "uint32", name: "", type: "uint32" } ], stateMutability: "view", type: "function" }, { inputs: [], name: "epochDurationS", outputs: [ { internalType: "uint32", name: "", type: "uint32" } ], stateMutability: "view", type: "function" }, { inputs: [ { internalType: "uint256", name: "", type: "uint256" } ], name: "epochs", outputs: [ { internalType: "uint32", name: "id", type: "uint32" }, { internalType: "uint32", name: "timestampStart", type: "uint32" }, { internalType: "uint32", name: "timestampEnd", type: "uint32" }, { internalType: "uint8", name: "minimumWitnessesForClaimCreation", type: "uint8" } ], stateMutability: "view", type: "function" }, { inputs: [ { internalType: "uint32", name: "epoch", type: "uint32" } ], name: "fetchEpoch", outputs: [ { components: [ { internalType: "uint32", name: "id", type: "uint32" }, { internalType: "uint32", name: "timestampStart", type: "uint32" }, { internalType: "uint32", name: "timestampEnd", type: "uint32" }, { components: [ { internalType: "address", name: "addr", type: "address" }, { internalType: "string", name: "host", type: "string" } ], internalType: "struct Reclaim.Witness[]", name: "witnesses", type: "tuple[]" }, { internalType: "uint8", name: "minimumWitnessesForClaimCreation", type: "uint8" } ], internalType: "struct Reclaim.Epoch", name: "", type: "tuple" } ], stateMutability: "view", type: "function" }, { inputs: [ { internalType: "uint32", name: "epoch", type: "uint32" }, { internalType: "bytes32", name: "identifier", type: "bytes32" }, { internalType: "uint32", name: "timestampS", type: "uint32" } ], name: "fetchWitnessesForClaim", outputs: [ { components: [ { internalType: "address", name: "addr", type: "address" }, { internalType: "string", name: "host", type: "string" } ], internalType: "struct Reclaim.Witness[]", name: "", type: "tuple[]" } ], stateMutability: "view", type: "function" }, { inputs: [], name: "initialize", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [], name: "minimumWitnessesForClaimCreation", outputs: [ { internalType: "uint8", name: "", type: "uint8" } ], stateMutability: "view", type: "function" }, { inputs: [], name: "owner", outputs: [ { internalType: "address", name: "", type: "address" } ], stateMutability: "view", type: "function" }, { inputs: [], name: "proxiableUUID", outputs: [ { internalType: "bytes32", name: "", type: "bytes32" } ], stateMutability: "view", type: "function" }, { inputs: [ { internalType: "address", name: "witnessAddress", type: "address" } ], name: "removeAsWitness", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [], name: "renounceOwnership", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [ { internalType: "address", name: "newOwner", type: "address" } ], name: "transferOwnership", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [ { internalType: "address", name: "addr", type: "address" }, { internalType: "bool", name: "isWhitelisted", type: "bool" } ], name: "updateWitnessWhitelist", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [ { internalType: "address", name: "newImplementation", type: "address" } ], name: "upgradeTo", outputs: [], stateMutability: "nonpayable", type: "function" }, { inputs: [ { internalType: "address", name: "newImplementation", type: "address" }, { internalType: "bytes", name: "data", type: "bytes" } ], name: "upgradeToAndCall", outputs: [], stateMutability: "payable", type: "function" }, { inputs: [ { internalType: "uint256", name: "", type: "uint256" } ], name: "witnesses", outputs: [ { internalType: "address", name: "addr", type: "address" }, { internalType: "string", name: "host", type: "string" } ], stateMutability: "view", type: "function" } ]; var Reclaim__factory = class { static connect(address, signerOrProvider) { return new import_ethers3.Contract(address, _abi, signerOrProvider); } }; Reclaim__factory.abi = _abi; // src/contract-types/config.json var config_default = { "0x1a4": { chainName: "opt-goerli", address: "0xF93F605142Fb1Efad7Aa58253dDffF67775b4520", rpcUrl: "https://opt-goerli.g.alchemy.com/v2/rksDkSUXd2dyk2ANy_zzODknx_AAokui" }, "0xaa37dc": { chainName: "opt-sepolia", address: "0x6D0f81BDA11995f25921aAd5B43359630E65Ca96", rpcUrl: "https://opt-sepolia.g.alchemy.com/v2/aO1-SfG4oFRLyAiLREqzyAUu0HTCwHgs" } }; // src/smart-contract.ts var import_ethers4 = require("ethers"); var DEFAULT_CHAIN_ID = 11155420; function makeBeacon(chainId) { chainId = chainId || DEFAULT_CHAIN_ID; const contract = getContract(chainId); if (contract) { let _a; return makeBeaconCacheable({ getState(epochId) { return __async(this, null, function* () { const epoch = yield contract.fetchEpoch(epochId || 0); if (!epoch.id) { throw new Error(`Invalid epoch ID: ${epochId}`); } return { epoch: epoch.id, witnesses: epoch.witnesses.map((w) => ({ id: w.addr.toLowerCase(), url: w.host })), witnessesRequiredForClaim: epoch.minimumWitnessesForClaimCreation, nextEpochTimestampS: epoch.timestampEnd }; }); } }); } else { return void 0; } } function makeBeaconCacheable(beacon) { const cache = {}; return __spreadProps(__spreadValues({}, beacon), { getState(epochId) { return __async(this, null, function* () { if (!epochId) { const state = yield beacon.getState(); return state; } const key = epochId; if (!cache[key]) { cache[key] = beacon.getState(epochId); } return cache[key]; }); } }); } var existingContractsMap = {}; function getContract(chainId) { const chainKey = `0x${chainId.toString(16)}`; if (!existingContractsMap[chainKey]) { const contractData = config_default[chainKey]; if (!contractData) { throw new Error(`Unsupported chain: "${chainKey}"`); } const rpcProvider = new import_ethers4.ethers.JsonRpcProvider(contractData.rpcUrl); existingContractsMap[chainKey] = Reclaim__factory.connect( contractData.address, rpcProvider ); } return existingContractsMap[chainKey]; } // src/utils/proofUtils.ts var logger5 = logger_default.logger; function getShortenedUrl(url) { return __async(this, null, function* () { logger5.info(`Attempting to shorten URL: ${url}`); try { validateURL(url, "getShortenedUrl"); const response = yield fetch(`${BACKEND_BASE_URL}/api/sdk/shortener`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ fullUrl: url }) }); const res = yield response.json(); if (!response.ok) { logger5.info(`Failed to shorten URL: ${url}, Response: ${JSON.stringify(res)}`); return url; } const shortenedVerificationUrl = res.result.shortUrl; return shortenedVerificationUrl; } catch (err) { logger5.info(`Error shortening URL: ${url}, Error: ${err}`); return url; } }); } function createLinkWithTemplateData(templateData) { return __async(this, null, function* () { let template = encodeURIComponent(JSON.stringify(templateData)); template = replaceAll(template, "(", "%28"); template = replaceAll(template, ")", "%29"); const fullLink = `${constants.RECLAIM_SHARE_URL}${template}`; try { const shortenedLink = yield getShortenedUrl(fullLink); return shortenedLink; } catch (err) { logger5.info(`Error creating link for sessionId: ${templateData.sessionId}, Error: ${err}`); return fullLink; } }); } function getWitnessesForClaim(epoch, identifier, timestampS) { return __async(this, null, function* () { const beacon = makeBeacon(); if (!beacon) { logger5.info("No beacon available for getting witnesses"); throw new Error("No beacon available"); } const state = yield beacon.getState(epoch); const witnessList = fetchWitnessListForClaim(state, identifier, timestampS); const witnesses = witnessList.map((w) => w.id.toLowerCase()); return witnesses; }); } function recoverSignersOfSignedClaim({ claim, signatures }) { const dataStr = createSignDataForClaim(__spreadValues({}, claim)); const signers = signatures.map( (signature) => import_ethers5.ethers.verifyMessage(dataStr, import_ethers5.ethers.hexlify(signature)).toLowerCase() ); return signers; } function assertValidSignedClaim(claim, expectedWitnessAddresses) { const witnessAddresses = recoverSignersOfSignedClaim(claim); const witnessesNotSeen = new Set(expectedWitnessAddresses); for (const witness of witnessAddresses) { if (witnessesNotSeen.has(witness)) { witnessesNotSeen.delete(witness); } } if (witnessesNotSeen.size > 0) { const missingWitnesses = Array.from(witnessesNotSeen).join(", "); logger5.info(`Claim validation failed. Missing signatures from: ${missingWitnesses}`); throw new ProofNotVerifiedError( `Missing signatures from ${missingWitnesses}` ); } } // src/Reclaim.ts var logger6 = logger_default.logger; var sdkVersion = require_package().version; function verifyProof(proofOrProofs) { return __async(this, null, function* () { var _a; if (Array.isArray(proofOrProofs)) { for (const proof2 of proofOrProofs) { const isVerified = yield verifyProof(proof2); if (!isVerified) { return false; } } return true; } const proof = proofOrProofs; if (!proof.signatures.length) { throw new SignatureNotFoundError("No signatures"); } try { let witnesses = []; if (proof.witnesses.length && ((_a = proof.witnesses[0]) == null ? void 0 : _a.url) === "manual-verify") { witnesses.push(proof.witnesses[0].id); } else { witnesses = yield getWitnessesForClaim( proof.claimData.epoch, proof.identifier, proof.claimData.timestampS ); } const calculatedIdentifier = getIdentifierFromClaimInfo({ parameters: JSON.parse( (0, import_canonicalize2.default)(proof.claimData.parameters) ), provider: proof.claimData.provider, context: proof.claimData.context }); proof.identifier = replaceAll(proof.identifier, '"', ""); if (calculatedIdentifier !== proof.identifier) { throw new ProofNotVerifiedError("Identifier Mismatch"); } const signedClaim = { claim: __spreadValues({}, proof.claimData), signatures: proof.signatures.map((signature) => { return import_ethers6.ethers.getBytes(signature); }) }; assertValidSignedClaim(signedClaim, witnesses); } catch (e) { logger6.info(`Error verifying proof: ${e instanceof Error ? e.message : String(e)}`); return false; } return true; }); } function transformForOnchain(proof) { const claimInfoBuilder = /* @__PURE__ */ new Map([ ["context", proof.claimData.context], ["parameters", proof.claimData.parameters], ["provider", proof.claimData.provider] ]); const claimInfo = Object.fromEntries(claimInfoBuilder); const claimBuilder = /* @__PURE__ */ new Map([ ["epoch", proof.claimData.epoch], ["identifier", proof.claimData.identifier], ["owner", proof.claimData.owner], ["timestampS", proof.claimData.timestampS] ]); const signedClaim = { claim: Object.fromEntries(claimBuilder), signatures: proof.signatures }; return { claimInfo, signedClaim }; } var ReclaimProofRequest = class _ReclaimProofRequest { // 30 seconds timeout, can be adjusted // Private constructor constructor(applicationId, providerId, options) { this.context = { contextAddress: "0x0", contextMessage: "sample context" }; this.intervals = /* @__PURE__ */ new Map(); this.jsonProofResponse = false; this.FAILURE_TIMEOUT = 3e4; this.providerId = providerId; this.timeStamp = Date.now().toString(); this.applicationId = applicationId; this.sessionId = ""; this.parameters = {}; if (options == null ? void 0 : options.log) { logger_default.setLogLevel("info"); } else { logger_default.setLogLevel("silent"); } if (options == null ? void 0 : options.envUrl) { setBackendBaseUrl(options.envUrl); } this.options = options; this.sdkVersion = "js-" + sdkVersion; logger6.info(`Initializing client with applicationId: ${this.applicationId}`); } // Static initialization methods static init(applicationId, appSecret, providerId, options) { return __async(this, null, function* () { try { validateFunctionParams([ { paramName: "applicationId", input: applicationId, isString: true }, { paramName: "providerId", input: providerId, isString: true }, { paramName: "appSecret", input: appSecret, isString: true } ], "the constructor"); if (options) { if (options.acceptAiProviders) { validateFunctionParams([ { paramName: "acceptAiProviders", input: options.acceptAiProviders } ], "the constructor"); } if (options.log) { validateFunctionParams([ { paramName: "log", input: options.log } ], "the constructor"); } if (options.useAppClip) { validateFunctionParams([ { paramName: "useAppClip", input: options.useAppClip } ], "the constructor"); } if (options.device) { validateFunctionParams([ { paramName: "device", input: options.device, isString: true } ], "the constructor"); } if (options.envUrl) { validateFunctionParams([ { paramName: "envUrl", input: options.envUrl, isString: true } ], "the constructor"); } } const proofRequestInstance = new _ReclaimProofRequest(applicationId, providerId, options); const signature = yield proofRequestInstance.generateSignature(appSecret); proofRequestInstance.setSignature(signature); const data = yield initSession(providerId, applicationId, proofRequestInstance.timeStamp, signature); proofRequestInstance.sessionId = data.sessionId; return proofRequestInstance; } catch (error) { logger6.info("Failed to initialize ReclaimProofRequest", error); throw new InitError("Failed to initialize ReclaimProofRequest", error); } }); } static fromJsonString(jsonString) { return __async(this, null, function* () { try { const { applicationId, providerId, sessionId, context, parameters, signature, redirectUrl, timeStamp, appCallbackUrl, options, sdkVersion: sdkVersion2, jsonProofResponse } = JSON.parse(jsonString); validateFunctionParams([ { input: applicationId, paramName: "applicationId", isString: true }, { input: providerId, paramName: "providerId", isString: true }, { input: signature, paramName: "signature", isString: true }, { input: sessionId, paramName: "sessionId", isString: true }, { input: timeStamp, paramName: "timeStamp", isString: true }, { input: sdkVersion2, paramName: "sdkVersion", isString: true } ], "fromJsonString"); if (redirectUrl) { validateURL(redirectUrl, "fromJsonString"); } if (appCallbackUrl) { validateURL(appCallbackUrl, "fromJsonString"); } if (context) { validateContext(context); } if (parameters) { validateParameters(parameters); } if (jsonProofResponse !== void 0) { validateFunctionParams([ { input: jsonProofResponse, paramName: "jsonProofResponse" } ], "fromJsonString"); } const proofRequestInstance = new _ReclaimProofRequest(applicationId, providerId, options); proofRequestInstance.sessionId = sessionId; proofRequestInstance.context = context; proofRequestInstance.parameters = parameters; proofRequestInstance.appCallbackUrl = appCallbackUrl; proofRequestInstance.redirectUrl = redirectUrl; proofRequestInstance.timeStamp = timeStamp; proofRequestInstance.signature = signature; proofRequestInstance.sdkVersion = sdkVersion2; return proofRequestInstance; } catch (error) { logger6.info("Failed to parse JSON string in fromJsonString:", error); throw new InvalidParamError("Invalid JSON string provided to fromJsonString"); } }); } // Setter methods setAppCallbackUrl(url, jsonProofResponse) { validateURL(url, "setAppCallbackUrl"); this.appCallbackUrl = url; this.jsonProofResponse = jsonProofResponse != null ? jsonProofResponse : false; } setRedirectUrl(url) { validateURL(url, "setRedirectUrl"); this.redirectUrl = url; } addContext(address, message) { try { validateFunctionParams([ { input: address, paramName: "address", isString: true }, { input: message, paramName: "message", isString: true } ], "addContext"); this.context = { contextAddress: address, contextMessage: message }; } catch (error) { logger6.info("Error adding context", error); throw new AddContextError("Error adding context", error); } } setParams(params) { try { validateParameters(params); this.parameters = __spreadValues(__spreadValues({}, this.parameters), params); } catch (error) { logger6.info("Error Setting Params:", error); throw new SetParamsError("Error setting params", error); } } // Getter methods getAppCallbackUrl() { try { validateFunctionParams([{ input: this.sessionId, paramName: "sessionId", isString: true }], "getAppCallbackUrl"); return this.appCallbackUrl || `${constants.DEFAULT_RECLAIM_CALLBACK_URL}${this.sessionId}`; } catch (error) { logger6.info("Error getting app callback url", error); throw new GetAppCallbackUrlError("Error getting app callback url", error); } } getStatusUrl() { try { validateFunctionParams([{ input: this.sessionId, paramName: "sessionId", isString: true }], "getStatusUrl"); return `${constants.DEFAULT_RECLAIM_STATUS_URL}${this.sessionId}`; } catch (error) { logger6.info("Error fetching Status Url", error); throw new GetStatusUrlError("Error fetching status url", error); } } // Private helper methods setSignature(signature) { try { validateFunctionParams([{ input: signature, paramName: "signature", isString: true }], "setSignature"); this.signature = signature; logger6.info(`Signature set successfully for applicationId: ${this.applicationId}`); } catch (error) { logger6.info("Error setting signature", error); throw new SetSignatureError("Error setting signature", error); } } generateSignature(applicationSecret) { return __async(this, null, function* () { try { const wallet = new import_ethers6.ethers.Wallet(applicationSecret); const canonicalData = (0, import_canonicalize2.default)({ providerId: this.providerId, timestamp: this.timeStamp }); if (!canonicalData) { throw new SignatureGeneratingError("Failed to canonicalize data for signing."); } const messageHash = import_ethers6.ethers.keccak256(new TextEncoder().encode(canonicalData)); return yield wallet.signMessage(import_ethers6.ethers.getBytes(messageHash)); } catch (err) { logger6.info(`Error generating proof request for applicationId: ${this.applicationId}, providerId: ${this.providerId}, signature: ${this.signature}, timeStamp: ${this.timeStamp}`, err); throw new SignatureGeneratingError(`Error generating signature for applicationSecret: ${applicationSecret}`); } }); } clearInterval() { if (this.sessionId && this.intervals.has(this.sessionId)) { clearInterval(this.intervals.get(this.sessionId)); this.intervals.delete(this.sessionId); } } // Public methods toJsonString(options) { return JSON.stringify({ applicationId: this.applicationId, providerId: this.providerId, sessionId: this.sessionId, context: this.context, appCallbackUrl: this.appCallbackUrl, parameters: this.parameters, signature: this.signature, redirectUrl: this.redirectUrl, timeStamp: this.timeStamp, options: this.options, sdkVersion: this.sdkVersion, jsonProofResponse: this.jsonProofResponse }); } getRequestUrl() { return __async(this, null, function* () { var _a, _b, _c, _d, _e; logger6.info("Creating Request Url"); if (!this.signature) { throw new SignatureNotFoundError("Signature is not set."); } try { validateSignature(this.providerId, this.signature, this.applicationId, this.timeStamp); const templateData = { sessionId: this.sessionId, providerId: this.providerId, applicationId: this.applicationId, signature: this.signature, timestamp: this.timeStamp, callbackUrl: this.getAppCallbackUrl(), context: JSON.stringify(this.context), parameters: this.parameters, redirectUrl: (_a = this.redirectUrl) != null ? _a : "", acceptAiProviders: (_c = (_b = this.options) == null ? void 0 : _b.acceptAiProviders) != null ? _c : false, sdkVersion: this.sdkVersion, jsonProofResponse: this.jsonProofResponse }; yield updateSession(this.sessionId, "SESSION_STARTED" /* SESSION_STARTED */); if ((_d = this.options) == null ? void 0 : _d.useAppClip) { let template = encodeURIComponent(JSON.stringify(templateData)); template = replaceAll(template, "(", "%28"); template = replaceAll(template, ")", "%29"); const isIos = ((_e = this.options) == null ? void 0 : _e.device) === "ios"; if (!isIos) { const instantAppUrl = `https://share.reclaimprotocol.org/verify/?template=${template}`; logger6.info("Instant App Url created successfully: " + instantAppUrl); return instantAppUrl; } else { const appClipUrl = `https://appclip.apple.com/id?p=org.reclaimprotocol.app.clip&template=${template}`; logger6.info("App Clip Url created successfully: " + appClipUrl); return appClipUrl; } } else { const link = yield createLinkWithTemplateData(templateData); logger6.info("Request Url created successfully: " + link); return link; } } catch (error) { logger6.info("Error creating Request Url:", error); throw error; } }); } startSession(_0) { return __async(this, arguments, function* ({ onSuccess, onError }) { if (!this.sessionId) { const message = "Session can't be started due to undefined value of sessionId"; logger6.info(message); throw new SessionNotStartedError(message); } logger6.info("Starting session"); const interval = setInterval(() => __async(this, null, function* () { try { const statusUrlResponse = yield fetchStatusUrl(this.sessionId); if (!statusUrlResponse.session) return; if (statusUrlResponse.session.statusV2 !== "PROOF_GENERATION