"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isValidResponse = exports.sanitizeRequestArguments = exports.assertEthereumOutboundRequest = exports.assertSnapOutboundRequest = exports.isMultichainRequest = exports.MULTICHAIN_API_METHODS = exports.BLOCKED_RPC_METHODS = exports.withTeardown = void 0;
const rpc_errors_1 = require("@metamask/rpc-errors");
const snaps_utils_1 = require("@metamask/snaps-utils");
const utils_1 = require("@metamask/utils");
const logging_1 = require("../logging.cjs");
// 64 MB - we chose this number because it is the size limit for postMessage
// between the extension and the dapp enforced by Chrome.
const MAX_RESPONSE_JSON_SIZE = 64000000;
/**
 * Make proxy for Promise and handle the teardown process properly.
 * If the teardown is called in the meanwhile, Promise result will not be
 * exposed to the snap anymore and warning will be logged to the console.
 *
 * @param originalPromise - Original promise.
 * @param teardownRef - Reference containing teardown count.
 * @param teardownRef.lastTeardown - Number of the last teardown.
 * @returns New proxy promise.
 */
async function withTeardown(originalPromise, teardownRef) {
    const myTeardown = teardownRef.lastTeardown;
    return new Promise((resolve, reject) => {
        originalPromise
            .then((value) => {
            if (teardownRef.lastTeardown === myTeardown) {
                resolve(value);
            }
            else {
                (0, logging_1.log)('Late promise received after Snap finished execution. Promise will be dropped.');
            }
        })
            .catch((reason) => {
            if (teardownRef.lastTeardown === myTeardown) {
                reject(reason);
            }
            else {
                (0, logging_1.log)('Late promise received after Snap finished execution. Promise will be dropped.');
            }
        });
    });
}
exports.withTeardown = withTeardown;
// We're blocking these RPC methods for v1, will revisit later.
exports.BLOCKED_RPC_METHODS = Object.freeze([
    'wallet_requestPermissions',
    'wallet_revokePermissions',
    // We disallow all of these confirmations for now, since the screens are not ready for Snaps.
    'eth_sendTransaction',
    'eth_decrypt',
    'eth_getEncryptionPublicKey',
    'wallet_addEthereumChain',
    'wallet_watchAsset',
    'wallet_registerOnboarding',
    'wallet_scanQRCode',
]);
exports.MULTICHAIN_API_METHODS = Object.freeze([
    'wallet_createSession',
    'wallet_invokeMethod',
    'wallet_getSession',
    'wallet_revokeSession',
]);
/**
 * Check whether a validated request should be routed to the multichain API.
 *
 * @param args - The request arguments.
 * @returns True if the request is a multichain request, otherwise false.
 */
function isMultichainRequest(args) {
    return exports.MULTICHAIN_API_METHODS.includes(args.method);
}
exports.isMultichainRequest = isMultichainRequest;
/**
 * Asserts the validity of request arguments for a snap outbound request using the `snap.request` API.
 *
 * @param args - The arguments to validate.
 */
function assertSnapOutboundRequest(args) {
    // Disallow any non `wallet_` or `snap_` methods for separation of concerns.
    (0, utils_1.assert)(String.prototype.startsWith.call(args.method, 'wallet_') ||
        String.prototype.startsWith.call(args.method, 'snap_'), 'The global Snap API only allows RPC methods starting with `wallet_*` and `snap_*`.', rpc_errors_1.rpcErrors.methodNotSupported);
    (0, utils_1.assert)(!exports.BLOCKED_RPC_METHODS.includes(args.method), rpc_errors_1.rpcErrors.methodNotFound({
        data: {
            method: args.method,
        },
    }));
}
exports.assertSnapOutboundRequest = assertSnapOutboundRequest;
/**
 * Asserts the validity of request arguments for an ethereum outbound request using the `ethereum.request` API.
 *
 * @param args - The arguments to validate.
 */
function assertEthereumOutboundRequest(args) {
    // Disallow snaps methods for separation of concerns.
    (0, utils_1.assert)(!String.prototype.startsWith.call(args.method, 'snap_'), rpc_errors_1.rpcErrors.methodNotFound({
        data: {
            method: args.method,
        },
    }));
    (0, utils_1.assert)(!exports.BLOCKED_RPC_METHODS.includes(args.method), rpc_errors_1.rpcErrors.methodNotFound({
        data: {
            method: args.method,
        },
    }));
}
exports.assertEthereumOutboundRequest = assertEthereumOutboundRequest;
/**
 * Gets a sanitized value to be used for passing to the underlying MetaMask provider.
 *
 * @param value - An unsanitized value from a snap.
 * @returns A sanitized value ready to be passed to a MetaMask provider.
 */
function sanitizeRequestArguments(value) {
    // Before passing to getSafeJson we run the value through JSON serialization.
    // This lets request arguments contain undefined which is normally disallowed.
    const json = JSON.parse(JSON.stringify(value));
    return (0, utils_1.getSafeJson)(json);
}
exports.sanitizeRequestArguments = sanitizeRequestArguments;
/**
 * Check if the input is a valid response.
 *
 * @param response - The response.
 * @returns True if the response is valid, otherwise false.
 */
function isValidResponse(response) {
    if (!(0, utils_1.isObject)(response)) {
        return false;
    }
    // We know that the response is valid JSON already and we don't
    // need the size to be exact.
    const size = (0, snaps_utils_1.getJsonSizeUnsafe)(response);
    return size < MAX_RESPONSE_JSON_SIZE;
}
exports.isValidResponse = isValidResponse;
//# sourceMappingURL=utils.cjs.map