Skip to content

Commit ff183f2

Browse files
committed
Fixed vendor
1 parent 9e04f4e commit ff183f2

72 files changed

Lines changed: 32510 additions & 31 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

web/src/simplicity/lwk.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,13 @@
33
* Only the address / serialization helpers are still used by the Wallet ABI web flow.
44
*/
55

6-
let lwkInit: Promise<typeof import('lwk_web')> | null = null
6+
let lwkInit: Promise<typeof import('wallet-abi-sdk-alpha/vendor')> | null = null
77

8-
function getWasmUrl(): string {
9-
if (import.meta.env.DEV) return '/lwk_wasm_bg.wasm'
10-
return `${import.meta.env.BASE_URL}assets/lwk_wasm_bg.wasm`
11-
}
12-
13-
export async function getLwk(): Promise<typeof import('lwk_web')> {
8+
export async function getLwk(): Promise<typeof import('wallet-abi-sdk-alpha/vendor')> {
149
if (!lwkInit) {
1510
lwkInit = (async () => {
16-
const lwk = await import('lwk_web')
17-
if (typeof lwk.default === 'function') await lwk.default(getWasmUrl())
11+
const lwk = await import('wallet-abi-sdk-alpha/vendor')
12+
if (typeof lwk.default === 'function') await lwk.default()
1813
return lwk
1914
})()
2015
}

web/src/walletAbi/WalletAbiSessionContext.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* eslint-disable react-refresh/only-export-components */
2+
13
import {
24
createContext,
35
useContext,
@@ -44,6 +46,7 @@ export interface WalletAbiSessionValue {
4446
}
4547

4648
const REQUEST_TIMEOUT_MS = 300_000
49+
const SESSION_IDENTITY_REQUEST_TIMEOUT_MS = 15_000
4750
const WalletAbiSessionContext = createContext<WalletAbiSessionValue | null>(null)
4851

4952
function errorMessage(error: unknown): string {
@@ -141,6 +144,13 @@ export function WalletAbiSessionProvider({ children }: PropsWithChildren) {
141144
return nextClient
142145
}
143146

147+
const createIdentityClient = (controller: WalletAbiSessionController): WalletAbiClient => {
148+
return new WalletAbiClient({
149+
requester: buildRequester(controller),
150+
requestTimeoutMs: SESSION_IDENTITY_REQUEST_TIMEOUT_MS,
151+
})
152+
}
153+
144154
const getController = async (): Promise<WalletAbiSessionController> => {
145155
if (reownProjectId.length === 0) {
146156
throw new Error('Missing VITE_REOWN_PROJECT_ID')
@@ -158,7 +168,7 @@ export function WalletAbiSessionProvider({ children }: PropsWithChildren) {
158168
const nextControllerPromise = createWalletAbiSessionController({
159169
projectId: reownProjectId,
160170
network: walletAbiNetwork,
161-
origin: window.location.origin,
171+
appUrl: window.location.href,
162172
}).then((controller) => {
163173
controllerRef.current = controller
164174
return controller
@@ -174,9 +184,10 @@ export function WalletAbiSessionProvider({ children }: PropsWithChildren) {
174184
}
175185

176186
const hydrateSession = async (controller: WalletAbiSessionController): Promise<WalletAbiClient> => {
187+
const identityClient = createIdentityClient(controller)
177188
const client = getClient(controller)
178-
const nextAddress = await client.getSignerReceiveAddress()
179-
const nextPubkey = await client.getRawSigningXOnlyPubkey()
189+
const nextAddress = await identityClient.getSignerReceiveAddress()
190+
const nextPubkey = await identityClient.getRawSigningXOnlyPubkey()
180191
const nextScript = await getScriptPubkeyHexFromAddress(nextAddress)
181192

182193
setSignerReceiveAddress(nextAddress)
@@ -238,6 +249,8 @@ export function WalletAbiSessionProvider({ children }: PropsWithChildren) {
238249
rememberWalletScript(signingXOnlyPubkey, network, signerScriptPubkeyHex)
239250
}, [network, signerScriptPubkeyHex, signingXOnlyPubkey])
240251

252+
// This effect should only rebind the controller when the project id or target network changes.
253+
// The helper functions close over refs/state and are intentionally not dependency drivers here.
241254
useEffect(() => {
242255
let cancelled = false
243256
let unsubscribe: (() => void) | undefined
@@ -294,7 +307,7 @@ export function WalletAbiSessionProvider({ children }: PropsWithChildren) {
294307
cancelled = true
295308
unsubscribe?.()
296309
}
297-
}, [reownProjectId, walletAbiNetwork])
310+
}, [reownProjectId, walletAbiNetwork]) // eslint-disable-line react-hooks/exhaustive-deps
298311

299312
const value: WalletAbiSessionValue = {
300313
status,

web/src/walletAbi/walletConnectSession.test.ts

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import { EventEmitter } from 'node:events'
12
import { describe, expect, it } from 'vitest'
2-
import type { SessionTypes } from '@walletconnect/types'
3+
import type { SessionTypes, SignClientTypes } from '@walletconnect/types'
34
import {
5+
awaitWalletAbiApprovedSession,
46
createWalletAbiCaipNetwork,
7+
createWalletAbiMetadata,
58
resolveWalletAbiNetwork,
69
selectWalletAbiSessions,
710
} from './walletConnectSession'
@@ -69,6 +72,40 @@ function sessionWith({
6972
}
7073
}
7174

75+
function createMockApprovalSignClient(initialSessions: SessionTypes.Struct[] = []) {
76+
const emitter = new EventEmitter()
77+
const sessions = [...initialSessions]
78+
79+
return {
80+
signClient: {
81+
session: {
82+
getAll() {
83+
return [...sessions]
84+
},
85+
},
86+
on(
87+
event: 'session_connect',
88+
listener: (event: SignClientTypes.EventArguments['session_connect']) => void
89+
) {
90+
emitter.on(event, listener)
91+
},
92+
off(
93+
event: 'session_connect',
94+
listener: (event: SignClientTypes.EventArguments['session_connect']) => void
95+
) {
96+
emitter.off(event, listener)
97+
},
98+
},
99+
addSession(session: SessionTypes.Struct) {
100+
sessions.unshift(session)
101+
},
102+
emitSessionConnect(session: SessionTypes.Struct) {
103+
sessions.unshift(session)
104+
emitter.emit('session_connect', { session })
105+
},
106+
}
107+
}
108+
72109
describe('walletConnectSession', () => {
73110
it('keeps the newest wallet_abi session and marks older ones as stale', () => {
74111
const chainId = 'walabi:testnet-liquid'
@@ -105,6 +142,96 @@ describe('walletConnectSession', () => {
105142
expect(resolveWalletAbiNetwork('unsupported-network')).toBe('testnet-liquid')
106143
})
107144

145+
it('includes a redirect target in WalletConnect metadata for mobile handoff', () => {
146+
expect(createWalletAbiMetadata('https://app.example/connect?wallet=green')).toEqual({
147+
name: 'Simplicity Lending',
148+
description: 'Wallet ABI WalletConnect session for the Simplicity Lending web app.',
149+
url: 'https://app.example/connect?wallet=green',
150+
icons: ['https://app.example/vite.svg'],
151+
redirect: {
152+
universal: 'https://app.example/connect?wallet=green',
153+
},
154+
})
155+
})
156+
157+
it('accepts session_connect as a fallback when approval does not settle', async () => {
158+
const chainId = 'walabi:testnet-liquid'
159+
const { signClient, emitSessionConnect } = createMockApprovalSignClient()
160+
const connectedSession = sessionWith({
161+
topic: 'connected',
162+
expiry: 50,
163+
chainId,
164+
})
165+
166+
const approval = awaitWalletAbiApprovedSession({
167+
approval: () => new Promise(() => undefined),
168+
signClient,
169+
chainId,
170+
connectTimeoutMs: 500,
171+
sessionPollMs: 5,
172+
})
173+
174+
setTimeout(() => {
175+
emitSessionConnect(connectedSession)
176+
}, 10)
177+
178+
await expect(approval).resolves.toMatchObject({
179+
topic: 'connected',
180+
})
181+
})
182+
183+
it('falls back to the stored session when approval rejects after the wallet settles', async () => {
184+
const chainId = 'walabi:testnet-liquid'
185+
const { signClient, addSession } = createMockApprovalSignClient()
186+
const settledSession = sessionWith({
187+
topic: 'settled',
188+
expiry: 60,
189+
chainId,
190+
})
191+
192+
const approval = awaitWalletAbiApprovedSession({
193+
approval: async () => {
194+
setTimeout(() => {
195+
addSession(settledSession)
196+
}, 10)
197+
throw new Error('approval promise failed')
198+
},
199+
signClient,
200+
chainId,
201+
connectTimeoutMs: 500,
202+
approvalRejectionGraceMs: 50,
203+
sessionPollMs: 5,
204+
})
205+
206+
await expect(approval).resolves.toMatchObject({
207+
topic: 'settled',
208+
})
209+
})
210+
211+
it('does not treat a stored session as approved before approval settles', async () => {
212+
const chainId = 'walabi:testnet-liquid'
213+
const { signClient, addSession } = createMockApprovalSignClient()
214+
const storedSession = sessionWith({
215+
topic: 'stored-only',
216+
expiry: 70,
217+
chainId,
218+
})
219+
220+
const approval = awaitWalletAbiApprovedSession({
221+
approval: () => new Promise(() => undefined),
222+
signClient,
223+
chainId,
224+
connectTimeoutMs: 50,
225+
sessionPollMs: 5,
226+
})
227+
228+
setTimeout(() => {
229+
addSession(storedSession)
230+
}, 10)
231+
232+
await expect(approval).rejects.toThrow('WalletConnect session approval timed out')
233+
})
234+
108235
it('infers wallet abi networks from Liquid address prefixes', () => {
109236
expect(
110237
inferWalletAbiNetworkFromAddress(

0 commit comments

Comments
 (0)