"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RawAddress = exports.TvmAddress = exports.SvmAddress = exports.EvmAddress = exports.Address = void 0;
exports.is7702Delegate = is7702Delegate;
exports.isContractDeployedToAddress = isContractDeployedToAddress;
exports.compareAddresses = compareAddresses;
exports.compareAddressesSimple = compareAddressesSimple;
exports.toBytes32 = toBytes32;
exports.toEvmAddress = toEvmAddress;
exports.isValidEvmAddress = isValidEvmAddress;
exports.toAddressType = toAddressType;
const tslib_1 = require("tslib");
const viem_1 = require("viem");
const ethers_1 = require("ethers");
const bs58_1 = tslib_1.__importDefault(require("bs58"));
const tronweb_1 = require("tronweb");
const _1 = require("./");
function is7702Delegate(code) {
    return code.length === 48 && code.startsWith("0xef0100") && (0, viem_1.isAddress)(`0x${code.slice(8)}`);
}
async function isContractDeployedToAddress(address, provider, ignore7702 = false) {
    if (!address || !(0, viem_1.isAddress)(address)) {
        return false;
    }
    const code = await provider.getCode(address);
    if (code === "0x") {
        return false;
    }
    if (ignore7702) {
        return !is7702Delegate(code);
    }
    return true;
}
function compareAddresses(addressA, addressB) {
    const bnAddressA = _1.BigNumber.from(addressA);
    const bnAddressB = _1.BigNumber.from(addressB);
    if (bnAddressA.gt(bnAddressB)) {
        return 1;
    }
    else if (bnAddressA.lt(bnAddressB)) {
        return -1;
    }
    else {
        return 0;
    }
}
function compareAddressesSimple(addressA, addressB) {
    if (addressA === undefined || addressB === undefined) {
        return false;
    }
    return addressA.toLowerCase() === addressB.toLowerCase();
}
function toBytes32(address) {
    return ethers_1.utils.hexZeroPad(address, 32).toLowerCase();
}
function toEvmAddress(hexString) {
    const rawAddress = ethers_1.utils.hexZeroPad(ethers_1.utils.hexStripZeros(hexString), 20);
    return ethers_1.utils.getAddress(rawAddress);
}
function isValidEvmAddress(address) {
    if ((0, viem_1.isAddress)(address)) {
        return true;
    }
    try {
        const evmAddress = ethers_1.utils.hexZeroPad(ethers_1.utils.hexStripZeros(address), 20);
        return (0, viem_1.isAddress)(ethers_1.utils.getAddress(evmAddress));
    }
    catch {
        return false;
    }
}
function toAddressType(address, chainId) {
    const rawAddress = address.startsWith("0x") ? ethers_1.utils.arrayify(address) : bs58_1.default.decode(address);
    if ((0, _1.chainIsTvm)(chainId))
        return TvmAddress.from(address);
    else if ((0, _1.chainIsEvm)(chainId) && EvmAddress.validate(rawAddress))
        return new EvmAddress(rawAddress);
    else if ((0, _1.chainIsSvm)(chainId) && SvmAddress.validate(rawAddress))
        return new SvmAddress(rawAddress);
    return new RawAddress(rawAddress);
}
class Address {
    __address_type_brand = true;
    rawAddress;
    evmAddress = undefined;
    bytes32Address = undefined;
    svmAddress = undefined;
    constructor(_rawAddress) {
        if (_rawAddress.length > 32) {
            throw new Error(`Address ${ethers_1.utils.hexlify(_rawAddress)} cannot be longer than 32 bytes.`);
        }
        this.rawAddress = ethers_1.utils.zeroPad(_rawAddress, 32);
    }
    static isAddress(obj) {
        return typeof obj === "object" && obj !== null && "__address_type_brand" in obj;
    }
    toJSON() {
        return this.toNative();
    }
    toBytes32() {
        return (this.bytes32Address ??= ethers_1.utils.hexZeroPad(ethers_1.utils.hexlify(this.rawAddress), 32).toLowerCase());
    }
    truncateToBytes20() {
        const bytes20 = this.rawAddress.slice(-20);
        return toEvmAddress(ethers_1.utils.hexlify(bytes20));
    }
    toBase58() {
        return (this.svmAddress ??= bs58_1.default.encode(this.rawAddress));
    }
    toEvmAddress() {
        const parseRawAddress = () => {
            const hexString = ethers_1.utils.hexlify(this.rawAddress);
            const rawAddress = ethers_1.utils.hexZeroPad(ethers_1.utils.hexStripZeros(hexString), 20);
            return ethers_1.utils.getAddress(rawAddress);
        };
        return (this.evmAddress ??= parseRawAddress());
    }
    toNative() {
        return this.toBytes32();
    }
    toHexString() {
        return this.toBytes32();
    }
    isValidOn(chainId) {
        if ((0, _1.chainIsTvm)(chainId))
            return TvmAddress.validate(this.rawAddress);
        if ((0, _1.chainIsEvm)(chainId))
            return EvmAddress.validate(this.rawAddress);
        if ((0, _1.chainIsSvm)(chainId))
            return SvmAddress.validate(this.rawAddress);
        return false;
    }
    toString() {
        return this.toNative();
    }
    isZeroAddress() {
        return ethers_1.utils.stripZeros(this.rawAddress).length === 0;
    }
    forceSvmAddress() {
        return SvmAddress.from(this.toBase58());
    }
    eq(other) {
        return this.toString() === other?.toString();
    }
    compare(otherAddress) {
        for (let i = 0; i < 32; i++) {
            if (this.rawAddress[i] > otherAddress.rawAddress[i])
                return 1;
            if (this.rawAddress[i] < otherAddress.rawAddress[i])
                return -1;
        }
        return 0;
    }
    isEVM() {
        return false;
    }
    isSVM() {
        return false;
    }
    isTVM() {
        return false;
    }
}
exports.Address = Address;
class EvmAddress extends Address {
    constructor(rawAddress) {
        if (!EvmAddress.validate(rawAddress)) {
            throw new Error(`${ethers_1.utils.hexlify(rawAddress)} is not a valid EVM address`);
        }
        super(rawAddress);
    }
    static validate(rawAddress) {
        return (rawAddress.length == 20 || (rawAddress.length === 32 && rawAddress.slice(0, 12).every((field) => field === 0)));
    }
    isEVM() {
        return true;
    }
    toNative() {
        return this.toEvmAddress();
    }
    static from(address) {
        return address.startsWith("0x") ? new this(ethers_1.utils.arrayify(address)) : new this(bs58_1.default.decode(address));
    }
}
exports.EvmAddress = EvmAddress;
class SvmAddress extends Address {
    constructor(rawAddress) {
        if (!SvmAddress.validate(rawAddress)) {
            throw new Error(`${ethers_1.utils.hexlify(rawAddress)} is not a valid SVM address`);
        }
        super(rawAddress);
    }
    static validate(rawAddress) {
        return (rawAddress.length === 32 &&
            (!rawAddress.slice(0, 12).every((field) => field === 0) || rawAddress.every((field) => field === 0)));
    }
    isSVM() {
        return true;
    }
    toNative() {
        return this.toBase58();
    }
    static from(address) {
        return address.startsWith("0x") ? new this(ethers_1.utils.arrayify(address)) : new this(bs58_1.default.decode(address));
    }
}
exports.SvmAddress = SvmAddress;
class TvmAddress extends Address {
    nativeAddress = undefined;
    constructor(rawAddress) {
        if (!TvmAddress.validate(rawAddress)) {
            throw new Error(`${ethers_1.utils.hexlify(rawAddress)} is not a valid TVM address`);
        }
        super(rawAddress);
    }
    static validate(rawAddress) {
        return (rawAddress.length == 20 || (rawAddress.length === 32 && rawAddress.slice(0, 12).every((field) => field === 0)));
    }
    isTVM() {
        return true;
    }
    toNative() {
        const computeNative = () => {
            const hexString = ethers_1.utils.hexlify(this.rawAddress);
            const evmHex = ethers_1.utils.hexZeroPad(ethers_1.utils.hexStripZeros(hexString), 20);
            return tronweb_1.TronWeb.address.fromHex(evmHex);
        };
        return (this.nativeAddress ??= computeNative());
    }
    toHexString() {
        return this.toEvmAddress();
    }
    static from(address) {
        if (address.startsWith("0x")) {
            return new this(ethers_1.utils.arrayify(address));
        }
        const hex = tronweb_1.TronWeb.address.toHex(address);
        const rawHex = "0x" + hex.slice(2);
        return new this(ethers_1.utils.arrayify(rawHex));
    }
}
exports.TvmAddress = TvmAddress;
class RawAddress extends Address {
}
exports.RawAddress = RawAddress;
//# sourceMappingURL=AddressUtils.js.map