"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalTokenInfo = exports.waitAlphTxConfirmed = exports.stringToByte32Hex = exports.getRemoteTokenInfo = exports.getRemoteTokenInfoFromContractState = exports.contractExists = exports.getUnexecutedSequenceId = exports.getTokenPoolId = exports.getTokenBridgeForChainId = exports.getAttestTokenHandlerId = exports.zeroPad = exports.updateRefundAddress = exports.destroyUnexecutedSequenceContracts = exports.deposit = exports.registerChain = void 0;
const web3_1 = require("@alephium/web3");
const utils_1 = require("../utils");
const scripts_1 = require("../alephium-contracts/ts/scripts");
const RemoteTokenPool_1 = require("../alephium-contracts/ts/RemoteTokenPool");
const token_list_1 = require("@alephium/token-list");
function registerChain(signerProvider, tokenBridgeId, signedVAA, alphAmount) {
    return __awaiter(this, void 0, void 0, function* () {
        const account = yield signerProvider.getSelectedAccount();
        return scripts_1.RegisterChain.execute(signerProvider, {
            initialFields: {
                payer: account.address,
                tokenBridge: tokenBridgeId,
                vaa: web3_1.binToHex(signedVAA),
                alphAmount: alphAmount
            },
            attoAlphAmount: alphAmount
        });
    });
}
exports.registerChain = registerChain;
function deposit(signerProvider, tokenBridgeForChainId, amount) {
    return __awaiter(this, void 0, void 0, function* () {
        const account = yield signerProvider.getSelectedAccount();
        return scripts_1.Deposit.execute(signerProvider, {
            initialFields: {
                tokenBridgeForChain: tokenBridgeForChainId,
                payer: account.address,
                amount: amount
            },
            attoAlphAmount: amount
        });
    });
}
exports.deposit = deposit;
function destroyUnexecutedSequenceContracts(signerProvider, tokenBridgeId, signedVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return scripts_1.DestroyUnexecutedSequenceContracts.execute(signerProvider, {
            initialFields: {
                tokenBridge: tokenBridgeId,
                vaa: web3_1.binToHex(signedVAA)
            }
        });
    });
}
exports.destroyUnexecutedSequenceContracts = destroyUnexecutedSequenceContracts;
function updateRefundAddress(signerProvider, tokenBridgeId, signedVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return scripts_1.UpdateRefundAddress.execute(signerProvider, {
            initialFields: {
                tokenBridge: tokenBridgeId,
                vaa: web3_1.binToHex(signedVAA)
            }
        });
    });
}
exports.updateRefundAddress = updateRefundAddress;
function zeroPad(value, byteLength) {
    const expectedLength = 2 * byteLength;
    if (value.length < expectedLength) {
        const prefix = Array(expectedLength - value.length).fill('0').join("");
        return prefix + value;
    }
    return value;
}
exports.zeroPad = zeroPad;
function getAttestTokenHandlerId(tokenBridgeId, remoteChainId, groupIndex) {
    const pathHex = '00' + zeroPad(remoteChainId.toString(16), 2);
    return web3_1.subContractId(tokenBridgeId, pathHex, groupIndex);
}
exports.getAttestTokenHandlerId = getAttestTokenHandlerId;
function getTokenBridgeForChainId(tokenBridgeId, remoteChainId, groupIndex) {
    const pathHex = '01' + zeroPad(remoteChainId.toString(16), 2);
    return web3_1.subContractId(tokenBridgeId, pathHex, groupIndex);
}
exports.getTokenBridgeForChainId = getTokenBridgeForChainId;
function getTokenPoolId(tokenBridgeId, tokenChainId, tokenId, groupIndex) {
    if (tokenId.length !== 64) {
        throw new Error(`Invalid token id ${tokenId}, expect 32 bytes hex string`);
    }
    const pathHex = '02' + zeroPad(tokenChainId.toString(16), 2) + tokenId;
    return web3_1.subContractId(tokenBridgeId, pathHex, groupIndex);
}
exports.getTokenPoolId = getTokenPoolId;
function getUnexecutedSequenceId(tokenBridgeForChainId, index, groupIndex) {
    const pathHex = zeroPad(index.toString(16), 8);
    return web3_1.subContractId(tokenBridgeForChainId, pathHex, groupIndex);
}
exports.getUnexecutedSequenceId = getUnexecutedSequenceId;
function contractExists(contractId, provider) {
    return __awaiter(this, void 0, void 0, function* () {
        const address = web3_1.addressFromContractId(contractId);
        return provider
            .addresses
            .getAddressesAddressGroup(address)
            .then(_ => true)
            .catch((e) => {
            if (e instanceof Error && e.message.indexOf("Group not found") !== -1) {
                return false;
            }
            throw e;
        });
    });
}
exports.contractExists = contractExists;
function getRemoteTokenInfoFromContractState(state) {
    const contractState = RemoteTokenPool_1.RemoteTokenPool.contract.fromApiContractState(state);
    const tokenId = contractState.fields.bridgeTokenId;
    const tokenChainId = Number(contractState.fields.tokenChainId);
    const symbolHex = contractState.fields.symbol_;
    const nameHex = contractState.fields.name_;
    const decimals = Number(contractState.fields['decimals_']);
    return {
        id: tokenId,
        tokenChainId: tokenChainId,
        symbol: utils_1.bytes32ToUtf8String(Buffer.from(symbolHex, 'hex')),
        name: utils_1.bytes32ToUtf8String(Buffer.from(nameHex, 'hex')),
        decimals: decimals
    };
}
exports.getRemoteTokenInfoFromContractState = getRemoteTokenInfoFromContractState;
function getRemoteTokenInfo(address) {
    return __awaiter(this, void 0, void 0, function* () {
        const contractState = yield RemoteTokenPool_1.RemoteTokenPool.at(address).fetchState();
        return {
            id: contractState.fields.bridgeTokenId,
            tokenChainId: Number(contractState.fields.tokenChainId),
            symbol: utils_1.bytes32ToUtf8String(Buffer.from(contractState.fields.symbol_, 'hex')),
            name: utils_1.bytes32ToUtf8String(Buffer.from(contractState.fields.name_, 'hex')),
            decimals: Number(contractState.fields.decimals_)
        };
    });
}
exports.getRemoteTokenInfo = getRemoteTokenInfo;
function stringToByte32Hex(str) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(str);
    if (bytes.length > 32) {
        throw new Error('string exceed 32 bytes');
    }
    return web3_1.binToHex(bytes).padStart(64, '0');
}
exports.stringToByte32Hex = stringToByte32Hex;
function isConfirmed(txStatus) {
    return txStatus.type === 'Confirmed';
}
function waitAlphTxConfirmed(provider, txId, confirmations) {
    return __awaiter(this, void 0, void 0, function* () {
        const status = yield provider.transactions.getTransactionsStatus({ txId: txId });
        if (isConfirmed(status) && status.chainConfirmations >= confirmations) {
            return status;
        }
        yield new Promise((r) => setTimeout(r, 1000));
        return waitAlphTxConfirmed(provider, txId, confirmations);
    });
}
exports.waitAlphTxConfirmed = waitAlphTxConfirmed;
function getLocalTokenInfo(nodeProvider, tokenId) {
    return __awaiter(this, void 0, void 0, function* () {
        if (tokenId === web3_1.ALPH_TOKEN_ID) {
            return token_list_1.ALPH;
        }
        const tokenMetaData = yield nodeProvider.fetchStdTokenMetaData(tokenId);
        return {
            id: tokenId,
            symbol: Buffer.from(tokenMetaData.symbol, 'hex').toString('utf8'),
            name: Buffer.from(tokenMetaData.name, 'hex').toString('utf8'),
            decimals: tokenMetaData.decimals
        };
    });
}
exports.getLocalTokenInfo = getLocalTokenInfo;
