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());
    });
};
import { addressFromContractId, ALPH_TOKEN_ID, binToHex, subContractId } from "@alephium/web3";
import { bytes32ToUtf8String } from "../utils";
import { RegisterChain, Deposit, DestroyUnexecutedSequenceContracts, UpdateRefundAddress } from "../alephium-contracts/ts/scripts";
import { RemoteTokenPool } from "../alephium-contracts/ts/RemoteTokenPool";
import { ALPH as ALPHTokenInfo } from "@alephium/token-list";
export function registerChain(signerProvider, tokenBridgeId, signedVAA, alphAmount) {
    return __awaiter(this, void 0, void 0, function* () {
        const account = yield signerProvider.getSelectedAccount();
        return RegisterChain.execute(signerProvider, {
            initialFields: {
                payer: account.address,
                tokenBridge: tokenBridgeId,
                vaa: binToHex(signedVAA),
                alphAmount: alphAmount
            },
            attoAlphAmount: alphAmount
        });
    });
}
export function deposit(signerProvider, tokenBridgeForChainId, amount) {
    return __awaiter(this, void 0, void 0, function* () {
        const account = yield signerProvider.getSelectedAccount();
        return Deposit.execute(signerProvider, {
            initialFields: {
                tokenBridgeForChain: tokenBridgeForChainId,
                payer: account.address,
                amount: amount
            },
            attoAlphAmount: amount
        });
    });
}
export function destroyUnexecutedSequenceContracts(signerProvider, tokenBridgeId, signedVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return DestroyUnexecutedSequenceContracts.execute(signerProvider, {
            initialFields: {
                tokenBridge: tokenBridgeId,
                vaa: binToHex(signedVAA)
            }
        });
    });
}
export function updateRefundAddress(signerProvider, tokenBridgeId, signedVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return UpdateRefundAddress.execute(signerProvider, {
            initialFields: {
                tokenBridge: tokenBridgeId,
                vaa: binToHex(signedVAA)
            }
        });
    });
}
export 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;
}
export function getAttestTokenHandlerId(tokenBridgeId, remoteChainId, groupIndex) {
    const pathHex = '00' + zeroPad(remoteChainId.toString(16), 2);
    return subContractId(tokenBridgeId, pathHex, groupIndex);
}
export function getTokenBridgeForChainId(tokenBridgeId, remoteChainId, groupIndex) {
    const pathHex = '01' + zeroPad(remoteChainId.toString(16), 2);
    return subContractId(tokenBridgeId, pathHex, groupIndex);
}
export 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 subContractId(tokenBridgeId, pathHex, groupIndex);
}
export function getUnexecutedSequenceId(tokenBridgeForChainId, index, groupIndex) {
    const pathHex = zeroPad(index.toString(16), 8);
    return subContractId(tokenBridgeForChainId, pathHex, groupIndex);
}
export function contractExists(contractId, provider) {
    return __awaiter(this, void 0, void 0, function* () {
        const address = 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;
        });
    });
}
export function getRemoteTokenInfoFromContractState(state) {
    const contractState = 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: bytes32ToUtf8String(Buffer.from(symbolHex, 'hex')),
        name: bytes32ToUtf8String(Buffer.from(nameHex, 'hex')),
        decimals: decimals
    };
}
export function getRemoteTokenInfo(address) {
    return __awaiter(this, void 0, void 0, function* () {
        const contractState = yield RemoteTokenPool.at(address).fetchState();
        return {
            id: contractState.fields.bridgeTokenId,
            tokenChainId: Number(contractState.fields.tokenChainId),
            symbol: bytes32ToUtf8String(Buffer.from(contractState.fields.symbol_, 'hex')),
            name: bytes32ToUtf8String(Buffer.from(contractState.fields.name_, 'hex')),
            decimals: Number(contractState.fields.decimals_)
        };
    });
}
export function stringToByte32Hex(str) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(str);
    if (bytes.length > 32) {
        throw new Error('string exceed 32 bytes');
    }
    return binToHex(bytes).padStart(64, '0');
}
function isConfirmed(txStatus) {
    return txStatus.type === 'Confirmed';
}
export 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);
    });
}
export function getLocalTokenInfo(nodeProvider, tokenId) {
    return __awaiter(this, void 0, void 0, function* () {
        if (tokenId === ALPH_TOKEN_ID) {
            return ALPHTokenInfo;
        }
        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
        };
    });
}
