@sky-mavis/tanto-widget
Version:
Tanto Widget
133 lines • 3.84 kB
JavaScript
import {useRef,useCallback,useEffect}from'react';import {useAccount}from'wagmi';import {analytic}from'../analytic.mjs';const SIGNATURE_METHODS = ['personal_sign', 'eth_signTypedData_v4', 'eth_sign', 'eth_signTypedData'];
const TRANSACTION_METHODS = ['eth_sendTransaction'];
const REQUIRED_SIGNING_METHODS = [...SIGNATURE_METHODS, ...TRANSACTION_METHODS];
function isSignatureMethod(method) {
return SIGNATURE_METHODS.includes(method);
}
function isTransactionMethod(method) {
return TRANSACTION_METHODS.includes(method);
}
function isRequiredSigningMethod(method) {
return REQUIRED_SIGNING_METHODS.includes(method);
}
function createRequestProxy({
request,
beforeRequest,
afterRequest
}) {
return new Proxy(request, {
async apply(target, thisArg, args) {
beforeRequest?.(args[0]);
try {
const result = await Reflect.apply(target, thisArg, args);
afterRequest?.(args[0]);
return result;
} catch (e) {
afterRequest?.(args[0], e);
throw e;
}
}
});
}
function createSignerProxy({
signer,
beforeRequest,
afterRequest
}) {
return new Proxy(signer, {
get(target, prop, receiver) {
if (prop === 'request') {
return createRequestProxy({
request: target.request,
beforeRequest,
afterRequest
});
}
return Reflect.get(target, prop, receiver);
}
});
}
function useConnectorRequestInterceptor({
beforeRequest,
afterRequest
} = {}) {
const {
connector
} = useAccount();
const isListenerActive = useRef(false);
const handleBeforeRequest = useCallback(({
method,
params
}) => {
if (!isRequiredSigningMethod(method)) return;
beforeRequest?.({
method,
params
});
if (isSignatureMethod(method)) analytic.sendEvent('sign_message_open', {
method,
params
});
if (isTransactionMethod(method)) analytic.sendEvent('send_transaction_open', {
method,
params
});
}, [beforeRequest]);
const handleAfterRequest = useCallback(({
method,
params
}, error) => {
if (!isRequiredSigningMethod(method)) return;
afterRequest?.({
method,
params
}, error);
if (isSignatureMethod(method)) {
if (error) analytic.sendEvent('sign_message_fail', {
method,
params,
error_reason: error.message
});else analytic.sendEvent('sign_message_success', {
method,
params
});
}
if (isTransactionMethod(method)) {
if (error) analytic.sendEvent('send_transaction_fail', {
method,
params,
error_reason: error.message
});else analytic.sendEvent('send_transaction_success', {
method,
params
});
}
}, [afterRequest]);
useEffect(() => {
if (!connector || isListenerActive.current) return;
isListenerActive.current = true;
async function setupProvider() {
try {
const provider = await connector.getProvider();
if (provider?.signer && typeof provider.signer.request === 'function') {
provider.signer = createSignerProxy({
signer: provider.signer,
beforeRequest: handleBeforeRequest,
afterRequest: handleAfterRequest
});
return;
}
if (provider?.request && typeof provider.request === 'function') {
provider.request = createRequestProxy({
request: provider.request,
beforeRequest: handleBeforeRequest,
afterRequest: handleAfterRequest
});
}
} catch (error) {
console.debug('Failed to setup provider in useConnectorRequestInterceptor:', error);
}
}
void setupProvider();
}, [connector, handleBeforeRequest, handleAfterRequest]);
}export{useConnectorRequestInterceptor};