@marigoldlabs/web3-tester 0.1.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +26 -17
- package/LICENSE +21 -0
- package/README.md +167 -41
- package/dist/anvil.d.ts +90 -2
- package/dist/anvil.d.ts.map +1 -1
- package/dist/anvil.js +215 -13
- package/dist/anvil.js.map +1 -1
- package/dist/contracts/test-erc20.d.ts +227 -0
- package/dist/contracts/test-erc20.d.ts.map +1 -0
- package/dist/contracts/test-erc20.js +8 -0
- package/dist/contracts/test-erc20.js.map +1 -0
- package/dist/erc20.d.ts +38 -0
- package/dist/erc20.d.ts.map +1 -0
- package/dist/erc20.js +229 -0
- package/dist/erc20.js.map +1 -0
- package/dist/fixtures.d.ts +44 -2
- package/dist/fixtures.d.ts.map +1 -1
- package/dist/fixtures.js +162 -17
- package/dist/fixtures.js.map +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/injected-provider.d.ts.map +1 -1
- package/dist/injected-provider.js +142 -79
- package/dist/injected-provider.js.map +1 -1
- package/dist/live-fixtures.d.ts +32 -3
- package/dist/live-fixtures.d.ts.map +1 -1
- package/dist/live-fixtures.js +64 -27
- package/dist/live-fixtures.js.map +1 -1
- package/dist/matchers.d.ts +90 -0
- package/dist/matchers.d.ts.map +1 -0
- package/dist/matchers.js +268 -0
- package/dist/matchers.js.map +1 -0
- package/dist/metamask-extension.d.ts +34 -0
- package/dist/metamask-extension.d.ts.map +1 -0
- package/dist/metamask-extension.js +97 -0
- package/dist/metamask-extension.js.map +1 -0
- package/dist/mock-wallet-controller.d.ts +205 -3
- package/dist/mock-wallet-controller.d.ts.map +1 -1
- package/dist/mock-wallet-controller.js +843 -46
- package/dist/mock-wallet-controller.js.map +1 -1
- package/dist/private-key-rpc-client.d.ts +1730 -0
- package/dist/private-key-rpc-client.d.ts.map +1 -1
- package/dist/private-key-rpc-client.js +105 -12
- package/dist/private-key-rpc-client.js.map +1 -1
- package/dist/real-wallet-cache.d.ts +65 -0
- package/dist/real-wallet-cache.d.ts.map +1 -0
- package/dist/real-wallet-cache.js +245 -0
- package/dist/real-wallet-cache.js.map +1 -0
- package/dist/real-wallet-fixtures.d.ts +52 -0
- package/dist/real-wallet-fixtures.d.ts.map +1 -0
- package/dist/real-wallet-fixtures.js +73 -0
- package/dist/real-wallet-fixtures.js.map +1 -0
- package/dist/real-wallet.d.ts +123 -14
- package/dist/real-wallet.d.ts.map +1 -1
- package/dist/real-wallet.js +1336 -57
- package/dist/real-wallet.js.map +1 -1
- package/dist/transactions.d.ts +118 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/transactions.js +207 -0
- package/dist/transactions.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/walletconnect.d.ts +206 -0
- package/dist/walletconnect.d.ts.map +1 -0
- package/dist/walletconnect.js +359 -0
- package/dist/walletconnect.js.map +1 -0
- package/examples/live-sepolia.spec.ts +20 -1
- package/package.json +62 -6
- package/docs/API.md +0 -223
- package/docs/ARCHITECTURE.md +0 -81
- package/docs/CONSUMING_FROM_FJORD.md +0 -123
- package/docs/FJORD_LIVE_QA.md +0 -87
- package/docs/RELEASE_CHECKLIST.md +0 -55
package/dist/matchers.js
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { expect as baseExpect, } from '@playwright/test';
|
|
2
|
+
import { erc20Abi, parseEventLogs } from 'viem';
|
|
3
|
+
import { describePanic, extractRevertInfo, isWalletRejectionError, recoverRevertInfo, renderRevertInfo, resolveClient, resolveTxHash, web3Equals, web3Stringify, } from './transactions.js';
|
|
4
|
+
/** hardhat-chai-matchers `anyValue` parity for arg wildcards. */
|
|
5
|
+
export const anyValue = (_value) => true;
|
|
6
|
+
const ADDRESS_PATTERN = /^0x[0-9a-fA-F]{40}$/;
|
|
7
|
+
const toBigInt = (value) => typeof value === 'bigint' ? value : BigInt(value);
|
|
8
|
+
const badReceiver = (state, name, received) => ({
|
|
9
|
+
pass: false,
|
|
10
|
+
message: () => `${state.utils.matcherHint(name, undefined, undefined, { isNot: state.isNot })}\n\n` +
|
|
11
|
+
`Received value is not a transaction hash (or { hash }): ${web3Stringify(received)}`,
|
|
12
|
+
});
|
|
13
|
+
const eventArgsMatch = (logArgs, expectation, abi, eventName) => {
|
|
14
|
+
if (Array.isArray(expectation)) {
|
|
15
|
+
const positional = Array.isArray(logArgs)
|
|
16
|
+
? [...logArgs]
|
|
17
|
+
: (() => {
|
|
18
|
+
const event = abi.find((entry) => entry.type === 'event' && 'name' in entry && entry.name === eventName);
|
|
19
|
+
return (event?.inputs ?? []).map((input, index) => input.name
|
|
20
|
+
? logArgs[input.name]
|
|
21
|
+
: logArgs[index]);
|
|
22
|
+
})();
|
|
23
|
+
return expectation.every((expected, index) => expected === undefined || web3Equals(expected, positional[index]));
|
|
24
|
+
}
|
|
25
|
+
const named = (logArgs ?? {});
|
|
26
|
+
return Object.entries(expectation).every(([key, expected]) => web3Equals(expected, named[key]));
|
|
27
|
+
};
|
|
28
|
+
// Resolves a revert-family receiver into a uniform shape; wallet approval
|
|
29
|
+
// failures are rethrown with a hint instead of counting as reverts.
|
|
30
|
+
const resolveRevertReceiver = async (target, client, timeout, abi) => {
|
|
31
|
+
let resolved;
|
|
32
|
+
try {
|
|
33
|
+
resolved = typeof target === 'function' ? await target() : await target;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (isWalletRejectionError(error)) {
|
|
37
|
+
throw new Error(`The wallet rejected the request — a wallet approval failure, not a chain revert: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
38
|
+
}
|
|
39
|
+
const info = extractRevertInfo(error, abi);
|
|
40
|
+
if (!info) {
|
|
41
|
+
throw new Error(`The call rejected with a non-revert error: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
42
|
+
}
|
|
43
|
+
return { outcome: 'reverted', info };
|
|
44
|
+
}
|
|
45
|
+
const hash = await resolveTxHash(resolved);
|
|
46
|
+
if (!hash) {
|
|
47
|
+
return {
|
|
48
|
+
outcome: 'succeeded',
|
|
49
|
+
detail: `the call succeeded and resolved to ${web3Stringify(resolved)}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const receipt = await client.waitForTransactionReceipt({ hash, timeout });
|
|
53
|
+
if (receipt.status === 'success') {
|
|
54
|
+
return {
|
|
55
|
+
outcome: 'succeeded',
|
|
56
|
+
detail: `transaction ${hash} succeeded (gasUsed ${receipt.gasUsed})`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
outcome: 'reverted',
|
|
61
|
+
info: await recoverRevertInfo(client, hash, receipt, abi),
|
|
62
|
+
gasUsed: receipt.gasUsed,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
const balanceChangeMatcher = async (state, name, target, chain, changes, options, readBalance, feeAdjustable) => {
|
|
66
|
+
const client = resolveClient(chain);
|
|
67
|
+
const hash = await resolveTxHash(target);
|
|
68
|
+
if (!hash) {
|
|
69
|
+
return badReceiver(state, name, await target);
|
|
70
|
+
}
|
|
71
|
+
const receipt = await client.waitForTransactionReceipt({
|
|
72
|
+
hash,
|
|
73
|
+
timeout: options.timeout ?? state.timeout,
|
|
74
|
+
});
|
|
75
|
+
const observed = [];
|
|
76
|
+
for (const change of changes) {
|
|
77
|
+
const after = await readBalance(client, change.address, receipt.blockNumber);
|
|
78
|
+
const before = await readBalance(client, change.address, receipt.blockNumber - 1n);
|
|
79
|
+
let delta = after - before;
|
|
80
|
+
// hardhat parity: the sender's gas fee is excluded unless includeFee.
|
|
81
|
+
if (feeAdjustable &&
|
|
82
|
+
!options.includeFee &&
|
|
83
|
+
change.address.toLowerCase() === receipt.from.toLowerCase()) {
|
|
84
|
+
delta += receipt.gasUsed * receipt.effectiveGasPrice;
|
|
85
|
+
}
|
|
86
|
+
observed.push({ address: change.address, expected: toBigInt(change.delta), actual: delta });
|
|
87
|
+
}
|
|
88
|
+
const pass = observed.every((entry) => entry.expected === entry.actual);
|
|
89
|
+
const message = async () => {
|
|
90
|
+
const lines = observed.map((entry) => ` ${entry.address}: expected ${entry.expected}, observed ${entry.actual}${entry.expected === entry.actual ? '' : ' ←'}`);
|
|
91
|
+
const block = await client.getBlock({ blockNumber: receipt.blockNumber }).catch(() => undefined);
|
|
92
|
+
const crowded = block && block.transactions.length > 1
|
|
93
|
+
? `\n${block.transactions.length - 1} other transaction(s) share this block and may also have moved balances.`
|
|
94
|
+
: '';
|
|
95
|
+
return (`${state.utils.matcherHint(name, undefined, undefined, { isNot: state.isNot })}\n\n` +
|
|
96
|
+
`Transaction ${hash} (block ${receipt.blockNumber}):\n${lines.join('\n')}${crowded}`);
|
|
97
|
+
};
|
|
98
|
+
const rendered = await message();
|
|
99
|
+
return {
|
|
100
|
+
pass,
|
|
101
|
+
message: () => rendered,
|
|
102
|
+
expected: observed.map((entry) => `${entry.address}: ${entry.expected}`),
|
|
103
|
+
actual: observed.map((entry) => `${entry.address}: ${entry.actual}`),
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
const erc20Balance = (token) => async (client, address, blockNumber) => (await client.readContract({
|
|
107
|
+
address: token,
|
|
108
|
+
abi: erc20Abi,
|
|
109
|
+
functionName: 'balanceOf',
|
|
110
|
+
args: [address],
|
|
111
|
+
blockNumber,
|
|
112
|
+
}));
|
|
113
|
+
export const web3Matchers = {
|
|
114
|
+
async toEmitEvent(target, chain, abi, eventName, options = {}) {
|
|
115
|
+
const client = resolveClient(chain);
|
|
116
|
+
const hash = await resolveTxHash(target);
|
|
117
|
+
if (!hash) {
|
|
118
|
+
return badReceiver(this, 'toEmitEvent', await target);
|
|
119
|
+
}
|
|
120
|
+
const receipt = await client.waitForTransactionReceipt({
|
|
121
|
+
hash,
|
|
122
|
+
timeout: options.timeout ?? this.timeout,
|
|
123
|
+
});
|
|
124
|
+
const decoded = parseEventLogs({ abi, logs: receipt.logs, strict: false });
|
|
125
|
+
// parseEventLogs silently drops foreign-topic0 logs; surface them by diff.
|
|
126
|
+
const decodedIndexes = new Set(decoded.map((log) => log.logIndex));
|
|
127
|
+
const undecodable = receipt.logs.filter((log) => !decodedIndexes.has(log.logIndex));
|
|
128
|
+
let candidates = decoded.filter((log) => log.eventName === eventName);
|
|
129
|
+
if (options.address) {
|
|
130
|
+
candidates = candidates.filter((log) => log.address.toLowerCase() === options.address.toLowerCase());
|
|
131
|
+
}
|
|
132
|
+
const matching = options.args === undefined
|
|
133
|
+
? candidates
|
|
134
|
+
: candidates.filter((log) => eventArgsMatch(log.args, options.args, abi, eventName));
|
|
135
|
+
const pass = options.count !== undefined ? matching.length === options.count : matching.length >= 1;
|
|
136
|
+
const emitted = decoded.map((log) => ` ${log.eventName}(${web3Stringify(log.args).replace(/\n\s*/g, ' ')}) @ ${log.address}`);
|
|
137
|
+
const extras = undecodable.map((log) => ` <undecodable> topic0=${log.topics[0]} @ ${log.address}`);
|
|
138
|
+
const revertedNote = receipt.status !== 'success'
|
|
139
|
+
? '\nThe transaction REVERTED — reverted transactions emit no events.'
|
|
140
|
+
: '';
|
|
141
|
+
return {
|
|
142
|
+
pass,
|
|
143
|
+
message: () => `${this.utils.matcherHint('toEmitEvent', undefined, eventName, { isNot: this.isNot })}\n\n` +
|
|
144
|
+
`Expected ${options.count !== undefined ? `exactly ${options.count}` : 'at least one'} ` +
|
|
145
|
+
`"${eventName}" event${options.args ? ` with args ${web3Stringify(options.args)}` : ''}; ` +
|
|
146
|
+
`found ${matching.length}.${revertedNote}\n` +
|
|
147
|
+
`Events in receipt:\n${[...emitted, ...extras].join('\n') || ' (none)'}`,
|
|
148
|
+
expected: options.args,
|
|
149
|
+
actual: candidates.map((log) => log.args),
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
async toChangeBalance(target, chain, address, delta, options = {}) {
|
|
153
|
+
return balanceChangeMatcher(this, 'toChangeBalance', target, chain, [{ address, delta }], options, (client, holder, blockNumber) => client.getBalance({ address: holder, blockNumber }), true);
|
|
154
|
+
},
|
|
155
|
+
async toChangeBalances(target, chain, changes, options = {}) {
|
|
156
|
+
return balanceChangeMatcher(this, 'toChangeBalances', target, chain, changes, options, (client, holder, blockNumber) => client.getBalance({ address: holder, blockNumber }), true);
|
|
157
|
+
},
|
|
158
|
+
async toChangeTokenBalance(target, chain, token, address, delta, options = {}) {
|
|
159
|
+
return balanceChangeMatcher(this, 'toChangeTokenBalance', target, chain, [{ address, delta }], options, erc20Balance(token), false);
|
|
160
|
+
},
|
|
161
|
+
async toChangeTokenBalances(target, chain, token, changes, options = {}) {
|
|
162
|
+
return balanceChangeMatcher(this, 'toChangeTokenBalances', target, chain, changes, options, erc20Balance(token), false);
|
|
163
|
+
},
|
|
164
|
+
async toBeReverted(target, chain, options = {}) {
|
|
165
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, undefined);
|
|
166
|
+
return {
|
|
167
|
+
pass: result.outcome === 'reverted',
|
|
168
|
+
message: () => `${this.utils.matcherHint('toBeReverted', undefined, undefined, { isNot: this.isNot })}\n\n` +
|
|
169
|
+
(result.outcome === 'reverted'
|
|
170
|
+
? `Reverted with ${renderRevertInfo(result.info)}.`
|
|
171
|
+
: `Expected a revert, but ${result.detail}.`),
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
async toBeRevertedWith(target, chain, reason, options = {}) {
|
|
175
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, undefined);
|
|
176
|
+
let pass = false;
|
|
177
|
+
let detail;
|
|
178
|
+
if (result.outcome === 'succeeded') {
|
|
179
|
+
detail = `Expected a revert, but ${result.detail}.`;
|
|
180
|
+
}
|
|
181
|
+
else if (result.info.kind === 'reason') {
|
|
182
|
+
pass =
|
|
183
|
+
typeof reason === 'string' ? result.info.reason === reason : reason.test(result.info.reason);
|
|
184
|
+
detail = `Reverted with Error("${result.info.reason}").`;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
detail = `Reverted, but not with an Error(string): ${renderRevertInfo(result.info)}.`;
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
pass,
|
|
191
|
+
message: () => `${this.utils.matcherHint('toBeRevertedWith', undefined, String(reason), { isNot: this.isNot })}\n\n${detail}`,
|
|
192
|
+
expected: String(reason),
|
|
193
|
+
actual: result.outcome === 'reverted' ? renderRevertInfo(result.info) : 'success',
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
async toBeRevertedWithCustomError(target, chain, abi, errorName, options = {}) {
|
|
197
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, abi);
|
|
198
|
+
let pass = false;
|
|
199
|
+
let detail;
|
|
200
|
+
if (result.outcome === 'succeeded') {
|
|
201
|
+
detail = `Expected a revert, but ${result.detail}.`;
|
|
202
|
+
}
|
|
203
|
+
else if (result.info.kind === 'custom') {
|
|
204
|
+
pass =
|
|
205
|
+
result.info.errorName === errorName &&
|
|
206
|
+
(options.args === undefined ||
|
|
207
|
+
web3Equals([...options.args], [...(result.info.args ?? [])]));
|
|
208
|
+
detail = `Reverted with ${renderRevertInfo(result.info)}.`;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
detail = `Reverted, but not with a custom error: ${renderRevertInfo(result.info)}.`;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
pass,
|
|
215
|
+
message: () => `${this.utils.matcherHint('toBeRevertedWithCustomError', undefined, errorName, { isNot: this.isNot })}\n\n${detail}`,
|
|
216
|
+
expected: `${errorName}(${(options.args ?? []).map(String).join(', ')})`,
|
|
217
|
+
actual: result.outcome === 'reverted' ? renderRevertInfo(result.info) : 'success',
|
|
218
|
+
};
|
|
219
|
+
},
|
|
220
|
+
async toBeRevertedWithPanic(target, chain, code, options = {}) {
|
|
221
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, undefined);
|
|
222
|
+
let pass = false;
|
|
223
|
+
let detail;
|
|
224
|
+
if (result.outcome === 'succeeded') {
|
|
225
|
+
detail = `Expected a panic, but ${result.detail}.`;
|
|
226
|
+
}
|
|
227
|
+
else if (result.info.kind === 'panic') {
|
|
228
|
+
pass = code === undefined || BigInt(code) === result.info.code;
|
|
229
|
+
detail = `Reverted with ${renderRevertInfo(result.info)}.`;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
detail = `Reverted, but not with a Panic: ${renderRevertInfo(result.info)}.`;
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
pass,
|
|
236
|
+
message: () => `${this.utils.matcherHint('toBeRevertedWithPanic', undefined, code === undefined ? '' : `0x${BigInt(code).toString(16)} (${describePanic(BigInt(code))})`, { isNot: this.isNot })}\n\n${detail}`,
|
|
237
|
+
};
|
|
238
|
+
},
|
|
239
|
+
async toHaveTokenBalance(holder, chain, token, expected) {
|
|
240
|
+
// Address and tx-hash are both `0x${string}` — catch 32-byte receivers.
|
|
241
|
+
if (typeof holder !== 'string' || !ADDRESS_PATTERN.test(holder)) {
|
|
242
|
+
return {
|
|
243
|
+
pass: false,
|
|
244
|
+
message: () => `${this.utils.matcherHint('toHaveTokenBalance', undefined, undefined, { isNot: this.isNot })}\n\n` +
|
|
245
|
+
`Received value is not a 20-byte address: ${web3Stringify(holder)}`,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const client = resolveClient(chain);
|
|
249
|
+
const balance = (await client.readContract({
|
|
250
|
+
address: token,
|
|
251
|
+
abi: erc20Abi,
|
|
252
|
+
functionName: 'balanceOf',
|
|
253
|
+
args: [holder],
|
|
254
|
+
}));
|
|
255
|
+
const pass = typeof expected === 'function' ? Boolean(expected(balance)) : toBigInt(expected) === balance;
|
|
256
|
+
return {
|
|
257
|
+
pass,
|
|
258
|
+
message: () => `${this.utils.matcherHint('toHaveTokenBalance', undefined, undefined, { isNot: this.isNot })}\n\n` +
|
|
259
|
+
`Token ${token} balance of ${holder}: ${balance}` +
|
|
260
|
+
(typeof expected === 'function' ? ' (predicate)' : `, expected ${toBigInt(expected)}`),
|
|
261
|
+
expected: typeof expected === 'function' ? 'predicate' : toBigInt(expected).toString(),
|
|
262
|
+
actual: balance.toString(),
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
/** Pre-extended expect carrying every web3 matcher, fully typed. */
|
|
267
|
+
export const expect = baseExpect.extend(web3Matchers);
|
|
268
|
+
//# sourceMappingURL=matchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MetaMask build the adapter's selectors are maintained against. Bump
|
|
3
|
+
* deliberately and re-run the real-wallet smoke suite when changing it
|
|
4
|
+
* (`npm run smoke:real-wallet`).
|
|
5
|
+
*
|
|
6
|
+
* The adapter drives one UI generation per launch as explicit configuration
|
|
7
|
+
* (derived from the extension manifest, overridable via the `generation`
|
|
8
|
+
* option): 13.x (the "multichain" UI) is validated end to end and gates
|
|
9
|
+
* releases; the last 12.x line stays supported on a best-effort cadence. Set
|
|
10
|
+
* WEB3_TESTER_METAMASK_VERSION=12.23.1 to drive the older generation.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_METAMASK_VERSION = "13.34.1";
|
|
13
|
+
export type PrepareMetaMaskExtensionOptions = {
|
|
14
|
+
/** Release version, e.g. "13.34.1". Defaults to WEB3_TESTER_METAMASK_VERSION or the pinned default. */
|
|
15
|
+
version?: string;
|
|
16
|
+
/** Directory unpacked extensions are cached in. Defaults to ~/.cache/web3-tester/metamask. */
|
|
17
|
+
cacheDir?: string;
|
|
18
|
+
/** Full download URL override (e.g. an internal mirror). */
|
|
19
|
+
downloadUrl?: string;
|
|
20
|
+
/** Optional sha256 (hex) of the zip for integrity verification. */
|
|
21
|
+
sha256?: string;
|
|
22
|
+
/** Re-download even if a cached copy exists. */
|
|
23
|
+
force?: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare const defaultExtensionCacheDir: () => string;
|
|
26
|
+
/**
|
|
27
|
+
* Downloads and unpacks a pinned MetaMask release into a local cache and
|
|
28
|
+
* returns the unpacked extension directory, suitable for
|
|
29
|
+
* launchRealWallet({ extensionPath }). Subsequent calls hit the cache.
|
|
30
|
+
*/
|
|
31
|
+
export declare function prepareMetaMaskExtension(options?: PrepareMetaMaskExtensionOptions): Promise<string>;
|
|
32
|
+
/** Reads the version field of an unpacked extension's manifest.json. */
|
|
33
|
+
export declare function extensionManifestVersion(extensionPath: string): string;
|
|
34
|
+
//# sourceMappingURL=metamask-extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metamask-extension.d.ts","sourceRoot":"","sources":["../src/metamask-extension.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,YAAY,CAAC;AAElD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,uGAAuG;IACvG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAAO,MACkB,CAAC;AA0B/D;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAuDjB;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAOtE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { once } from 'node:events';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
/**
|
|
8
|
+
* The MetaMask build the adapter's selectors are maintained against. Bump
|
|
9
|
+
* deliberately and re-run the real-wallet smoke suite when changing it
|
|
10
|
+
* (`npm run smoke:real-wallet`).
|
|
11
|
+
*
|
|
12
|
+
* The adapter drives one UI generation per launch as explicit configuration
|
|
13
|
+
* (derived from the extension manifest, overridable via the `generation`
|
|
14
|
+
* option): 13.x (the "multichain" UI) is validated end to end and gates
|
|
15
|
+
* releases; the last 12.x line stays supported on a best-effort cadence. Set
|
|
16
|
+
* WEB3_TESTER_METAMASK_VERSION=12.23.1 to drive the older generation.
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_METAMASK_VERSION = '13.34.1';
|
|
19
|
+
export const defaultExtensionCacheDir = () => path.join(os.homedir(), '.cache', 'web3-tester', 'metamask');
|
|
20
|
+
const releaseUrl = (version) => `https://github.com/MetaMask/metamask-extension/releases/download/v${version}/metamask-chrome-${version}.zip`;
|
|
21
|
+
const unzip = async (zipPath, destination) => {
|
|
22
|
+
const [command, args] = process.platform === 'win32'
|
|
23
|
+
? [
|
|
24
|
+
'powershell.exe',
|
|
25
|
+
['-NoProfile', '-Command', `Expand-Archive -LiteralPath '${zipPath}' -DestinationPath '${destination}' -Force`],
|
|
26
|
+
]
|
|
27
|
+
: ['unzip', ['-o', '-q', zipPath, '-d', destination]];
|
|
28
|
+
const child = spawn(command, args, { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
29
|
+
let stderr = '';
|
|
30
|
+
child.stderr.on('data', (chunk) => {
|
|
31
|
+
stderr += chunk.toString();
|
|
32
|
+
});
|
|
33
|
+
const [code] = (await once(child, 'exit'));
|
|
34
|
+
if (code !== 0) {
|
|
35
|
+
throw new Error(`Failed to unzip MetaMask extension (${command} exited with ${code}).\n${stderr}`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Downloads and unpacks a pinned MetaMask release into a local cache and
|
|
40
|
+
* returns the unpacked extension directory, suitable for
|
|
41
|
+
* launchRealWallet({ extensionPath }). Subsequent calls hit the cache.
|
|
42
|
+
*/
|
|
43
|
+
export async function prepareMetaMaskExtension(options = {}) {
|
|
44
|
+
// `||` (not `??`): an empty env var (e.g. a workflow_dispatch input left
|
|
45
|
+
// blank) must fall through to the pinned default, not become version "".
|
|
46
|
+
const version = options.version || process.env.WEB3_TESTER_METAMASK_VERSION || DEFAULT_METAMASK_VERSION;
|
|
47
|
+
const cacheDir = options.cacheDir ?? defaultExtensionCacheDir();
|
|
48
|
+
const destination = path.join(cacheDir, `metamask-chrome-${version}`);
|
|
49
|
+
const manifestPath = path.join(destination, 'manifest.json');
|
|
50
|
+
if (!options.force && fs.existsSync(manifestPath)) {
|
|
51
|
+
return destination;
|
|
52
|
+
}
|
|
53
|
+
const url = options.downloadUrl ?? releaseUrl(version);
|
|
54
|
+
const response = await fetch(url);
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new Error(`Failed to download MetaMask ${version} from ${url}: HTTP ${response.status}. ` +
|
|
57
|
+
`Check the version exists (https://github.com/MetaMask/metamask-extension/releases) ` +
|
|
58
|
+
`or set WEB3_TESTER_METAMASK_VERSION / options.version.`);
|
|
59
|
+
}
|
|
60
|
+
const zipBytes = Buffer.from(await response.arrayBuffer());
|
|
61
|
+
if (options.sha256) {
|
|
62
|
+
const actual = createHash('sha256').update(zipBytes).digest('hex');
|
|
63
|
+
if (actual !== options.sha256.toLowerCase()) {
|
|
64
|
+
throw new Error(`MetaMask ${version} download failed integrity check: expected sha256 ${options.sha256}, got ${actual}.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
68
|
+
const zipPath = path.join(cacheDir, `metamask-chrome-${version}.zip`);
|
|
69
|
+
fs.writeFileSync(zipPath, zipBytes);
|
|
70
|
+
// Extract into a staging directory and rename so a partially extracted
|
|
71
|
+
// cache entry can never be mistaken for a complete one.
|
|
72
|
+
const staging = `${destination}.tmp-${process.pid}`;
|
|
73
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
74
|
+
try {
|
|
75
|
+
await unzip(zipPath, staging);
|
|
76
|
+
if (!fs.existsSync(path.join(staging, 'manifest.json'))) {
|
|
77
|
+
throw new Error(`MetaMask zip for ${version} did not contain a manifest.json at its root.`);
|
|
78
|
+
}
|
|
79
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
80
|
+
fs.renameSync(staging, destination);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
84
|
+
fs.rmSync(zipPath, { force: true });
|
|
85
|
+
}
|
|
86
|
+
return destination;
|
|
87
|
+
}
|
|
88
|
+
/** Reads the version field of an unpacked extension's manifest.json. */
|
|
89
|
+
export function extensionManifestVersion(extensionPath) {
|
|
90
|
+
const manifestPath = path.join(extensionPath, 'manifest.json');
|
|
91
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
92
|
+
if (!manifest.version) {
|
|
93
|
+
throw new Error(`No version field in ${manifestPath}.`);
|
|
94
|
+
}
|
|
95
|
+
return manifest.version;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=metamask-extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metamask-extension.js","sourceRoot":"","sources":["../src/metamask-extension.ts"],"names":[],"mappings":"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"}
|