Skip to content

Refactored fcl-core wallet-utils folder files to TypeScript #2478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions packages/fcl-core/src/wallet-utils/CompositeSignature.js

This file was deleted.

25 changes: 25 additions & 0 deletions packages/fcl-core/src/wallet-utils/CompositeSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {withPrefix} from "@onflow/util-address"
import {COMPOSITE_SIGNATURE_PRAGMA} from "../normalizers/service/__vsn"

/**
* @description Constructs a new CompositeSignature instance.
*
* @param {string} addr Flow Address
* @param {number} keyId Key ID
* @param {string} signature Signature as a hex string
*/
export class CompositeSignature {
f_type: string
f_vsn: string
addr: string
keyId: number
signature: string

constructor(addr: string, keyId: number | string, signature: string) {
this.f_type = COMPOSITE_SIGNATURE_PRAGMA.f_type
this.f_vsn = COMPOSITE_SIGNATURE_PRAGMA.f_vsn
this.addr = withPrefix(addr)
this.keyId = Number(keyId)
this.signature = signature
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {encodeAccountProof} from "./encode-account-proof.js"
import {encodeAccountProof} from "./encode-account-proof"

const address = "0xABC123DEF456"
const appIdentifier = "AWESOME-APP-ID"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,41 @@ import {sansPrefix} from "@onflow/util-address"
import {invariant} from "@onflow/util-invariant"
import {Buffer, encode as rlpEncode} from "@onflow/rlp"

const rightPaddedHexBuffer = (value, pad) =>
export interface AccountProofData {
address?: string
nonce?: string
appIdentifier?: string
}

const rightPaddedHexBuffer = (value: string, pad: number): Buffer =>
Buffer.from(value.padEnd(pad * 2, "0"), "hex")

const leftPaddedHexBuffer = (value, pad) =>
const leftPaddedHexBuffer = (value: string, pad: number): Buffer =>
Buffer.from(value.padStart(pad * 2, "0"), "hex")

const addressBuffer = addr => leftPaddedHexBuffer(addr, 8)
const addressBuffer = (addr: string): Buffer => leftPaddedHexBuffer(addr, 8)

const nonceBuffer = nonce => Buffer.from(nonce, "hex")
const nonceBuffer = (nonce: string): Buffer => Buffer.from(nonce, "hex")

export const encodeAccountProof = (
{address, nonce, appIdentifier},
includeDomainTag = true
) => {
{address, nonce, appIdentifier}: AccountProofData,
includeDomainTag: boolean = true
): string => {
invariant(
address,
!!address,
"Encode Message For Provable Authn Error: address must be defined"
)
invariant(
nonce,
!!nonce,
"Encode Message For Provable Authn Error: nonce must be defined"
)
invariant(
appIdentifier,
appIdentifier as any,
"Encode Message For Provable Authn Error: appIdentifier must be defined"
)

invariant(
nonce.length >= 64,
nonce!.length >= 64,
"Encode Message For Provable Authn Error: nonce must be minimum of 32 bytes"
)

Expand All @@ -44,15 +50,15 @@ export const encodeAccountProof = (
ACCOUNT_PROOF_DOMAIN_TAG,
rlpEncode([
appIdentifier,
addressBuffer(sansPrefix(address)),
nonceBuffer(nonce),
addressBuffer(sansPrefix(address!)),
nonceBuffer(nonce!),
]),
]).toString("hex")
}

return rlpEncode([
appIdentifier,
addressBuffer(sansPrefix(address)),
nonceBuffer(nonce),
addressBuffer(sansPrefix(address!)),
nonceBuffer(nonce!),
]).toString("hex")
}
13 changes: 0 additions & 13 deletions packages/fcl-core/src/wallet-utils/index.js

This file was deleted.

13 changes: 13 additions & 0 deletions packages/fcl-core/src/wallet-utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export {
sendMsgToFCL,
ready,
close,
approve,
decline,
redirect,
} from "./send-msg-to-fcl"
export {onMessageFromFCL} from "./on-message-from-fcl"
export {encodeMessageFromSignable} from "@onflow/sdk"
export {CompositeSignature} from "./CompositeSignature"
export {encodeAccountProof} from "./encode-account-proof"
export {injectExtService} from "./inject-ext-service"
10 changes: 0 additions & 10 deletions packages/fcl-core/src/wallet-utils/inject-ext-service.js

This file was deleted.

12 changes: 12 additions & 0 deletions packages/fcl-core/src/wallet-utils/inject-ext-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {Service} from "@onflow/typedefs"

export function injectExtService(service: Service): void {
if (service.type === "authn" && service.endpoint != null) {
if (!Array.isArray((window as any).fcl_extensions)) {
;(window as any).fcl_extensions = []
}
;(window as any).fcl_extensions.push(service)
} else {
console.warn("Authn service is required")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@
* @description
* Listens for messages from FCL
*
* @param {string} messageType - Message type
* @param {Function} cb - Callback function
* @returns {Function} - Function to remove event listener
* @param {string} messageType Message type
* @param {Function} cb Callback function
* @returns {Function} Function to remove event listener
*/
export const onMessageFromFCL = (messageType, cb = () => {}) => {
const buildData = data => {
export const onMessageFromFCL = (
messageType: string,
cb: (data: any, context: {origin: string}) => void = () => {}
): (() => void) => {
const buildData = (data: any): any => {
if (data.deprecated)
console.warn("DEPRECATION NOTICE", data.deprecated.message)
delete data?.body?.interaction

return data
}

const internal = e => {
const internal = (e: MessageEvent): void => {
const {data, origin} = e
if (typeof data !== "object") return
if (typeof data == null) return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ import {
FCL_RESPONSE_PARAM_NAME,
} from "../utils/constants"
import {onMessageFromFCL} from "./on-message-from-fcl"
import {URL} from "../utils/url"

export interface PollingResponse {
f_type: "PollingResponse"
f_vsn: "1.0.0"
status: "APPROVED" | "DECLINED" | "REDIRECT"
reason: string | null
data: any
}

/**
* @description
* Sends message to FCL window
* @description Sends message to FCL window
*
* @param {string} type - Message type
* @param {object} msg - Message object
* @param {string} type Message type
* @param {PollingResponse} msg Message object
* @returns {void}
*
* @example
Expand All @@ -22,7 +28,10 @@ import {URL} from "../utils/url"
* data: data,
* })
*/
export const sendMsgToFCL = (type, msg = {}) => {
export const sendMsgToFCL = (
type: string,
msg: PollingResponse = {} as PollingResponse
): void => {
const data = {...msg, type}

const urlParams = new URLSearchParams(window.location.search)
Expand All @@ -41,75 +50,73 @@ export const sendMsgToFCL = (type, msg = {}) => {
}

/**
* @description
* Listens for "FCL:VIEW:READY:RESPONSE" and sends "FCL:VIEW:READY"
* @description Listens for "FCL:VIEW:READY:RESPONSE" and sends "FCL:VIEW:READY"
*
* @param {Function} cb - Callback function
* @param {object} msg - Message object
* @param {Function} cb Callback function
* @param {PollingResponse} msg Message object
* @returns {void}
*/
export const ready = (cb, msg = {}) => {
export const ready = (
cb: (data: any, context: {origin: string}) => void,
msg: PollingResponse = {} as PollingResponse
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
msg: PollingResponse = {} as PollingResponse

Looks like msg is unused here. IMO we should maybe just take this opportunity to drop it. The risk is that users could get type errors for this if they were passing an (unused) msg arg here, but functionally this should not break anything so I think it's worth it for the long term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes to me it makes completely sense because it's useless. If we want to maintain backward compatibility we could still leave it but make it optional like it is done in the sendMsgToFCL method. What do you think?

): void => {
onMessageFromFCL("FCL:VIEW:READY:RESPONSE", cb)
sendMsgToFCL("FCL:VIEW:READY")
}

/**
* @description
* Sends "FCL:VIEW:CLOSE"
* @description Sends "FCL:VIEW:CLOSE"
*
* @returns {void}
*/
export const close = () => {
export const close = (): void => {
sendMsgToFCL("FCL:VIEW:CLOSE")
}

/**
* @description
* Sends "FCL:VIEW:RESPONSE" with status "APPROVED"
* @description Sends "FCL:VIEW:RESPONSE" with status "APPROVED"
*
* @param {object} data - Data object
* @param {object} data Data object
* @returns {void}
*/
export const approve = data => {
export const approve = (data: any): void => {
sendMsgToFCL("FCL:VIEW:RESPONSE", {
f_type: "PollingResponse",
f_vsn: "1.0.0",
status: "APPROVED",
reason: null,
data: data,
})
} as PollingResponse)
}

/**
* @description
* Sends "FCL:VIEW:RESPONSE" with status "DECLINED"
* @description Sends "FCL:VIEW:RESPONSE" with status "DECLINED"
*
* @param {string} reason - Reason for declining
* @param {string} reason Reason for declining
* @returns {void}
*/
export const decline = reason => {
export const decline = (reason: string): void => {
sendMsgToFCL("FCL:VIEW:RESPONSE", {
f_type: "PollingResponse",
f_vsn: "1.0.0",
status: "DECLINED",
reason: reason,
data: null,
})
} as PollingResponse)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these type assertions necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed anymore, removed!

}

/**
* @description
* Sends "FCL:VIEW:RESPONSE" with status "REDIRECT"
* @description Sends "FCL:VIEW:RESPONSE" with status "REDIRECT"
*
* @param {object} data - Data object
* @param {object} data Data object
* @returns {void}
*/
export const redirect = data => {
export const redirect = (data: any): void => {
sendMsgToFCL("FCL:VIEW:RESPONSE", {
f_type: "PollingResponse",
f_vsn: "1.0.0",
status: "REDIRECT",
reason: null,
data: data,
})
} as PollingResponse)
}