Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 37 additions & 3 deletions packages/connect/src/config/defaultTransports.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { http, type Chain } from 'viem'

import { normalizeSequenceNodesUrl } from '../utils/helpers.js'
import { getNetwork } from '../utils/networks.js'

const isSequenceNodeUrl = (url: string): boolean => {
return url.includes('sequence.app')
}
Expand All @@ -8,10 +11,32 @@ const applyTemplate = (template: string, params: Record<string, string>): string
return Object.entries(params).reduce((result, [key, value]) => result.replaceAll(`{${key}}`, value), template)
}

const resolveNetworkName = (chain: Chain, nodesUrl: string): string => {
if (isSequenceNodeUrl(nodesUrl)) {
try {
return getNetwork(chain.id).name
} catch {
return (chain as any).shortName ?? chain.name
}
}

return (chain as any).shortName ?? chain.name
}

const withSequenceNetworkPath = (url: string, networkName: string, hasTemplate: boolean): string => {
const cleanUrl = url.endsWith('/') ? url.slice(0, -1) : url

if (hasTemplate) {
return cleanUrl
}

return `${cleanUrl}/${networkName}`
}

const appendAccessKey = (url: string, accessKey: string): string => {
const cleanUrl = url.endsWith('/') ? url.slice(0, -1) : url
if (url.endsWith(accessKey)) {
return url
if (cleanUrl.endsWith(accessKey)) {
return cleanUrl
}

return `${cleanUrl}/${accessKey}`
Expand All @@ -21,7 +46,16 @@ export const getDefaultTransports = (chains: readonly [Chain, ...Chain[]], proje
return Object.fromEntries(
chains.map(chain => {
const resolvedNodesUrl = nodesUrl
? applyTemplate(nodesUrl, { network: (chain as any).shortName ?? chain.name })
? (() => {
const normalizedNodesUrl = normalizeSequenceNodesUrl(nodesUrl) ?? nodesUrl
const networkName = resolveNetworkName(chain, normalizedNodesUrl)
const hasTemplate = normalizedNodesUrl.includes('{network}')
const templatedUrl = applyTemplate(normalizedNodesUrl, { network: networkName })

return isSequenceNodeUrl(normalizedNodesUrl)
? withSequenceNetworkPath(templatedUrl, networkName, hasTemplate)
: templatedUrl
})()
: chain.rpcUrls.default.http[0]

if (projectAccessKey && resolvedNodesUrl && isSequenceNodeUrl(resolvedNodesUrl)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { createConnector, type Connector } from 'wagmi'

import { LocalStorageKey } from '../../constants/localStorage.js'
import type { EthAuthSettings } from '../../types.js'
import { normalizeSequenceNodesUrl } from '../../utils/helpers.js'
import { getNetwork } from '../../utils/networks.js'
import { SEQUENCE_VALUE_FORWARDER } from '../../utils/session/constants.js'
import { createContractPermission, createExplicitSessionConfig } from '../../utils/session/index.js'
Expand Down Expand Up @@ -94,14 +95,16 @@ export function sequenceV3Wallet(params: BaseSequenceV3ConnectorOptions) {
[LocalStorageKey.V3ActiveLoginType]: string
}

const normalizedNodesUrl = normalizeSequenceNodesUrl(params.nodesUrl)

const client = new DappClient(params.walletUrl, params.dappOrigin, params.projectAccessKey, {
nodesUrl: params.nodesUrl,
nodesUrl: normalizedNodesUrl,
relayerUrl: params.relayerUrl
})
const provider = new SequenceV3Provider(
client,
params.defaultNetwork,
params.nodesUrl,
normalizedNodesUrl,
params.projectAccessKey,
params.loginType,
params.explicitSessionParams ? createExplicitSessionConfig(params.explicitSessionParams) : undefined,
Expand Down Expand Up @@ -269,7 +272,7 @@ export class SequenceV3Provider implements EIP1193Provider {
constructor(
private client: DappClient,
defaultNetwork: number,
nodesUrl = 'https://nodes.sequence.app',
nodesUrl = 'https://nodes.sequence.app/{network}',
projectAccessKey: string,
loginType?: SequenceV3LoginType,
initialSessionConfig?: ExplicitSessionConfig,
Expand Down Expand Up @@ -703,7 +706,15 @@ const getRpcUrl = (nodesUrl: string, projectAccessKey: string, networkName: stri
let url = applyTemplate(nodesUrl, { network: networkName })

if (nodesUrl.includes('sequence')) {
url = `${url}/${projectAccessKey}`
const cleanUrl = url.endsWith('/') ? url.slice(0, -1) : url
const hasTemplate = nodesUrl.includes('{network}')
const withNetwork = hasTemplate ? cleanUrl : `${cleanUrl}/${networkName}`

if (withNetwork.endsWith(`/${projectAccessKey}`)) {
return withNetwork
}

url = `${withNetwork}/${projectAccessKey}`
}

return url
Expand Down
29 changes: 29 additions & 0 deletions packages/connect/src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,32 @@ export const normalizeChainId = (chainId: string | number | bigint | { chainId:
}
return chainId
}

export const isSequenceUrl = (url?: string): url is string => {
return !!url && url.includes('sequence.app')
}

export const normalizeSequenceNodesUrl = (nodesUrl?: string) => {
if (!nodesUrl) {
return nodesUrl
}

const cleanUrl = nodesUrl.endsWith('/') ? nodesUrl.slice(0, -1) : nodesUrl

if (!isSequenceUrl(cleanUrl)) {
return cleanUrl
}

if (cleanUrl.includes('{network}')) {
return cleanUrl
}

const pathSegments = cleanUrl.split('/').filter(Boolean)
const hasPathBeyondHost = pathSegments.length > 2

if (hasPathBeyondHost) {
throw new Error('Invalid nodesUrl: Sequence nodesUrl must be a bare host or include "{network}".')
}

return `${cleanUrl}/{network}`
}
Loading