Implement EIP-1193 provider for dApp connectivity
All checks were successful
check / check (push) Successful in 13s
All checks were successful
check / check (push) Successful in 13s
Three-part architecture: - inpage.js: creates window.ethereum in page context with request(), on(), send(), sendAsync(), enable() methods. Sets isMetaMask=true for compatibility. - content/index.js: bridge between page and extension via postMessage (page<->content) and runtime.sendMessage (content<->background). - background/index.js: handles RPC routing. Proxies read-only methods (eth_call, eth_getBalance, etc.) to configured RPC. Handles eth_requestAccounts (auto-connect for now), wallet_switchEthereumChain (mainnet only), and returns informative errors for unimplemented signing methods. Manifests updated with web_accessible_resources for inpage.js. Build updated to bundle inpage.js as a separate output file.
This commit is contained in:
128
src/content/inpage.js
Normal file
128
src/content/inpage.js
Normal file
@@ -0,0 +1,128 @@
|
||||
// AutistMask inpage script — injected into the page's JS context.
|
||||
// Creates window.ethereum (EIP-1193 provider).
|
||||
|
||||
(function () {
|
||||
if (typeof window.ethereum !== "undefined") return;
|
||||
|
||||
const CHAIN_ID = "0x1"; // Ethereum mainnet
|
||||
|
||||
const listeners = {};
|
||||
let nextId = 1;
|
||||
const pending = {};
|
||||
|
||||
// Listen for responses from the content script
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.source !== window) return;
|
||||
if (event.data?.type !== "AUTISTMASK_RESPONSE") return;
|
||||
const { id, result, error } = event.data;
|
||||
const p = pending[id];
|
||||
if (!p) return;
|
||||
delete pending[id];
|
||||
if (error) {
|
||||
p.reject(new Error(error.message || "Request failed"));
|
||||
} else {
|
||||
p.resolve(result);
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for events pushed from the extension
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.source !== window) return;
|
||||
if (event.data?.type !== "AUTISTMASK_EVENT") return;
|
||||
const { eventName, data } = event.data;
|
||||
emit(eventName, data);
|
||||
});
|
||||
|
||||
function emit(eventName, data) {
|
||||
const cbs = listeners[eventName];
|
||||
if (!cbs) return;
|
||||
for (const cb of cbs) {
|
||||
try {
|
||||
cb(data);
|
||||
} catch (e) {
|
||||
// ignore listener errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function request(args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = nextId++;
|
||||
pending[id] = { resolve, reject };
|
||||
window.postMessage(
|
||||
{ type: "AUTISTMASK_REQUEST", id, ...args },
|
||||
"*",
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const provider = {
|
||||
isAutistMask: true,
|
||||
isMetaMask: true, // compatibility — many dApps check this
|
||||
chainId: CHAIN_ID,
|
||||
networkVersion: "1",
|
||||
selectedAddress: null,
|
||||
|
||||
request(args) {
|
||||
return request({ method: args.method, params: args.params || [] });
|
||||
},
|
||||
|
||||
// Legacy methods (still used by some dApps)
|
||||
enable() {
|
||||
return this.request({ method: "eth_requestAccounts" });
|
||||
},
|
||||
|
||||
send(methodOrPayload, paramsOrCallback) {
|
||||
// Handle both send(method, params) and send({method, params})
|
||||
if (typeof methodOrPayload === "string") {
|
||||
return this.request({
|
||||
method: methodOrPayload,
|
||||
params: paramsOrCallback || [],
|
||||
});
|
||||
}
|
||||
return this.request({
|
||||
method: methodOrPayload.method,
|
||||
params: methodOrPayload.params || [],
|
||||
});
|
||||
},
|
||||
|
||||
sendAsync(payload, callback) {
|
||||
this.request({
|
||||
method: payload.method,
|
||||
params: payload.params || [],
|
||||
})
|
||||
.then((result) =>
|
||||
callback(null, { id: payload.id, jsonrpc: "2.0", result }),
|
||||
)
|
||||
.catch((err) => callback(err));
|
||||
},
|
||||
|
||||
on(event, cb) {
|
||||
if (!listeners[event]) listeners[event] = [];
|
||||
listeners[event].push(cb);
|
||||
return this;
|
||||
},
|
||||
|
||||
removeListener(event, cb) {
|
||||
if (!listeners[event]) return this;
|
||||
listeners[event] = listeners[event].filter((c) => c !== cb);
|
||||
return this;
|
||||
},
|
||||
|
||||
removeAllListeners(event) {
|
||||
if (event) {
|
||||
delete listeners[event];
|
||||
} else {
|
||||
for (const key of Object.keys(listeners)) {
|
||||
delete listeners[key];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
window.ethereum = provider;
|
||||
|
||||
// Announce via EIP-6963 (multi-wallet discovery)
|
||||
window.dispatchEvent(new Event("ethereum#initialized"));
|
||||
})();
|
||||
Reference in New Issue
Block a user