Skip to content

Commit 93f15ec

Browse files
CP-13448 - Injected Provider Demo (#3645)
1 parent 84121e5 commit 93f15ec

File tree

11 files changed

+1897
-4
lines changed

11 files changed

+1897
-4
lines changed

docs/injected-provider/working_demo.md

Lines changed: 421 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
import { buildEvmProviderShim } from './evmProviderShim'
2+
3+
describe('buildEvmProviderShim', () => {
4+
const defaultParams = {
5+
chainId: '0xa86a',
6+
address: '0x1234567890abcdef1234567890abcdef12345678'
7+
}
8+
9+
it('returns a non-empty string', () => {
10+
const shim = buildEvmProviderShim(defaultParams)
11+
expect(typeof shim).toBe('string')
12+
expect(shim.length).toBeGreaterThan(0)
13+
})
14+
15+
it('wraps the code in an IIFE', () => {
16+
const shim = buildEvmProviderShim(defaultParams)
17+
expect(shim.trimStart()).toMatch(/^\(function\(\)/)
18+
expect(shim.trimEnd()).toMatch(/\}\)\(\);$/)
19+
})
20+
21+
describe('embedded values', () => {
22+
it('embeds the chain ID', () => {
23+
const shim = buildEvmProviderShim(defaultParams)
24+
expect(shim).toContain("var _chainId = '0xa86a'")
25+
})
26+
27+
it('embeds the address', () => {
28+
const shim = buildEvmProviderShim(defaultParams)
29+
expect(shim).toContain(
30+
"var _address = '0x1234567890abcdef1234567890abcdef12345678'"
31+
)
32+
})
33+
34+
it('embeds a different chain ID when provided', () => {
35+
const shim = buildEvmProviderShim({
36+
chainId: '0x1',
37+
address: defaultParams.address
38+
})
39+
expect(shim).toContain("var _chainId = '0x1'")
40+
expect(shim).not.toContain("var _chainId = '0xa86a'")
41+
})
42+
43+
it('embeds an empty address when not provided', () => {
44+
const shim = buildEvmProviderShim({ chainId: '0xa86a', address: '' })
45+
expect(shim).toContain("var _address = ''")
46+
})
47+
})
48+
49+
describe('pre-connected state', () => {
50+
it('sets _connected to true when address is provided', () => {
51+
const shim = buildEvmProviderShim(defaultParams)
52+
expect(shim).toContain('var _connected = !!_address')
53+
})
54+
55+
it('initializes _accounts from _address', () => {
56+
const shim = buildEvmProviderShim(defaultParams)
57+
expect(shim).toContain('var _accounts = _address ? [_address] : []')
58+
})
59+
})
60+
61+
describe('EIP-1193 provider object', () => {
62+
let shim: string
63+
64+
beforeAll(() => {
65+
shim = buildEvmProviderShim(defaultParams)
66+
})
67+
68+
it('sets isMetaMask flag', () => {
69+
expect(shim).toContain('isMetaMask: true')
70+
})
71+
72+
it('sets isCore flag', () => {
73+
expect(shim).toContain('isCore: true')
74+
})
75+
76+
it('sets isAvalanche flag', () => {
77+
expect(shim).toContain('isAvalanche: true')
78+
})
79+
80+
it('implements request method', () => {
81+
expect(shim).toContain('request: function(args)')
82+
})
83+
84+
it('implements isConnected method', () => {
85+
expect(shim).toContain('isConnected: function()')
86+
})
87+
})
88+
89+
describe('local RPC methods handled in shim', () => {
90+
let shim: string
91+
92+
beforeAll(() => {
93+
shim = buildEvmProviderShim(defaultParams)
94+
})
95+
96+
it.each([
97+
'eth_chainId',
98+
'eth_accounts',
99+
'net_version',
100+
'eth_coinbase',
101+
'eth_requestAccounts',
102+
'wallet_requestPermissions',
103+
'wallet_getPermissions'
104+
])('handles %s locally', method => {
105+
expect(shim).toContain(`method === '${method}'`)
106+
})
107+
})
108+
109+
describe('legacy method support', () => {
110+
let shim: string
111+
112+
beforeAll(() => {
113+
shim = buildEvmProviderShim(defaultParams)
114+
})
115+
116+
it('implements enable()', () => {
117+
expect(shim).toContain('enable: function()')
118+
})
119+
120+
it('implements send()', () => {
121+
expect(shim).toContain('send: function(methodOrPayload')
122+
})
123+
124+
it('implements sendAsync()', () => {
125+
expect(shim).toContain('sendAsync: function(payload, callback)')
126+
})
127+
})
128+
129+
describe('event emitter', () => {
130+
let shim: string
131+
132+
beforeAll(() => {
133+
shim = buildEvmProviderShim(defaultParams)
134+
})
135+
136+
it('implements on()', () => {
137+
expect(shim).toContain('on: function(event, fn)')
138+
})
139+
140+
it('implements removeListener()', () => {
141+
expect(shim).toContain('removeListener: function(event, fn)')
142+
})
143+
144+
it('implements removeAllListeners()', () => {
145+
expect(shim).toContain('removeAllListeners: function(event)')
146+
})
147+
})
148+
149+
describe('global provider installation', () => {
150+
let shim: string
151+
152+
beforeAll(() => {
153+
shim = buildEvmProviderShim(defaultParams)
154+
})
155+
156+
it('installs window.ethereum via Object.defineProperty', () => {
157+
expect(shim).toContain("Object.defineProperty(window, 'ethereum'")
158+
})
159+
160+
it('installs window.core via Object.defineProperty', () => {
161+
expect(shim).toContain("Object.defineProperty(window, 'core'")
162+
})
163+
164+
it('installs window.avalanche via Object.defineProperty', () => {
165+
expect(shim).toContain("Object.defineProperty(window, 'avalanche'")
166+
})
167+
168+
it('makes properties non-configurable', () => {
169+
expect(shim).toContain('configurable: false')
170+
})
171+
172+
it('includes a no-op setter to prevent overrides', () => {
173+
expect(shim).toContain('set: function() {}')
174+
})
175+
})
176+
177+
describe('EIP-6963 announcement', () => {
178+
let shim: string
179+
180+
beforeAll(() => {
181+
shim = buildEvmProviderShim(defaultParams)
182+
})
183+
184+
it('dispatches eip6963:announceProvider event', () => {
185+
expect(shim).toContain('eip6963:announceProvider')
186+
})
187+
188+
it('listens for eip6963:requestProvider event', () => {
189+
expect(shim).toContain('eip6963:requestProvider')
190+
})
191+
192+
it('uses rdns app.core.mobile', () => {
193+
expect(shim).toContain("rdns: 'app.core.mobile'")
194+
})
195+
196+
it('sets provider name to Core', () => {
197+
expect(shim).toContain("name: 'Core'")
198+
})
199+
200+
it('includes a base64 SVG icon', () => {
201+
expect(shim).toContain("icon: 'data:image/svg+xml;base64,")
202+
})
203+
})
204+
205+
describe('injection guards', () => {
206+
let shim: string
207+
208+
beforeAll(() => {
209+
shim = buildEvmProviderShim(defaultParams)
210+
})
211+
212+
it('includes doctypeCheck', () => {
213+
expect(shim).toContain('function doctypeCheck()')
214+
})
215+
216+
it('includes suffixCheck for xml and pdf', () => {
217+
expect(shim).toContain('function suffixCheck()')
218+
expect(shim).toContain("'xml'")
219+
expect(shim).toContain("'pdf'")
220+
})
221+
222+
it('includes documentElementCheck', () => {
223+
expect(shim).toContain('function documentElementCheck()')
224+
})
225+
226+
it('early returns if guards fail', () => {
227+
expect(shim).toContain(
228+
'if (!doctypeCheck() || !suffixCheck() || !documentElementCheck()) return'
229+
)
230+
})
231+
})
232+
233+
describe('native bridge', () => {
234+
let shim: string
235+
236+
beforeAll(() => {
237+
shim = buildEvmProviderShim(defaultParams)
238+
})
239+
240+
it('defines __coreProviderRespond on window', () => {
241+
expect(shim).toContain('window.__coreProviderRespond = function(id')
242+
})
243+
244+
it('defines __coreProviderEmit on window', () => {
245+
expect(shim).toContain('window.__coreProviderEmit = function(eventName')
246+
})
247+
248+
it('uses safeSend wrapper for postMessage', () => {
249+
expect(shim).toContain('function safeSend(msg)')
250+
expect(shim).toContain('window.ReactNativeWebView')
251+
})
252+
253+
it('sends domain_metadata message', () => {
254+
expect(shim).toContain("method: 'domain_metadata'")
255+
})
256+
257+
it('sends provider_request messages', () => {
258+
expect(shim).toContain("method: 'provider_request'")
259+
})
260+
})
261+
262+
describe('legacy event dispatch', () => {
263+
it('dispatches ethereum#initialized event', () => {
264+
const shim = buildEvmProviderShim(defaultParams)
265+
expect(shim).toContain("new Event('ethereum#initialized')")
266+
})
267+
})
268+
269+
describe('auto-connect event firing', () => {
270+
it('auto-fires connect event on listener attachment', () => {
271+
const shim = buildEvmProviderShim(defaultParams)
272+
expect(shim).toContain("event === 'connect'")
273+
expect(shim).toContain('fn({ chainId: _chainId })')
274+
})
275+
276+
it('auto-fires accountsChanged event on listener attachment', () => {
277+
const shim = buildEvmProviderShim(defaultParams)
278+
expect(shim).toContain("event === 'accountsChanged'")
279+
expect(shim).toContain('fn(_accounts.slice())')
280+
})
281+
})
282+
})

0 commit comments

Comments
 (0)