UNPKG

@radixdlt/radix-dapp-toolkit

Version:
1,651 lines (1,622 loc) 150 kB
// src/polyfills.ts import { Buffer as Buffer2 } from "buffer"; var polyfills_default = () => { if (!globalThis.Buffer) globalThis.Buffer = Buffer2; }; // src/modules/connect-button/connect-button.module.ts import { concatMap, delay, filter as filter7, finalize, first as first3, fromEvent, map as map6, merge as merge3, mergeMap as mergeMap2, of as of3, Subscription as Subscription7, switchMap as switchMap6, tap as tap4 } from "rxjs"; // src/modules/connect-button/subjects.ts import { BehaviorSubject, ReplaySubject, Subject } from "rxjs"; var ConnectButtonSubjects = (input) => ({ onConnect: new Subject(), onDisconnect: new Subject(), onUpdateSharedAccounts: new Subject(), connected: new ReplaySubject(1), requestItems: new BehaviorSubject([]), onCancelRequestItem: new Subject(), onIgnoreTransactionItem: new Subject(), accounts: new BehaviorSubject([]), onShowPopover: new Subject(), status: new BehaviorSubject("default"), loggedInTimestamp: new BehaviorSubject(""), isMobile: new BehaviorSubject(input.providers.environmentModule.isMobile()), isWalletLinked: new BehaviorSubject(false), showPopoverMenu: new BehaviorSubject(false), isExtensionAvailable: new BehaviorSubject(false), fullWidth: new BehaviorSubject(false), activeTab: new BehaviorSubject("sharing"), mode: new BehaviorSubject("light"), theme: new BehaviorSubject("radix-blue"), avatarUrl: new BehaviorSubject(""), personaLabel: new BehaviorSubject(""), personaData: new BehaviorSubject([]), dAppName: new BehaviorSubject(""), onLinkClick: new Subject() }); // src/modules/wallet-request/crypto/curve25519.ts import { x25519, ed25519 } from "@noble/curves/ed25519"; import { Buffer as Buffer3 } from "buffer"; import { err, ok } from "neverthrow"; // ../../node_modules/@noble/hashes/esm/_assert.js function number(n) { if (!Number.isSafeInteger(n) || n < 0) throw new Error(`positive integer expected, not ${n}`); } function isBytes(a) { return a instanceof Uint8Array || a != null && typeof a === "object" && a.constructor.name === "Uint8Array"; } function bytes(b, ...lengths) { if (!isBytes(b)) throw new Error("Uint8Array expected"); if (lengths.length > 0 && !lengths.includes(b.length)) throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`); } function hash(h) { if (typeof h !== "function" || typeof h.create !== "function") throw new Error("Hash should be wrapped by utils.wrapConstructor"); number(h.outputLen); number(h.blockLen); } function exists(instance, checkFinished = true) { if (instance.destroyed) throw new Error("Hash instance has been destroyed"); if (checkFinished && instance.finished) throw new Error("Hash#digest() has already been called"); } function output(out, instance) { bytes(out); const min = instance.outputLen; if (out.length < min) { throw new Error(`digestInto() expects output buffer of length at least ${min}`); } } // ../../node_modules/@noble/hashes/esm/utils.js var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength); var rotr = (word, shift) => word << 32 - shift | word >>> shift; var isLE = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68; function utf8ToBytes(str) { if (typeof str !== "string") throw new Error(`utf8ToBytes expected string, got ${typeof str}`); return new Uint8Array(new TextEncoder().encode(str)); } function toBytes(data) { if (typeof data === "string") data = utf8ToBytes(data); bytes(data); return data; } var Hash = class { // Safe version that clones internal state clone() { return this._cloneInto(); } }; var toStr = {}.toString; function wrapConstructor(hashCons) { const hashC = (msg) => hashCons().update(toBytes(msg)).digest(); const tmp = hashCons(); hashC.outputLen = tmp.outputLen; hashC.blockLen = tmp.blockLen; hashC.create = () => hashCons(); return hashC; } // ../../node_modules/@noble/hashes/esm/hmac.js var HMAC = class extends Hash { constructor(hash2, _key) { super(); this.finished = false; this.destroyed = false; hash(hash2); const key = toBytes(_key); this.iHash = hash2.create(); if (typeof this.iHash.update !== "function") throw new Error("Expected instance of class which extends utils.Hash"); this.blockLen = this.iHash.blockLen; this.outputLen = this.iHash.outputLen; const blockLen = this.blockLen; const pad = new Uint8Array(blockLen); pad.set(key.length > blockLen ? hash2.create().update(key).digest() : key); for (let i = 0; i < pad.length; i++) pad[i] ^= 54; this.iHash.update(pad); this.oHash = hash2.create(); for (let i = 0; i < pad.length; i++) pad[i] ^= 54 ^ 92; this.oHash.update(pad); pad.fill(0); } update(buf) { exists(this); this.iHash.update(buf); return this; } digestInto(out) { exists(this); bytes(out, this.outputLen); this.finished = true; this.iHash.digestInto(out); this.oHash.update(out); this.oHash.digestInto(out); this.destroy(); } digest() { const out = new Uint8Array(this.oHash.outputLen); this.digestInto(out); return out; } _cloneInto(to) { to || (to = Object.create(Object.getPrototypeOf(this), {})); const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this; to = to; to.finished = finished; to.destroyed = destroyed; to.blockLen = blockLen; to.outputLen = outputLen; to.oHash = oHash._cloneInto(to.oHash); to.iHash = iHash._cloneInto(to.iHash); return to; } destroy() { this.destroyed = true; this.oHash.destroy(); this.iHash.destroy(); } }; var hmac = (hash2, key, message) => new HMAC(hash2, key).update(message).digest(); hmac.create = (hash2, key) => new HMAC(hash2, key); // ../../node_modules/@noble/hashes/esm/hkdf.js function extract(hash2, ikm, salt) { hash(hash2); if (salt === void 0) salt = new Uint8Array(hash2.outputLen); return hmac(hash2, toBytes(salt), toBytes(ikm)); } var HKDF_COUNTER = /* @__PURE__ */ new Uint8Array([0]); var EMPTY_BUFFER = /* @__PURE__ */ new Uint8Array(); function expand(hash2, prk, info, length = 32) { hash(hash2); number(length); if (length > 255 * hash2.outputLen) throw new Error("Length should be <= 255*HashLen"); const blocks = Math.ceil(length / hash2.outputLen); if (info === void 0) info = EMPTY_BUFFER; const okm = new Uint8Array(blocks * hash2.outputLen); const HMAC2 = hmac.create(hash2, prk); const HMACTmp = HMAC2._cloneInto(); const T = new Uint8Array(HMAC2.outputLen); for (let counter = 0; counter < blocks; counter++) { HKDF_COUNTER[0] = counter + 1; HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T); okm.set(T, hash2.outputLen * counter); HMAC2._cloneInto(HMACTmp); } HMAC2.destroy(); HMACTmp.destroy(); T.fill(0); HKDF_COUNTER.fill(0); return okm.slice(0, length); } var hkdf = (hash2, ikm, salt, info, length) => expand(hash2, extract(hash2, ikm, salt), info, length); // ../../node_modules/@noble/hashes/esm/_md.js function setBigUint64(view, byteOffset, value, isLE2) { if (typeof view.setBigUint64 === "function") return view.setBigUint64(byteOffset, value, isLE2); const _32n = BigInt(32); const _u32_max = BigInt(4294967295); const wh = Number(value >> _32n & _u32_max); const wl = Number(value & _u32_max); const h = isLE2 ? 4 : 0; const l = isLE2 ? 0 : 4; view.setUint32(byteOffset + h, wh, isLE2); view.setUint32(byteOffset + l, wl, isLE2); } var Chi = (a, b, c) => a & b ^ ~a & c; var Maj = (a, b, c) => a & b ^ a & c ^ b & c; var HashMD = class extends Hash { constructor(blockLen, outputLen, padOffset, isLE2) { super(); this.blockLen = blockLen; this.outputLen = outputLen; this.padOffset = padOffset; this.isLE = isLE2; this.finished = false; this.length = 0; this.pos = 0; this.destroyed = false; this.buffer = new Uint8Array(blockLen); this.view = createView(this.buffer); } update(data) { exists(this); const { view, buffer, blockLen } = this; data = toBytes(data); const len = data.length; for (let pos = 0; pos < len; ) { const take = Math.min(blockLen - this.pos, len - pos); if (take === blockLen) { const dataView = createView(data); for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos); continue; } buffer.set(data.subarray(pos, pos + take), this.pos); this.pos += take; pos += take; if (this.pos === blockLen) { this.process(view, 0); this.pos = 0; } } this.length += data.length; this.roundClean(); return this; } digestInto(out) { exists(this); output(out, this); this.finished = true; const { buffer, view, blockLen, isLE: isLE2 } = this; let { pos } = this; buffer[pos++] = 128; this.buffer.subarray(pos).fill(0); if (this.padOffset > blockLen - pos) { this.process(view, 0); pos = 0; } for (let i = pos; i < blockLen; i++) buffer[i] = 0; setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE2); this.process(view, 0); const oview = createView(out); const len = this.outputLen; if (len % 4) throw new Error("_sha2: outputLen should be aligned to 32bit"); const outLen = len / 4; const state = this.get(); if (outLen > state.length) throw new Error("_sha2: outputLen bigger than state"); for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE2); } digest() { const { buffer, outputLen } = this; this.digestInto(buffer); const res = buffer.slice(0, outputLen); this.destroy(); return res; } _cloneInto(to) { to || (to = new this.constructor()); to.set(...this.get()); const { blockLen, buffer, length, finished, destroyed, pos } = this; to.length = length; to.pos = pos; to.finished = finished; to.destroyed = destroyed; if (length % blockLen) to.buffer.set(buffer); return to; } }; // ../../node_modules/@noble/hashes/esm/sha256.js var SHA256_K = /* @__PURE__ */ new Uint32Array([ 1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298 ]); var SHA256_IV = /* @__PURE__ */ new Uint32Array([ 1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225 ]); var SHA256_W = /* @__PURE__ */ new Uint32Array(64); var SHA256 = class extends HashMD { constructor() { super(64, 32, 8, false); this.A = SHA256_IV[0] | 0; this.B = SHA256_IV[1] | 0; this.C = SHA256_IV[2] | 0; this.D = SHA256_IV[3] | 0; this.E = SHA256_IV[4] | 0; this.F = SHA256_IV[5] | 0; this.G = SHA256_IV[6] | 0; this.H = SHA256_IV[7] | 0; } get() { const { A, B, C, D, E, F, G, H } = this; return [A, B, C, D, E, F, G, H]; } // prettier-ignore set(A, B, C, D, E, F, G, H) { this.A = A | 0; this.B = B | 0; this.C = C | 0; this.D = D | 0; this.E = E | 0; this.F = F | 0; this.G = G | 0; this.H = H | 0; } process(view, offset) { for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false); for (let i = 16; i < 64; i++) { const W15 = SHA256_W[i - 15]; const W2 = SHA256_W[i - 2]; const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0; } let { A, B, C, D, E, F, G, H } = this; for (let i = 0; i < 64; i++) { const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0; const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22); const T2 = sigma0 + Maj(A, B, C) | 0; H = G; G = F; F = E; E = D + T1 | 0; D = C; C = B; B = A; A = T1 + T2 | 0; } A = A + this.A | 0; B = B + this.B | 0; C = C + this.C | 0; D = D + this.D | 0; E = E + this.E | 0; F = F + this.F | 0; G = G + this.G | 0; H = H + this.H | 0; this.set(A, B, C, D, E, F, G, H); } roundClean() { SHA256_W.fill(0); } destroy() { this.set(0, 0, 0, 0, 0, 0, 0, 0); this.buffer.fill(0); } }; var sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256()); // src/modules/wallet-request/crypto/curve25519.ts var toHex = (input) => Buffer3.from(input).toString("hex"); var Curve25519 = (privateKeyHex = toHex(x25519.utils.randomPrivateKey())) => { const getPrivateKey = () => privateKeyHex; const x25519Api = { getPublicKey: () => toHex(x25519.getPublicKey(privateKeyHex)), calculateSharedSecret: (publicKeyHex, dAppDefinitionAddress) => { try { const sharedSecret = x25519.getSharedSecret(privateKeyHex, publicKeyHex); const derived = hkdf( sha256, sharedSecret, Buffer3.from(dAppDefinitionAddress, "utf-8"), "RCfM", 32 ); return ok(toHex(derived)); } catch (error) { return err(error); } } }; const ed25519Api = { getPublicKey: () => toHex(ed25519.getPublicKey(privateKeyHex)), sign: (messageHex) => { try { return ok(toHex(ed25519.sign(messageHex, privateKeyHex))); } catch (error) { return err(error); } } }; return { getPrivateKey, x25519: x25519Api, ed25519: ed25519Api }; }; // src/modules/wallet-request/crypto/blake2b.ts import { err as err2, ok as ok2 } from "neverthrow"; import blake from "blakejs"; import { Buffer as Buffer4 } from "buffer"; var bufferToArrayBuffer = (buffer) => { const arrayBuffer = new ArrayBuffer(buffer.length); const view = new Uint8Array(arrayBuffer); for (let i = 0; i < buffer.length; ++i) { view[i] = buffer[i]; } return arrayBuffer; }; var bufferToUnit8Array = (buffer) => new Uint8Array(bufferToArrayBuffer(buffer)); var blake2b = (input) => { try { return ok2(blake.blake2bHex(bufferToUnit8Array(input), void 0, 32)).map( (hex) => Buffer4.from(hex, "hex") ); } catch (error) { return err2(error); } }; // src/modules/wallet-request/data-request/builders/accounts.ts import { produce } from "immer"; import { boolean as boolean2, object as object2, optional as optional2 } from "valibot"; // src/schemas/index.ts import { array, boolean, literal, number as number2, object, optional, minValue, string, union, check, pipe } from "valibot"; var Account = object({ address: string(), label: string(), appearanceId: number2() }); var Proof = object({ publicKey: string(), signature: string(), curve: union([literal("curve25519"), literal("secp256k1")]) }); var AccountProof = object({ accountAddress: string(), proof: Proof }); var PersonaProof = object({ identityAddress: string(), proof: Proof }); var ProofOfOwnershipRequestItem = object({ challenge: string(), identityAddress: optional(string()), accountAddresses: optional(array(string())) }); var ProofOfOwnershipResponseItem = object({ challenge: string(), proofs: array(union([AccountProof, PersonaProof])) }); var Persona = object({ identityAddress: string(), label: string() }); var personaDataFullNameVariant = { western: "western", eastern: "eastern" }; var PersonaDataNameVariant = union([ literal(personaDataFullNameVariant.eastern), literal(personaDataFullNameVariant.western) ]); var PersonaDataName = object({ variant: PersonaDataNameVariant, familyName: string(), nickname: string(), givenNames: string() }); var NumberOfValues = object({ quantifier: union([literal("exactly"), literal("atLeast")]), quantity: pipe(number2(), minValue(0, "The number must be at least 0.")) }); var AccountsRequestItem = object({ challenge: optional(string()), numberOfAccounts: NumberOfValues }); var AccountsRequestResponseItem = pipe( object({ accounts: array(Account), challenge: optional(string()), proofs: optional(array(AccountProof)) }), check((data) => { if (data.challenge || data?.proofs) { return !!(data.challenge && data?.proofs?.length); } return true; }, "missing challenge or proofs") ); var PersonaDataRequestItem = object({ isRequestingName: optional(boolean()), numberOfRequestedEmailAddresses: optional(NumberOfValues), numberOfRequestedPhoneNumbers: optional(NumberOfValues) }); var PersonaDataRequestResponseItem = object({ name: optional(PersonaDataName), emailAddresses: optional(array(string())), phoneNumbers: optional(array(string())) }); var ResetRequestItem = object({ accounts: boolean(), personaData: boolean() }); var LoginRequestResponseItem = pipe( object({ persona: Persona, challenge: optional(string()), proof: optional(Proof) }), check((data) => { if (data.challenge || data.proof) { return !!(data.challenge && data.proof); } return true; }, "missing challenge or proof") ); var WalletUnauthorizedRequestItems = object({ discriminator: literal("unauthorizedRequest"), oneTimeAccounts: optional(AccountsRequestItem), oneTimePersonaData: optional(PersonaDataRequestItem) }); var AuthUsePersonaRequestItem = object({ discriminator: literal("usePersona"), identityAddress: string() }); var AuthLoginWithoutChallengeRequestItem = object({ discriminator: literal("loginWithoutChallenge") }); var AuthLoginWithChallengeRequestItem = object({ discriminator: literal("loginWithChallenge"), challenge: string() }); var AuthLoginRequestItem = union([ AuthLoginWithoutChallengeRequestItem, AuthLoginWithChallengeRequestItem ]); var AuthRequestItem = union([ AuthUsePersonaRequestItem, AuthLoginRequestItem ]); var WalletAuthorizedRequestItems = object({ discriminator: literal("authorizedRequest"), auth: AuthRequestItem, reset: optional(ResetRequestItem), proofOfOwnership: optional(ProofOfOwnershipRequestItem), oneTimeAccounts: optional(AccountsRequestItem), ongoingAccounts: optional(AccountsRequestItem), oneTimePersonaData: optional(PersonaDataRequestItem), ongoingPersonaData: optional(PersonaDataRequestItem) }); var WalletRequestItems = union([ WalletUnauthorizedRequestItems, WalletAuthorizedRequestItems ]); var SendTransactionItem = object({ transactionManifest: string(), version: number2(), blobs: optional(array(string())), message: optional(string()) }); var WalletTransactionItems = object({ discriminator: literal("transaction"), send: SendTransactionItem }); var SendTransactionResponseItem = object({ transactionIntentHash: string() }); var WalletTransactionResponseItems = object({ discriminator: literal("transaction"), send: SendTransactionResponseItem }); var CancelRequest = object({ discriminator: literal("cancelRequest") }); var ExpireAtTime = object({ discriminator: literal("expireAtTime"), unixTimestampSeconds: number2() }); var ExpireAfterDelay = object({ discriminator: literal("expireAfterDelay"), expireAfterSeconds: number2() }); var SubintentRequestItem = object({ discriminator: literal("subintent"), /** * Version of the message interface */ version: number2(), /** * Version of the Transaction Manifest */ manifestVersion: number2(), subintentManifest: string(), blobs: optional(array(string())), message: optional(string()), expiration: union([ExpireAtTime, ExpireAfterDelay]) }); var SubintentResponseItem = object({ expirationTimestamp: number2(), subintentHash: string(), signedPartialTransaction: string() }); var WalletPreAuthorizationItems = object({ discriminator: literal("preAuthorizationRequest"), request: optional(SubintentRequestItem) }); var WalletInteractionItems = union([ WalletRequestItems, WalletTransactionItems, CancelRequest, WalletPreAuthorizationItems ]); var Metadata = object({ version: literal(2), networkId: number2(), dAppDefinitionAddress: string(), origin: string() }); var WalletInteraction = object({ interactionId: string(), metadata: Metadata, items: WalletInteractionItems }); var WalletUnauthorizedRequestResponseItems = object({ discriminator: literal("unauthorizedRequest"), oneTimeAccounts: optional(AccountsRequestResponseItem), oneTimePersonaData: optional(PersonaDataRequestResponseItem) }); var AuthLoginWithoutChallengeRequestResponseItem = object({ discriminator: literal("loginWithoutChallenge"), persona: Persona }); var AuthLoginWithChallengeRequestResponseItem = object({ discriminator: literal("loginWithChallenge"), persona: Persona, challenge: string(), proof: Proof }); var WalletPreAuthorizationResponseItems = object({ discriminator: literal("preAuthorizationResponse"), response: optional(SubintentResponseItem) }); var AuthLoginRequestResponseItem = union([ AuthLoginWithoutChallengeRequestResponseItem, AuthLoginWithChallengeRequestResponseItem ]); var AuthUsePersonaRequestResponseItem = object({ discriminator: literal("usePersona"), persona: Persona }); var AuthRequestResponseItem = union([ AuthUsePersonaRequestResponseItem, AuthLoginRequestResponseItem ]); var WalletAuthorizedRequestResponseItems = object({ discriminator: literal("authorizedRequest"), auth: AuthRequestResponseItem, proofOfOwnership: optional(ProofOfOwnershipResponseItem), oneTimeAccounts: optional(AccountsRequestResponseItem), ongoingAccounts: optional(AccountsRequestResponseItem), oneTimePersonaData: optional(PersonaDataRequestResponseItem), ongoingPersonaData: optional(PersonaDataRequestResponseItem) }); var WalletRequestResponseItems = union([ WalletUnauthorizedRequestResponseItems, WalletAuthorizedRequestResponseItems ]); var WalletInteractionResponseItems = union([ WalletRequestResponseItems, WalletTransactionResponseItems, WalletPreAuthorizationResponseItems ]); var WalletInteractionSuccessResponse = object({ discriminator: literal("success"), interactionId: string(), items: WalletInteractionResponseItems }); var WalletInteractionFailureResponse = object({ discriminator: literal("failure"), interactionId: string(), error: string(), message: optional(string()) }); var WalletInteractionResponse = union([ WalletInteractionSuccessResponse, WalletInteractionFailureResponse ]); var extensionInteractionDiscriminator = { extensionStatus: "extensionStatus", openPopup: "openPopup", cancelWalletInteraction: "cancelWalletInteraction", walletInteraction: "walletInteraction" }; var StatusExtensionInteraction = object({ interactionId: string(), discriminator: literal(extensionInteractionDiscriminator.extensionStatus) }); var OpenPopupExtensionInteraction = object({ interactionId: string(), discriminator: literal(extensionInteractionDiscriminator.openPopup) }); var WalletInteractionExtensionInteraction = object({ interactionId: string(), discriminator: literal(extensionInteractionDiscriminator.walletInteraction), interaction: WalletInteraction, sessionId: optional(string()) }); var CancelWalletInteractionExtensionInteraction = object({ interactionId: string(), discriminator: literal( extensionInteractionDiscriminator.cancelWalletInteraction ), metadata: Metadata }); var ExtensionInteraction = union([ StatusExtensionInteraction, OpenPopupExtensionInteraction, WalletInteractionExtensionInteraction, CancelWalletInteractionExtensionInteraction ]); var messageLifeCycleEventType = { extensionStatus: "extensionStatus", receivedByExtension: "receivedByExtension", receivedByWallet: "receivedByWallet", requestCancelSuccess: "requestCancelSuccess", requestCancelFail: "requestCancelFail" }; var MessageLifeCycleExtensionStatusEvent = object({ eventType: literal(messageLifeCycleEventType.extensionStatus), interactionId: string(), isWalletLinked: boolean(), isExtensionAvailable: boolean(), canHandleSessions: optional(boolean()) }); var MessageLifeCycleEvent = object({ eventType: union([ literal(messageLifeCycleEventType.extensionStatus), literal(messageLifeCycleEventType.receivedByExtension), literal(messageLifeCycleEventType.receivedByWallet), literal(messageLifeCycleEventType.requestCancelSuccess), literal(messageLifeCycleEventType.requestCancelFail) ]), interactionId: string() }); var IncomingMessage = union([ MessageLifeCycleEvent, WalletInteractionResponse ]); var eventType = { outgoingMessage: "radix#chromeExtension#send", incomingMessage: "radix#chromeExtension#receive" }; var Offer = literal("offer"); var Answer = literal("answer"); var IceCandidate = literal("iceCandidate"); var IceCandidates = literal("iceCandidates"); var Types = union([Offer, Answer, IceCandidate, IceCandidates]); var Sources = union([literal("wallet"), literal("extension")]); var SignalingServerMessage = object({ requestId: string(), targetClientId: string(), encryptedPayload: string(), source: optional(Sources), // redundant, to be removed connectionId: optional(string()) // redundant, to be removed }); var AnswerIO = object({ ...SignalingServerMessage.entries, method: Answer, payload: object({ sdp: string() }) }); var OfferIO = object({ ...SignalingServerMessage.entries, method: Offer, payload: object({ sdp: string() }) }); var IceCandidatePayloadIO = object({ candidate: string(), sdpMid: string(), sdpMLineIndex: number2() }); var IceCandidateIO = object({ ...SignalingServerMessage.entries, method: IceCandidate, payload: IceCandidatePayloadIO }); var IceCandidatesIO = object({ ...SignalingServerMessage.entries, method: IceCandidates, payload: array(IceCandidatePayloadIO) }); // src/modules/wallet-request/data-request/builders/accounts.ts var AccountsDataRequestSchema = object2({ numberOfAccounts: NumberOfValues, withProof: optional2(boolean2()), reset: optional2(boolean2()) }); var accounts = () => { const defaultValue = { numberOfAccounts: { quantifier: "atLeast", quantity: 1 } }; let data = produce(defaultValue, () => { }); const atLeast = (n) => { data = produce(data, (draft) => { draft.numberOfAccounts.quantifier = "atLeast"; draft.numberOfAccounts.quantity = n; }); return methods; }; const exactly = (n) => { data = produce(data, (draft) => { draft.numberOfAccounts.quantifier = "exactly"; draft.numberOfAccounts.quantity = n; }); return methods; }; const reset = (value = true) => { data = produce(data, (draft) => { draft.reset = value; }); return methods; }; const withProof = (value = true) => { data = produce(data, (draft) => { draft.withProof = value; }); return methods; }; const _toObject = () => ({ accounts: data }); const methods = { atLeast, exactly, withProof, reset, _toObject }; return methods; }; // src/modules/wallet-request/data-request/builders/persona.ts import { produce as produce2 } from "immer"; import { boolean as boolean3, object as object3, optional as optional3 } from "valibot"; var schema = object3({ withProof: optional3(boolean3()) }); var persona = (initialData = { withProof: false }) => { let data = produce2(initialData, () => { }); const withProof = (value = true) => { data = produce2(data, (draft) => { draft.withProof = value; }); return methods; }; const _toObject = () => ({ persona: data }); const methods = { withProof, _toObject }; return methods; }; // src/modules/wallet-request/data-request/builders/persona-data.ts import { produce as produce3 } from "immer"; import { boolean as boolean4, object as object4, partial } from "valibot"; var PersonaDataRequestSchema = partial( object4({ fullName: boolean4(), emailAddresses: NumberOfValues, phoneNumbers: NumberOfValues, reset: boolean4() }) ); var personaData = (initialData = {}) => { let data = produce3(initialData, () => { }); const fullName = (value = true) => { data = produce3(data, (draft) => { draft.fullName = value; }); return methods; }; const createNumberOfValuesOptions = (key) => ({ atLeast: (n) => { data = produce3(data, (draft) => { draft[key] = { quantifier: "atLeast", quantity: n }; }); return methods; }, exactly: (n) => { data = produce3(data, (draft) => { draft[key] = { quantifier: "exactly", quantity: n }; }); return methods; } }); const emailAddresses = (value = true) => { const options = createNumberOfValuesOptions("emailAddresses"); options.exactly(value ? 1 : 0); return methods; }; const phoneNumbers = (value = true) => { const options = createNumberOfValuesOptions("phoneNumbers"); options.exactly(value ? 1 : 0); return methods; }; const reset = (value = true) => { data = produce3(data, (draft) => { draft.reset = value; }); return methods; }; const _toObject = () => ({ personaData: data }); const methods = { fullName, emailAddresses, phoneNumbers, reset, _toObject }; return methods; }; // src/modules/wallet-request/data-request/builders/proof-of-ownership.ts import { produce as produce4 } from "immer"; import { object as object5, string as string2, array as array2, optional as optional4 } from "valibot"; var schema2 = object5({ accountAddresses: optional4(array2(string2())), identityAddress: optional4(string2()) }); var proofOfOwnership = (initialData = {}) => { let data = produce4(initialData, () => { }); const accounts2 = (value) => { data = produce4(data, (draft) => { draft.accountAddresses = value; }); return methods; }; const identity = (value) => { data = produce4(data, (draft) => { draft.identityAddress = value; }); return methods; }; const _toObject = () => ({ proofOfOwnership: data }); const methods = { accounts: accounts2, identity, _toObject }; return methods; }; // src/modules/wallet-request/data-request/builders/index.ts var config = (data) => { const _toObject = () => ({ ...data }); const methods = { _toObject }; return methods; }; var DataRequestBuilder = { accounts, personaData, persona, config }; var OneTimeDataRequestBuilder = { accounts, personaData, proofOfOwnership }; // src/helpers/is-deep-equal.ts var isDeepEqual = (a, b) => { const values = [null, void 0, false, true]; if (values.includes(a) || values.includes(b) || typeof a === "number" || typeof b === "number") { return Object.is(a, b); } const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (aKeys.length !== bKeys.length) return false; for (const key of aKeys) { const value1 = a[key]; const value2 = b[key]; const isObjects = isObject(value1) && isObject(value2); if (isObjects && !isDeepEqual(value1, value2) || !isObjects && value1 !== value2) { return false; } } return true; }; var isObject = (x) => { return x != null && typeof x === "object"; }; // src/modules/wallet-request/data-request/helpers/can-data-request-be-resolved-by-rdt-state.ts var canDataRequestBeResolvedByRdtState = (dataRequest, state) => { if (dataRequest.discriminator === "authorizedRequest") { const isReset = dataRequest.reset?.accounts || dataRequest.reset?.personaData; const isOneTimeRequest = !!(dataRequest.oneTimeAccounts || dataRequest.oneTimePersonaData); const isChallengeRequest = dataRequest.auth.discriminator === "loginWithChallenge" || !!dataRequest.oneTimeAccounts?.challenge || !!dataRequest.ongoingAccounts?.challenge; if (isReset || isOneTimeRequest || isChallengeRequest) return false; let rdtStateSatisfiesRequest = false; if (dataRequest.ongoingAccounts) { const { quantifier, quantity } = dataRequest.ongoingAccounts.numberOfAccounts; rdtStateSatisfiesRequest = state.sharedData?.ongoingAccounts?.numberOfAccounts?.quantifier === quantifier && state.sharedData?.ongoingAccounts?.numberOfAccounts?.quantity === quantity; } if (dataRequest.ongoingPersonaData) { rdtStateSatisfiesRequest = isDeepEqual( dataRequest.ongoingPersonaData, state.sharedData?.ongoingPersonaData ); } return rdtStateSatisfiesRequest; } return false; }; // src/modules/wallet-request/data-request/helpers/to-wallet-request.ts import { produce as produce6 } from "immer"; // src/modules/wallet-request/data-request/transformations/rdt-to-wallet.ts import { produce as produce5 } from "immer"; import { ok as ok3 } from "neverthrow"; import { boolean as boolean5, object as object6, string as string3, optional as optional5, array as array3 } from "valibot"; var TransformRdtDataRequestToWalletRequestInput = object6({ proofOfOwnership: optional5( object6({ challenge: optional5(string3()), accountAddresses: optional5(array3(string3())), identityAddress: optional5(string3()) }) ), accounts: optional5( object6({ numberOfAccounts: NumberOfValues, reset: boolean5(), oneTime: boolean5(), challenge: optional5(string3()) }) ), personaData: optional5( object6({ fullName: optional5(boolean5()), phoneNumbers: optional5(NumberOfValues), emailAddresses: optional5(NumberOfValues), reset: boolean5(), oneTime: optional5(boolean5()) }) ), persona: optional5( object6({ identityAddress: optional5(string3()), label: optional5(string3()), challenge: optional5(string3()) }) ) }); var isAuthorized = (input) => { const { persona: persona2, accounts: accounts2, personaData: personaData2, proofOfOwnership: proofOfOwnership2 } = input; const isPersonaLogin = !!persona2; const shouldResetData = accounts2?.reset || personaData2?.reset; const isOngoingAccountsRequest = accounts2 && !accounts2?.oneTime; const isOngoingPersonaDataRequest = personaData2 && !personaData2?.oneTime; const isAuthorizedRequest = !!(shouldResetData || isOngoingAccountsRequest || isOngoingPersonaDataRequest || isPersonaLogin || proofOfOwnership2); return isAuthorizedRequest; }; var createLoginRequestItem = (input) => { if (input.persona?.challenge) { return { discriminator: "loginWithChallenge", challenge: input.persona.challenge }; } if (input.persona?.identityAddress) { return { discriminator: "usePersona", identityAddress: input.persona?.identityAddress }; } return { discriminator: "loginWithoutChallenge" }; }; var withAccountRequestItem = (input) => (requestItems) => { const updatedRequestItems = { ...requestItems }; const { accounts: accounts2 } = input; if (accounts2) { const data = { challenge: accounts2.challenge, numberOfAccounts: accounts2.numberOfAccounts }; const isOngoingRequest = updatedRequestItems.discriminator === "authorizedRequest" && !input.accounts?.oneTime; const isConnectOngoingRequest = updatedRequestItems.discriminator === "authorizedRequest"; if (input.accounts?.oneTime) { updatedRequestItems["oneTimeAccounts"] = data; } else if (isOngoingRequest || isConnectOngoingRequest) { updatedRequestItems["ongoingAccounts"] = data; } } return updatedRequestItems; }; var withProofOfOwnershipRequestItem = (input) => (requestItems) => { const updatedRequestItems = { ...requestItems }; if (input.proofOfOwnership) { const { challenge, accountAddresses, identityAddress } = input.proofOfOwnership; if (challenge && updatedRequestItems.discriminator === "authorizedRequest") { updatedRequestItems["proofOfOwnership"] = { challenge }; if (accountAddresses) { updatedRequestItems["proofOfOwnership"].accountAddresses = accountAddresses; } if (identityAddress) { updatedRequestItems["proofOfOwnership"].identityAddress = identityAddress; } } } return updatedRequestItems; }; var withPersonaDataRequestItem = (input) => (requestItems) => { const updatedRequestItems = { ...requestItems }; if (input.personaData) { const { fullName: isRequestingName, phoneNumbers: numberOfRequestedPhoneNumbers, emailAddresses: numberOfRequestedEmailAddresses } = input.personaData; if (input.personaData?.oneTime) { updatedRequestItems["oneTimePersonaData"] = { isRequestingName, numberOfRequestedPhoneNumbers, numberOfRequestedEmailAddresses }; } const isOngoingRequest = updatedRequestItems.discriminator === "authorizedRequest" && !input.personaData?.oneTime; const isConnectOngoingRequest = updatedRequestItems.discriminator === "authorizedRequest"; if (isOngoingRequest || isConnectOngoingRequest) { updatedRequestItems["ongoingPersonaData"] = { isRequestingName, numberOfRequestedPhoneNumbers, numberOfRequestedEmailAddresses }; } } return updatedRequestItems; }; var withResetRequestItem = (input) => (requestItems) => { const { accounts: accounts2, personaData: personaData2 } = input; return { ...requestItems, reset: { accounts: !!accounts2?.reset, personaData: !!personaData2?.reset } }; }; var createUnauthorizedRequestItems = (input) => ok3({ discriminator: "unauthorizedRequest" }).map(withAccountRequestItem(input)).map(withPersonaDataRequestItem(input)).map(withProofOfOwnershipRequestItem(input)); var createAuthorizedRequestItems = (input) => ok3({ discriminator: "authorizedRequest", auth: createLoginRequestItem(input) }).map(withAccountRequestItem(input)).map(withPersonaDataRequestItem(input)).map(withResetRequestItem(input)).map(withProofOfOwnershipRequestItem(input)); var transformConnectRequest = (isConnect, input) => ok3( isConnect ? produce5(input, (draft) => { if (draft.accounts) { draft.accounts.oneTime = false; draft.accounts.reset = false; } if (draft.personaData) { draft.personaData.oneTime = false; draft.personaData.reset = false; } }) : input ); var transformRdtDataRequestToWalletRequest = (isConnect, input) => transformConnectRequest(isConnect, input).andThen( (transformed) => isAuthorized(transformed) ? createAuthorizedRequestItems(transformed) : createUnauthorizedRequestItems(transformed) ); // src/modules/wallet-request/data-request/helpers/to-wallet-request.ts var toWalletRequest = ({ dataRequestState, isConnect, challenge, oneTime, walletData }) => transformRdtDataRequestToWalletRequest( isConnect, produce6({}, (draft) => { if (dataRequestState.proofOfOwnership) { draft.proofOfOwnership = { ...dataRequestState.proofOfOwnership, challenge }; } if (dataRequestState.accounts) { draft.accounts = { numberOfAccounts: dataRequestState.accounts.numberOfAccounts || { quantifier: "atLeast", quantity: 1 }, oneTime, reset: !!dataRequestState.accounts.reset, challenge: dataRequestState.accounts.withProof ? challenge : void 0 }; } if (dataRequestState.personaData) draft.personaData = { ...dataRequestState.personaData, reset: !!dataRequestState.personaData.reset, oneTime }; if (!oneTime || dataRequestState.proofOfOwnership) { const persona2 = walletData.persona; if (walletData.persona) draft.persona = persona2; if (dataRequestState.persona?.withProof) draft.persona = { ...draft.persona ?? {}, challenge }; if (Object.values(dataRequestState).length === 0) draft.persona = { challenge: void 0 }; } }) ); // src/modules/wallet-request/data-request/transformations/shared-data.ts import { produce as produce7 } from "immer"; var transformWalletRequestToSharedData = (walletInteraction, sharedData) => { const { items: walletDataRequest } = walletInteraction; if (walletDataRequest.discriminator === "authorizedRequest") return produce7({}, (draft) => { draft.persona = { proof: false }; if (walletDataRequest.auth.discriminator === "loginWithChallenge") draft.persona.proof = !!walletDataRequest.auth.challenge; if (walletDataRequest.ongoingAccounts) { draft.ongoingAccounts = { proof: !!walletDataRequest.ongoingAccounts.challenge, numberOfAccounts: walletDataRequest.ongoingAccounts.numberOfAccounts }; } if (walletDataRequest.ongoingPersonaData) { draft.ongoingPersonaData = walletDataRequest.ongoingPersonaData; } }); return sharedData; }; var transformSharedDataToDataRequestState = (sharedData) => produce7({}, (draft) => { if (sharedData.ongoingAccounts) { draft.accounts = { numberOfAccounts: sharedData.ongoingAccounts.numberOfAccounts, withProof: sharedData.ongoingAccounts.proof, reset: true }; } if (sharedData.ongoingPersonaData) { draft.personaData = { fullName: sharedData.ongoingPersonaData.isRequestingName, phoneNumbers: sharedData.ongoingPersonaData.numberOfRequestedPhoneNumbers, emailAddresses: sharedData.ongoingPersonaData.numberOfRequestedEmailAddresses, reset: false }; } if (sharedData.persona) { draft.persona = { withProof: false }; } }); // src/modules/wallet-request/data-request/transformations/wallet-to-rdt.ts import { produce as produce8 } from "immer"; import { okAsync as okAsync2 } from "neverthrow"; // src/modules/state/state.module.ts import { BehaviorSubject as BehaviorSubject2, Subscription, filter } from "rxjs"; // src/modules/state/types.ts import { array as array4, boolean as boolean6, optional as optional6, literal as literal2, object as object7, variant, string as string4 } from "valibot"; var proofType = { persona: "persona", account: "account" }; var SignedChallengePersona = object7({ challenge: string4(), proof: Proof, address: string4(), type: literal2(proofType.persona) }); var SignedChallengeAccount = object7({ challenge: string4(), proof: Proof, address: string4(), type: literal2(proofType.account) }); var SignedChallenge = variant("type", [ SignedChallengePersona, SignedChallengeAccount ]); var WalletDataPersonaDataFullName = object7({ entry: literal2("fullName"), fields: PersonaDataName }); var WalletDataPersonaDataEmailAddresses = object7({ entry: literal2("emailAddresses"), fields: array4(string4()) }); var WalletDataPersonaDataPhoneNumbersAddresses = object7({ entry: literal2("phoneNumbers"), fields: array4(string4()) }); var WalletDataPersonaData = variant("entry", [ WalletDataPersonaDataFullName, WalletDataPersonaDataEmailAddresses, WalletDataPersonaDataPhoneNumbersAddresses ]); var WalletData = object7({ accounts: array4(Account), personaData: array4(WalletDataPersonaData), persona: optional6(Persona), proofs: array4(SignedChallenge) }); var SharedData = object7({ persona: optional6(object7({ proof: boolean6() })), ongoingAccounts: optional6( object7({ numberOfAccounts: optional6(NumberOfValues), proof: boolean6() }) ), ongoingPersonaData: optional6(PersonaDataRequestItem) }); var RdtState = object7({ loggedInTimestamp: string4(), walletData: WalletData, sharedData: SharedData }); var walletDataDefault = { accounts: [], personaData: [], proofs: [], persona: void 0 }; // src/modules/state/state.module.ts import { ok as ok4, okAsync } from "neverthrow"; var StateModule = (input) => { const logger = input?.logger?.getSubLogger({ name: "StateModule" }); const storageModule = input.providers.storageModule; const subscriptions = new Subscription(); const setState = (state) => storageModule.setState(state); const getState = () => storageModule.getState().orElse(() => okAsync(defaultState)).andThen((state) => state ? ok4(state) : ok4(defaultState)); const patchState = (state) => getState().andThen( (oldState) => setState({ ...oldState, ...state }) ); const defaultState = { walletData: walletDataDefault, loggedInTimestamp: "", sharedData: {} }; const resetState = () => storageModule.setState(defaultState).map(() => { emitWalletData(); }); const initializeState = () => getState().map(() => emitWalletData()).orElse(() => resetState()); initializeState(); const walletDataSubject = new BehaviorSubject2( void 0 ); const emitWalletData = () => { storageModule.getState().map((state) => { walletDataSubject.next(state?.walletData); }); }; const walletData$ = walletDataSubject.asObservable().pipe(filter((walletData) => !!walletData)); return { setState, patchState, getState, walletData$, emitWalletData, getWalletData: () => walletDataSubject.value, reset: resetState, storage$: storageModule.storage$, destroy: () => { subscriptions.unsubscribe(); } }; }; // src/modules/wallet-request/data-request/transformations/wallet-to-rdt.ts var withAccounts = (input) => (walletData) => { let accounts2 = []; if (input.discriminator === "authorizedRequest") { const oneTimeAccounts = input.oneTimeAccounts?.accounts ?? []; const ongoingAccounts = input.ongoingAccounts?.accounts ?? []; accounts2 = [...oneTimeAccounts, ...ongoingAccounts]; } else if (input.discriminator === "unauthorizedRequest") { const oneTimeAccounts = input.oneTimeAccounts?.accounts ?? []; accounts2 = oneTimeAccounts; } return produce8(walletData, (draft) => { draft.accounts = accounts2; }); }; var withPersonaDataEntries = (input) => { const entries = []; if (input.name) { entries.push({ entry: "fullName", fields: input.name }); } if (input.emailAddresses) entries.push({ entry: "emailAddresses", fields: input.emailAddresses }); if (input.phoneNumbers) entries.push({ entry: "phoneNumbers", fields: input.phoneNumbers }); return entries; }; var convertOwnershipProofsToSignedChallenge = (challenge, proofs) => { return proofs.map((proof) => { const type = "identityAddress" in proof ? proofType.persona : proofType.account; const address = "identityAddress" in proof ? proof.identityAddress : proof.accountAddress; return { type, challenge, address, proof: proof.proof }; }); }; var withPersonaData = (input) => (walletData) => produce8(walletData, (draft) => { if (input.discriminator === "authorizedRequest") { if (input.oneTimePersonaData) draft.personaData = withPersonaDataEntries(input.oneTimePersonaData); if (input.ongoingPersonaData) draft.personaData = withPersonaDataEntries(input.ongoingPersonaData); } else if (input.discriminator === "unauthorizedRequest" && input.oneTimePersonaData) draft.personaData = withPersonaDataEntries(input.oneTimePersonaData); }); var withPersona = (input) => (walletData) => produce8(walletData, (draft) => { if (input.discriminator === "authorizedRequest") draft.persona = input.auth?.persona; }); var withProofs = (input) => (walletData) => produce8(walletData, (draft) => { draft.proofs = []; if (input.discriminator === "authorizedRequest") { if (input.auth.discriminator === "loginWithChallenge") draft.proofs.push({ challenge: input.auth.challenge, proof: input.auth.proof, address: input.auth.persona.identityAddress, type: proofType.persona }); if (input.ongoingAccounts?.challenge && input.ongoingAccounts.proofs?.length) { const challenge = input.ongoingAccounts.challenge; const accountProofs = input.ongoingAccounts.proofs.map( ({ accountAddress, proof }) => ({ proof, address: accountAddress, challenge, type: proofType.account }) ); draft.proofs.push(...accountProofs); } if (input.oneTimeAccounts?.challenge && input.oneTimeAccounts.proofs?.length) { const challenge = input.oneTimeAccounts.challenge; const accountProofs = input.oneTimeAccounts.proofs.map( ({ accountAddress, proof }) => ({ proof, address: accountAddress, challenge, type: proofType.account }) ); draft.proofs.push(...accountProofs); } if (input.proofOfOwnership) { draft.proofs.push( ...convertOwnershipProofsToSignedChallenge( input.proofOfOwnership.challenge, input.proofOfOwnership.proofs ) ); } } if (input.discriminator === "unauthorizedRequest") { if (input.oneTimeAccounts?.challenge && input.oneTimeAccounts.proofs?.length) { const challenge = input.oneTimeAccounts.challenge; const accountProofs = input.oneTimeAccounts.proofs.map( ({ accountAddress, proof }) => ({ proof, address: accountAddress, challenge, type: pro