"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.numberToU8a32 = exports.bigToU8a32 = exports.bigintToU8a32 = exports.isDepositForBurnEvent = exports.getCCTPNoncePda = exports.simulateAndDecode = exports.createDefaultTransaction = exports.getRandomSvmAddress = exports.getSelfAuthority = exports.getEventAuthority = exports.getClaimAccountPda = exports.getInstructionParamsPda = exports.getRootBundlePda = exports.getTransferLiabilityPda = exports.getRoutePda = exports.getFillStatusPda = exports.getStatePda = exports.unwrapEventData = exports.getEventName = exports.decodeEvent = exports.parseEventData = exports.getLatestFinalizedSlotWithBlock = exports.getNearestSlotTime = exports.toAddress = exports.isDevnet = exports.SolanaVoidSigner = exports.isSolanaError = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var contracts_1 = require("@across-protocol/contracts");
var anchor_1 = require("@coral-xyz/anchor");
var kit_1 = require("@solana/kit");
var bs58_1 = tslib_1.__importDefault(require("bs58"));
var ethers_1 = require("ethers");
var interfaces_1 = require("../../interfaces");
var utils_1 = require("../../utils");
var types_1 = require("./types");
var SpokeUtils_1 = require("./SpokeUtils");
var kit_2 = require("@solana/kit");
Object.defineProperty(exports, "isSolanaError", { enumerable: true, get: function () { return kit_2.isSolanaError; } });
var SolanaVoidSigner = function (simulationAddress) {
    return {
        address: (0, kit_1.address)(simulationAddress),
        signAndSendTransactions: function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4, Promise.resolve([])];
                    case 1: return [2, _a.sent()];
                }
            });
        }); },
    };
};
exports.SolanaVoidSigner = SolanaVoidSigner;
function isDevnet(rpc) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var genesisHash;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4, rpc.getGenesisHash().send()];
                case 1:
                    genesisHash = _a.sent();
                    return [2, genesisHash === "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG"];
            }
        });
    });
}
exports.isDevnet = isDevnet;
function toAddress(address) {
    return address.toBase58();
}
exports.toAddress = toAddress;
function getNearestSlotTime(provider, opts) {
    if (opts === void 0) { opts = { commitment: "confirmed" }; }
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var timestamp, slot, _a;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    if (!("slot" in opts)) return [3, 1];
                    _a = opts.slot;
                    return [3, 3];
                case 1: return [4, provider.getSlot(opts).send()];
                case 2:
                    _a = _b.sent();
                    _b.label = 3;
                case 3:
                    slot = _a;
                    _b.label = 4;
                case 4: return [4, (0, SpokeUtils_1.getTimestampForSlot)(provider, slot)];
                case 5:
                    timestamp = _b.sent();
                    _b.label = 6;
                case 6:
                    if (!(0, utils_1.isDefined)(timestamp) && --slot) return [3, 4];
                    _b.label = 7;
                case 7:
                    (0, assert_1.default)((0, utils_1.isDefined)(timestamp), "Unable to resolve block time for SVM slot ".concat(slot));
                    return [2, { slot: slot, timestamp: timestamp }];
            }
        });
    });
}
exports.getNearestSlotTime = getNearestSlotTime;
function getLatestFinalizedSlotWithBlock(provider, maxSlot, maxLookback) {
    if (maxLookback === void 0) { maxLookback = 1000; }
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var finalizedSlot, endSlot, opts, slot, block;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4, getNearestSlotTime(provider, { commitment: "finalized" })];
                case 1:
                    finalizedSlot = (_a.sent()).slot;
                    endSlot = Math.min(Number(maxSlot), Number(finalizedSlot));
                    opts = { maxSupportedTransactionVersion: 0, transactionDetails: "none", rewards: false };
                    slot = BigInt(endSlot);
                    _a.label = 2;
                case 2: return [4, provider.getBlock(slot, opts).send()];
                case 3:
                    block = _a.sent();
                    if ((0, utils_1.isDefined)(block) && [block.blockHeight, block.blockTime].every(utils_1.isDefined)) {
                        return [3, 5];
                    }
                    _a.label = 4;
                case 4:
                    if (--maxLookback > 0 && --slot > 0) return [3, 2];
                    _a.label = 5;
                case 5:
                    if (maxLookback === 0) {
                        throw new Error("Unable to find Solana block between slots [".concat(slot, ", ").concat(endSlot, "]"));
                    }
                    return [2, Number(slot)];
            }
        });
    });
}
exports.getLatestFinalizedSlotWithBlock = getLatestFinalizedSlotWithBlock;
function parseEventData(eventData) {
    if (!eventData)
        return eventData;
    if (Array.isArray(eventData)) {
        return eventData.map(parseEventData);
    }
    if (Buffer.isBuffer(eventData)) {
        return new Uint8Array(eventData);
    }
    if (typeof eventData === "object") {
        if (eventData.constructor.name === "PublicKey") {
            return (0, kit_1.address)(eventData.toString());
        }
        if (anchor_1.BN.isBN(eventData)) {
            return BigInt(eventData.toString());
        }
        return Object.fromEntries(Object.entries(eventData).map(function (_a) {
            var key = _a[0], value = _a[1];
            return [snakeToCamel(key), parseEventData(value)];
        }));
    }
    return eventData;
}
exports.parseEventData = parseEventData;
function decodeEvent(idl, rawEvent) {
    var event = new anchor_1.BorshEventCoder(idl).decode(rawEvent);
    if (!event)
        throw new Error("Malformed rawEvent for IDL ".concat(idl.address, ": ").concat(rawEvent));
    return {
        name: event.name,
        data: parseEventData(event.data),
    };
}
exports.decodeEvent = decodeEvent;
function snakeToCamel(s) {
    return s.replace(/(_\w)/g, function (match) { return match[1].toUpperCase(); });
}
function getEventName(rawName) {
    if (Object.values(types_1.SVMEventNames).some(function (name) { return rawName.includes(name); }))
        return rawName;
    throw new Error("Unknown event name: ".concat(rawName));
}
exports.getEventName = getEventName;
function unwrapEventData(data, uint8ArrayKeysAsBigInt, currentKey) {
    if (uint8ArrayKeysAsBigInt === void 0) { uint8ArrayKeysAsBigInt = ["depositId", "outputAmount", "inputAmount"]; }
    if (data == null) {
        return data;
    }
    if (typeof data === "bigint") {
        var bigIntKeysAsNumber = ["originChainId", "destinationChainId", "repaymentChainId", "chainId"];
        if (currentKey && bigIntKeysAsNumber.includes(currentKey)) {
            return Number(data);
        }
        return utils_1.BigNumber.from(data);
    }
    if (data instanceof Uint8Array || (0, utils_1.isUint8Array)(data)) {
        var bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
        var hex = ethers_1.ethers.utils.hexlify(bytes);
        if (currentKey && uint8ArrayKeysAsBigInt.includes(currentKey)) {
            return utils_1.BigNumber.from(hex);
        }
        return hex;
    }
    if (Array.isArray(data)) {
        return data.map(function (item) { return unwrapEventData(item, uint8ArrayKeysAsBigInt); });
    }
    if (typeof data === "string" && (0, kit_1.isAddress)(data)) {
        return ethers_1.ethers.utils.hexlify(bs58_1.default.decode(data));
    }
    if (typeof data === "object") {
        if (currentKey === "fillType") {
            var fillType = Object.keys(data)[0];
            switch (fillType) {
                case "FastFill":
                    return interfaces_1.FillType.FastFill;
                case "ReplacedSlowFill":
                    return interfaces_1.FillType.ReplacedSlowFill;
                case "SlowFill":
                    return interfaces_1.FillType.SlowFill;
                default:
                    throw new Error("Unknown fill type: ".concat(fillType));
            }
        }
        if (Object.keys(data).length === 0) {
            return "0x";
        }
        return Object.fromEntries(Object.entries(data).map(function (_a) {
            var key = _a[0], value = _a[1];
            return [
                key,
                unwrapEventData(value, uint8ArrayKeysAsBigInt, key),
            ];
        }));
    }
    return data;
}
exports.unwrapEventData = unwrapEventData;
function getStatePda(programId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var intEncoder, seed, statePda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    intEncoder = (0, kit_1.getU64Encoder)();
                    seed = intEncoder.encode(0);
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: ["state", seed],
                        })];
                case 1:
                    statePda = (_a.sent())[0];
                    return [2, statePda];
            }
        });
    });
}
exports.getStatePda = getStatePda;
function getFillStatusPda(programId, relayData, destinationChainId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var relayDataHash, uint8RelayDataHash, fillStatusPda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    relayDataHash = (0, utils_1.getRelayDataHash)(relayData, destinationChainId);
                    uint8RelayDataHash = new Uint8Array(Buffer.from(relayDataHash.slice(2), "hex"));
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: ["fills", uint8RelayDataHash],
                        })];
                case 1:
                    fillStatusPda = (_a.sent())[0];
                    return [2, fillStatusPda];
            }
        });
    });
}
exports.getFillStatusPda = getFillStatusPda;
function getRoutePda(originToken, seed, routeChainId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var intEncoder, addressEncoder, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    intEncoder = (0, kit_1.getU64Encoder)();
                    addressEncoder = (0, kit_1.getAddressEncoder)();
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: (0, kit_1.address)(contracts_1.SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS),
                            seeds: ["route", addressEncoder.encode(originToken), intEncoder.encode(seed), intEncoder.encode(routeChainId)],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
exports.getRoutePda = getRoutePda;
function getTransferLiabilityPda(programId, originToken) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var addressEncoder, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    addressEncoder = (0, kit_1.getAddressEncoder)();
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: ["transfer_liability", addressEncoder.encode(originToken)],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
exports.getTransferLiabilityPda = getTransferLiabilityPda;
function getRootBundlePda(programId, rootBundleId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var seedEncoder, seed, intEncoder, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    seedEncoder = (0, kit_1.getU64Encoder)();
                    seed = seedEncoder.encode(0);
                    intEncoder = (0, kit_1.getU32Encoder)();
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: ["root_bundle", seed, intEncoder.encode(rootBundleId)],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
exports.getRootBundlePda = getRootBundlePda;
function getInstructionParamsPda(programId, signer) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var addressEncoder, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    addressEncoder = (0, kit_1.getAddressEncoder)();
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: ["instruction_params", addressEncoder.encode(signer)],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
exports.getInstructionParamsPda = getInstructionParamsPda;
function getClaimAccountPda(programId, mint, tokenOwner) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var addressEncoder, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    addressEncoder = (0, kit_1.getAddressEncoder)();
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: ["claim_account", addressEncoder.encode(mint), addressEncoder.encode(tokenOwner)],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
exports.getClaimAccountPda = getClaimAccountPda;
function getEventAuthority(programId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var eventAuthority;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4, (0, kit_1.getProgramDerivedAddress)({
                        programAddress: programId,
                        seeds: ["__event_authority"],
                    })];
                case 1:
                    eventAuthority = (_a.sent())[0];
                    return [2, eventAuthority];
            }
        });
    });
}
exports.getEventAuthority = getEventAuthority;
var getSelfAuthority = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var selfAuthority;
    return tslib_1.__generator(this, function (_a) {
        switch (_a.label) {
            case 0: return [4, (0, kit_1.getProgramDerivedAddress)({
                    programAddress: (0, kit_1.address)(contracts_1.SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS),
                    seeds: ["self_authority"],
                })];
            case 1:
                selfAuthority = (_a.sent())[0];
                return [2, selfAuthority];
        }
    });
}); };
exports.getSelfAuthority = getSelfAuthority;
function getRandomSvmAddress() {
    var bytes = ethers_1.ethers.utils.randomBytes(32);
    var base58Address = bs58_1.default.encode(bytes);
    return (0, kit_1.address)(base58Address);
}
exports.getRandomSvmAddress = getRandomSvmAddress;
var createDefaultTransaction = function (rpcClient, signer) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var latestBlockhash;
    return tslib_1.__generator(this, function (_a) {
        switch (_a.label) {
            case 0: return [4, rpcClient.getLatestBlockhash().send()];
            case 1:
                latestBlockhash = (_a.sent()).value;
                return [2, (0, kit_1.pipe)((0, kit_1.createTransactionMessage)({ version: 0 }), function (tx) { return (0, kit_1.setTransactionMessageFeePayerSigner)(signer, tx); }, function (tx) { return (0, kit_1.setTransactionMessageLifetimeUsingBlockhash)(latestBlockhash, tx); })];
        }
    });
}); };
exports.createDefaultTransaction = createDefaultTransaction;
var simulateAndDecode = function (solanaClient, ix, signer, parser) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var simulationTx, _a, _b, simulationResult, _c, _d, _e;
    var _f;
    return tslib_1.__generator(this, function (_g) {
        switch (_g.label) {
            case 0:
                _a = kit_1.appendTransactionMessageInstruction;
                _b = [ix];
                return [4, (0, exports.createDefaultTransaction)(solanaClient, signer)];
            case 1:
                simulationTx = _a.apply(void 0, _b.concat([_g.sent()]));
                _d = (_c = solanaClient)
                    .simulateTransaction;
                _e = kit_1.getBase64EncodedWireTransaction;
                return [4, (0, kit_1.signTransactionMessageWithSigners)(simulationTx)];
            case 2: return [4, _d.apply(_c, [_e.apply(void 0, [_g.sent()]), {
                        encoding: "base64",
                    }])
                    .send()];
            case 3:
                simulationResult = _g.sent();
                if (!((_f = simulationResult.value.returnData) === null || _f === void 0 ? void 0 : _f.data[0])) {
                    throw new Error("No return data");
                }
                return [2, parser(Buffer.from(simulationResult.value.returnData.data[0], "base64"))];
        }
    });
}); };
exports.simulateAndDecode = simulateAndDecode;
var getCCTPNoncePda = function (solanaClient, signer, nonce, sourceDomain) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var messageTransmitterPda, getNonceIx, parserFunction;
    return tslib_1.__generator(this, function (_a) {
        switch (_a.label) {
            case 0: return [4, (0, kit_1.getProgramDerivedAddress)({
                    programAddress: contracts_1.MessageTransmitterClient.MESSAGE_TRANSMITTER_PROGRAM_ADDRESS,
                    seeds: ["message_transmitter"],
                })];
            case 1:
                messageTransmitterPda = (_a.sent())[0];
                return [4, contracts_1.MessageTransmitterClient.getGetNoncePdaInstruction({
                        messageTransmitter: messageTransmitterPda,
                        nonce: nonce,
                        sourceDomain: sourceDomain,
                    })];
            case 2:
                getNonceIx = _a.sent();
                parserFunction = function (buf) {
                    if (buf.length === 32) {
                        return (0, kit_1.address)(bs58_1.default.encode(buf));
                    }
                    throw new Error("Invalid buffer");
                };
                return [4, (0, exports.simulateAndDecode)(solanaClient, getNonceIx, signer, parserFunction)];
            case 3: return [2, _a.sent()];
        }
    });
}); };
exports.getCCTPNoncePda = getCCTPNoncePda;
function isDepositForBurnEvent(event) {
    return event.type === "transfer";
}
exports.isDepositForBurnEvent = isDepositForBurnEvent;
function bigintToU8a32(n) {
    if (n < BigInt(0) || n > ethers_1.ethers.constants.MaxUint256.toBigInt()) {
        throw new RangeError("Value must fit in 256 bits");
    }
    var hexPadded = ethers_1.ethers.utils.hexZeroPad("0x" + n.toString(16), 32);
    return ethers_1.ethers.utils.arrayify(hexPadded);
}
exports.bigintToU8a32 = bigintToU8a32;
var bigToU8a32 = function (bn) {
    return bigintToU8a32(typeof bn === "bigint" ? bn : BigInt(bn.toString()));
};
exports.bigToU8a32 = bigToU8a32;
var numberToU8a32 = function (n) { return bigintToU8a32(BigInt(n)); };
exports.numberToU8a32 = numberToU8a32;
//# sourceMappingURL=utils.js.map