"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExternalWallet = void 0;
const dataverse_kernel_1 = require("@dataverse/dataverse-kernel");
const communicator_1 = require("@meteor-web3/communicator");
const ethers_1 = require("ethers");
const constants_1 = require("./constants");
const utils_1 = require("./utils");
class ExternalWallet {
    wallet = constants_1.WALLET.EXTERNAL_WALLET;
    provider;
    signer;
    address;
    namespace;
    reference;
    communicator;
    constructor() {
        const communicator = new communicator_1.Communicator({
            source: window,
            target: window.top,
            runningEnv: "Kernel",
        });
        communicator.onRequestMessage(event => {
            // console.log("ExternalWallet onRequestMessage", event);
            // const args = message as RequestArguments & RequestInputs;
            // if (args.method === "accountsChanged" || args.method === "chainChanged") {
            //   this[args.method](sender);
            // }
        });
        this.communicator = communicator;
    }
    getExternalProvider() {
        return {
            request: ({ method, params }) => {
                // console.log("ExternalProvider request", method, params);
                const res = this.communicator.sendRequest({
                    method: dataverse_kernel_1.SYSTEM_CALL.ethereumRequest,
                    params: { method, params },
                    postMessageTo: "Client",
                });
                res.then(_res => {
                    // console.log("ExternalProvider request res", _res);
                });
                return res;
            },
        };
    }
    async connect() {
        const ethereum = this.getExternalProvider();
        const provider = new ethers_1.ethers.providers.Web3Provider(ethereum, "any");
        await provider.send("eth_requestAccounts", []);
        const signer = provider.getSigner();
        const address = await signer.getAddress();
        const { chainId } = await provider.getNetwork();
        this.provider = provider;
        this.signer = signer;
        this.address = address;
        this.namespace = constants_1.EIP155;
        this.reference = String(chainId);
        return {
            wallet: this.wallet,
            provider,
            signer,
            address,
            namespace: this.namespace,
            reference: this.reference,
        };
    }
    async requestPermissions() {
        let provider = this.provider;
        let noProviderFlag = false;
        let addressList = [];
        if (!provider) {
            noProviderFlag = true;
            addressList = (await this.getExternalProvider()?.request?.({
                method: "wallet_requestPermissions",
                params: [{ eth_accounts: {} }],
            }));
            const res = await this.connect();
            provider = res.provider;
        }
        const ethereum = provider.provider;
        if (!provider || !ethereum) {
            dataverse_kernel_1.DataverseKernel.instance.exception.advancedException.assertCheckProviderIsInitialized();
        }
        if (!noProviderFlag) {
            addressList = await ethereum?.request?.({
                method: "wallet_requestPermissions",
                params: [{ eth_accounts: {} }],
            });
        }
        this.signer = provider.getSigner();
        this.address = (0, utils_1.getChecksumAddress)(ethereum["selectedAddress"]);
        return Promise.all(addressList?.[0]?.caveats?.[0]?.value.map((address) => (0, utils_1.getChecksumAddress)(address)));
    }
    async switchNetwork(chainId) {
        const chainIdHex = `0x${chainId.toString(16)}`;
        const provider = this.provider;
        const ethereum = provider.provider;
        try {
            await ethereum.request?.({
                method: "wallet_switchEthereumChain",
                params: [{ chainId: chainIdHex }],
            });
            this.reference = String(chainId);
            const newProvider = new ethers_1.ethers.providers.Web3Provider(
            // await getEthereum(),
            ethereum, "any");
            this.provider = newProvider;
            this.signer = newProvider.getSigner();
        }
        catch (error) {
            console.log(error);
            // error code 4902 说明用户钱包里没有该网络，需要添加进去
            if (error.code === 4902) {
                if (chainIdHex === "0x89") {
                    await ethereum.request?.({
                        method: "wallet_addEthereumChain",
                        params: [
                            {
                                chainId: "0x89",
                                chainName: "Polygon Mainnet",
                                rpcUrls: ["https://polygon-rpc.com"],
                                nativeCurrency: {
                                    name: "MATIC",
                                    symbol: "MATIC",
                                    decimals: 18,
                                },
                                blockExplorerUrls: ["https://polygonscan.com"],
                            },
                        ],
                    });
                }
                else if (chainIdHex === "0x13881") {
                    await ethereum.request?.({
                        method: "wallet_addEthereumChain",
                        params: [
                            {
                                chainId: "0x13881",
                                chainName: "Mumbai",
                                rpcUrls: ["https://rpc-mumbai.maticvigil.com"],
                                nativeCurrency: {
                                    name: "MATIC",
                                    symbol: "MATIC",
                                    decimals: 18,
                                },
                                blockExplorerUrls: ["https://mumbai.polygonscan.com"],
                            },
                        ],
                    });
                }
                else if (chainIdHex === "0x13a") {
                    await ethereum.request?.({
                        method: "wallet_addEthereumChain",
                        params: [
                            {
                                chainId: "0x13a",
                                chainName: "Filecoin - Mainnet",
                                rpcUrls: ["https://api.node.glif.io"],
                                nativeCurrency: {
                                    name: "FIL",
                                    symbol: "FIL",
                                    decimals: 18,
                                },
                                blockExplorerUrls: ["https://filfox.info"],
                            },
                        ],
                    });
                }
                else if (chainIdHex === "0xc45") {
                    await ethereum.request?.({
                        method: "wallet_addEthereumChain",
                        params: [
                            {
                                chainId: "0xc45",
                                chainName: "Filecoin - Hyperspace testnet",
                                rpcUrls: ["https://filecoin-hyperspace.chainup.net/rpc/v1"],
                                nativeCurrency: {
                                    name: "tFIL",
                                    symbol: "tFIL",
                                    decimals: 18,
                                },
                                blockExplorerUrls: ["https://hyperspace.filfox.info"],
                            },
                        ],
                    });
                }
                else if (chainIdHex === "0x38") {
                    await ethereum.request?.({
                        method: "wallet_addEthereumChain",
                        params: [
                            {
                                chainId: "0x38",
                                chainName: "Binance Smart Chain Mainnet",
                                rpcUrls: ["https://bsc-dataseed.binance.org"],
                                nativeCurrency: {
                                    name: "BNB",
                                    symbol: "BNB",
                                    decimals: 18,
                                },
                                blockExplorerUrls: ["https://bscscan.com"],
                            },
                        ],
                    });
                }
                else if (chainIdHex === "0x61") {
                    await ethereum.request?.({
                        method: "wallet_addEthereumChain",
                        params: [
                            {
                                chainId: "0x61",
                                chainName: "Binance Smart Chain Testnet",
                                rpcUrls: [
                                    "https://endpoints.omniatech.io/v1/bsc/testnet/public",
                                ],
                                nativeCurrency: {
                                    name: "tBNB",
                                    symbol: "tBNB",
                                    decimals: 18,
                                },
                                blockExplorerUrls: ["https://testnet.bscscan.com"],
                            },
                        ],
                    });
                }
                else {
                    dataverse_kernel_1.DataverseKernel.instance.exception.advancedException.assertUnrecognizedChainID();
                }
            }
            else {
                throw error;
            }
        }
    }
    async ethereumRequest({ method, params }) {
        const provider = this.provider;
        const ethereum = provider.provider;
        if (method === "wallet_requestPermissions") {
            return this.requestPermissions();
        }
        else if (method === "wallet_switchEthereumChain") {
            return this.switchNetwork(Number(params?.[0]?.chainId));
        }
        else {
            const res = await ethereum.request?.({
                method,
                params,
            });
            return res;
        }
    }
    chainChanged() {
        this.connect();
    }
    accountsChanged() {
        this.connect();
    }
}
exports.ExternalWallet = ExternalWallet;
